1
0
mirror of https://github.com/google/nomulus synced 2026-05-19 06:11:49 +00:00

Compare commits

...

25 Commits

Author SHA1 Message Date
gbrodman
cf698c2586 Add page for WHOIS-editable fields in the console (#2155)
This isn't the prettiest thing, but it replicates the type of view /
edit functionality that we had in the original console.

Of note: this doesn't include input field validation, which would
probably be a good idea to add at some point.
2023-09-28 22:46:18 -04:00
Lai Jiang
cb240a8f03 Use equals() method to compare equality (#2158)
It will call equalsImmutableObject(), which seems the right thing to do.
We only care if the two Tld objects have the same fields, not if they
are the same object. ErrorProne complained about comparison by identity.
2023-09-28 13:27:36 -04:00
gbrodman
0801679173 Close sidenav on click (#2156)
It shouldn't stick around after we've clicked on one of the links
2023-09-25 14:43:07 -04:00
sarahcaseybot
a87c4a31a3 Add breakglass handling to configureTldCommand (#2154)
* Add a breakglass flag to configureTldCommand

* Add tests

* small fixes
2023-09-22 11:51:02 -04:00
sarahcaseybot
58c7e3a52c Change __REMOVEDOMAIN__ token to __REMOVE_BULK_PRICING__ (#2152) 2023-09-21 16:03:39 -04:00
Pavlo Tkach
dded258864 Add resources widget front-end (#2151) 2023-09-21 13:59:40 -04:00
Lai Jiang
759143535f Update proxy k8s manifest (#2153)
The beta API is deprecated.

TESTED=deployed the new manifest to alpha. Without the change, deploying
resulted in an error.

<!-- Reviewable:start -->
- - -
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/google/nomulus/2153)
<!-- Reviewable:end -->
2023-09-21 10:53:39 -04:00
Weimin Yu
46fdf2c996 Defend against deserialization-based attacks (#2150)
* Defend against deserialization-based attacks

Added the `SafeObjectInputStream` class that defends attacks using
malformed serialized data, including remote code execution and
denial-of-service attacks.

Started using the new class to handle EPP resource VKeys and
PendingDeposits, which are passed across credential-boundaries: between
TaskQueue and AppEngine server, and between AppEngine server and the RDE
pipeline on GCE. Note that the wireformat of VKeys do not change,
therefore existing tasks sitting in the TaskQueue are not affected.

Also removed an unused class: JaxbFragment.
2023-09-20 16:56:56 -04:00
sarahcaseybot
fc1857717d Use PrintStream in ConfirmingCommand (#2140)
* Use PrintStream in ConfirmingCommand

* Add errorPrintStream

* remove unneccesary line
2023-09-19 12:11:18 -04:00
sarahcaseybot
e182692a5f Check for diffs in ConfigureTldCommand (#2146)
* Check for diffs in ConfigureTldCommand

* undo override

* Add handling for ordering sets

* Fix comments

* fix formatting

* fix test
2023-09-19 12:10:26 -04:00
gbrodman
a65e85f9e1 Don't include a nextUrl when accessing the console homepage (#2149)
In this case we should just display the standard page, no need to
redirect anywhere since there's nothing to redirect to.
2023-09-15 12:28:04 -04:00
Lai Jiang
2713a10a07 Redact OAuth access token in prod (#2148)
This token is only ever used for logging. The GAE OAuth service will
parse the header directly when called to retrieve the current user and
user id. Logging it in prod could be a security risk if the logs are
leaked.
2023-09-14 13:53:56 -04:00
Pavlo Tkach
5eb44c165c Add settings to console home page, update settings->security styles (#2144) 2023-09-14 12:37:54 -04:00
Lai Jiang
6c18ea9cff Use constant-time comparison when validating client cert hashes (#2147)
Per b/298447714, non-constant-time comparison is prone to brute-force
attacks.
2023-09-14 12:37:20 -04:00
Lai Jiang
43692d3409 Use Java 11 for CodeQL (#2145) 2023-09-13 12:08:33 -04:00
Lai Jiang
38b73b9ecd Upgrade to gradle 8.3 (#2142) 2023-09-13 11:11:49 -04:00
sarahcaseybot
954537291f Disable test failing in cloudbuild (#2143) 2023-09-12 17:06:18 -04:00
Pavlo Tkach
9434d01234 Add /console/userdata endpoint (#2137)
Provides initial set of data, necessary to start the UI
2023-09-12 16:29:53 -04:00
gbrodman
3dafaff2c0 Pass around the full URL in RegistrarGuard (#2139)
Previously this didn't properly deal with nested routings, e.g.
"settings/whois". It tried to just pass "whois" as the next url which
doesn't work with the router because it's nested under the settings.
Using all parts of the URL allows us to handle the nesting.
2023-09-12 15:37:12 -04:00
gbrodman
ca25e4dfbd Use registrar ID, not name, in selector (#2138) 2023-09-12 14:11:31 -04:00
Lai Jiang
6047c16f3e Make Kythe work with Gradle 8 (#2141)
Mostly implementing the fix suggested by b/294850265. Tested by
submitting a job to GCB which ran successfully.
2023-09-12 10:47:57 -04:00
sarahcaseybot
1248c25041 Add a configureTld command that uses YAML files for configuration (#2117)
* Add a configureTld command that uses YAML

* Add more tests and edge case handling

* Add out of order test and fix wrong inject

* small changes

* Add check for ascii

* Add check for ROID suffix
2023-09-06 16:17:22 -04:00
Pavlo Tkach
001e9363a1 Add billing details (#2136)
This adds functionality to billing details widget on home screen
2023-09-06 14:37:58 -04:00
Weimin Yu
9a6a7116da Disable Hibernate error logging (#2134)
Hibernate logs certain information at the ERROR level, which for the
purpose of troubleshooting is misleading, since most affected operations
succeed after retry. ERROR-level logging should only be added by Nomulus
code.

This PR does two things:
1. Disable all logging in two Hibernate classes: we cannot disable
   logging at a finer granularity, and we cannot preserve lower-level
   logging while disabling ERROR.
2. Adds a DatabaseException which captures all error details that may
   escape the typical loggers' attention: SQLException instances can be
   chained in a different way from Throwable's `getCause()` method.
2023-09-06 13:25:21 -04:00
Pavlo Tkach
335af52112 Allow homepage widgets to rearrange on mobile (#2135) 2023-09-05 20:45:13 -04:00
129 changed files with 4555 additions and 1390 deletions

View File

@@ -29,6 +29,12 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v3
- name: Set Java version
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '11'
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v2

View File

@@ -210,8 +210,8 @@ allprojects {
gradle.projectsEvaluated {
tasks.withType(JavaCompile) {
options.fork = true
options.forkOptions.javaHome =
file("${System.env.REAL_JAVA_HOME}")
options.forkOptions.executable =
file("${System.env.JAVA_HOME}/bin/javac")
}
}
}

View File

@@ -19,10 +19,10 @@ net.ltgt.errorprone:net.ltgt.errorprone.gradle.plugin:2.0.2=classpath
net.ltgt.gradle:gradle-errorprone-plugin:2.0.2=classpath
org.eclipse.jgit:org.eclipse.jgit:6.6.0.202305301015-r=classpath
org.eclipse.platform:org.eclipse.osgi:3.18.300=classpath
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.20=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.8.20=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.8.20=classpath
org.jetbrains.kotlin:kotlin-stdlib:1.8.20=classpath
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.9.0=classpath
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.9.0=classpath
org.jetbrains.kotlin:kotlin-stdlib:1.9.0=classpath
org.jetbrains:annotations:13.0=classpath
org.slf4j:slf4j-api:1.7.36=classpath
org.tukaani:xz:1.9=classpath

View File

@@ -22,7 +22,7 @@ com.google.apis:google-api-services-storage:v1-rev20230301-2.0.0=buildScriptClas
com.google.auth:google-auth-library-credentials:1.19.0=buildScriptClasspath,compileClasspath
com.google.auth:google-auth-library-oauth2-http:1.19.0=buildScriptClasspath,compileClasspath
com.google.auto.value:auto-value-annotations:1.10.1=buildScriptClasspath,compileClasspath
com.google.auto.value:auto-value:1.10.2=annotationProcessor
com.google.auto.value:auto-value:1.10.4=annotationProcessor
com.google.auto:auto-common:0.10=annotationProcessor
com.google.cloud:google-cloud-core-grpc:2.21.0=buildScriptClasspath,compileClasspath
com.google.cloud:google-cloud-core-http:2.21.0=buildScriptClasspath,compileClasspath

View File

@@ -41,8 +41,8 @@
"budgets": [
{
"type": "initial",
"maximumWarning": "500kb",
"maximumError": "1mb"
"maximumWarning": "2mb",
"maximumError": "5mb"
},
{
"type": "anyComponentStyle",

View File

@@ -24,6 +24,10 @@ import SettingsSecurityComponent from './settings/security/security.component';
import { RegistrarGuard } from './registrar/registrar.guard';
import { RegistrarComponent } from './registrar/registrarsTable.component';
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
import ContactComponent from './settings/contact/contact.component';
import WhoisComponent from './settings/whois/whois.component';
import SecurityComponent from './settings/security/security.component';
import UsersComponent from './settings/users/users.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
@@ -32,7 +36,7 @@ const routes: Routes = [
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
{
path: 'settings',
path: SettingsComponent.PATH,
component: SettingsComponent,
children: [
{
@@ -41,32 +45,27 @@ const routes: Routes = [
pathMatch: 'full',
},
{
path: 'contact',
path: ContactComponent.PATH,
component: SettingsContactComponent,
canActivate: [RegistrarGuard],
},
{
path: 'whois',
path: WhoisComponent.PATH,
component: SettingsWhoisComponent,
canActivate: [RegistrarGuard],
},
{
path: 'security',
path: SecurityComponent.PATH,
component: SettingsSecurityComponent,
canActivate: [RegistrarGuard],
},
{
path: 'epp-password',
component: SettingsSecurityComponent,
canActivate: [RegistrarGuard],
},
{
path: 'users',
path: UsersComponent.PATH,
component: SettingsUsersComponent,
canActivate: [RegistrarGuard],
},
{
path: 'registrars',
path: RegistrarComponent.PATH,
component: RegistrarComponent,
},
],

View File

@@ -12,9 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
import { Component, ViewChild } from '@angular/core';
import { RegistrarService } from './registrar/registrar.service';
import { UserDataService } from './shared/services/userData.service';
import { GlobalLoaderService } from './shared/services/globalLoader.service';
import { NavigationEnd, Router } from '@angular/router';
import { MatSidenav } from '@angular/material/sidenav';
@Component({
selector: 'app-root',
@@ -23,9 +26,15 @@ import { GlobalLoaderService } from './shared/services/globalLoader.service';
})
export class AppComponent {
renderRouter: boolean = true;
@ViewChild('sidenav')
sidenav!: MatSidenav;
constructor(
protected registrarService: RegistrarService,
protected globalLoader: GlobalLoaderService
protected userDataService: UserDataService,
protected globalLoader: GlobalLoaderService,
protected router: Router
) {
registrarService.activeRegistrarIdChange.subscribe(() => {
this.renderRouter = false;
@@ -34,4 +43,12 @@ export class AppComponent {
}, 400);
});
}
ngAfterViewInit() {
this.router.events.subscribe((event) => {
if (event instanceof NavigationEnd) {
this.sidenav.close();
}
});
}
}

View File

@@ -45,40 +45,46 @@ import { ResourcesWidgetComponent } from './home/widgets/resources-widget.compon
import { EppWidgetComponent } from './home/widgets/epp-widget.component';
import { BillingWidgetComponent } from './home/widgets/billing-widget.component';
import { DomainsWidgetComponent } from './home/widgets/domains-widget.component';
import { SettingsWidgetComponent } from './home/widgets/settings-widget.component';
import { UserDataService } from './shared/services/userData.service';
import WhoisComponent from './settings/whois/whois.component';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
TldsComponent,
HeaderComponent,
SettingsComponent,
SettingsContactComponent,
BillingWidgetComponent,
ContactDetailsDialogComponent,
RegistrarComponent,
SecurityComponent,
EmptyRegistrar,
RegistrarSelectorComponent,
ContactWidgetComponent,
DomainsWidgetComponent,
PromotionsWidgetComponent,
TldsWidgetComponent,
ResourcesWidgetComponent,
EmptyRegistrar,
EppWidgetComponent,
BillingWidgetComponent,
HeaderComponent,
HomeComponent,
PromotionsWidgetComponent,
RegistrarComponent,
RegistrarSelectorComponent,
ResourcesWidgetComponent,
SecurityComponent,
SettingsComponent,
SettingsContactComponent,
SettingsWidgetComponent,
TldsComponent,
TldsWidgetComponent,
WhoisComponent,
],
imports: [
HttpClientModule,
FormsModule,
MaterialModule,
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
BrowserModule,
FormsModule,
HttpClientModule,
MaterialModule,
],
providers: [
GlobalLoaderService,
BackendService,
GlobalLoaderService,
RegistrarGuard,
UserDataService,
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: {

View File

@@ -3,7 +3,15 @@
<button mat-icon-button aria-label="Open menu" (click)="toggleNavPane()">
<mat-icon>menu</mat-icon>
</button>
<span>Google Registry</span>
<span>
<a
[routerLink]="'/home'"
routerLinkActive="active"
class="console-app__logo"
>
Google Registry
</a>
</span>
<span class="spacer"></span>
<app-registrar-selector />
<button mat-icon-button aria-label="Open FAQ">

View File

@@ -12,8 +12,11 @@
// See the License for the specific language governing permissions and
// limitations under the License.
.console-app__header {
margin-top: 0;
.console-app {
&__logo {
color: inherit;
text-decoration: none;
}
}
.spacer {
flex: 1;

View File

@@ -5,7 +5,7 @@
<div app-contact-widget class="console-app__widget-wrapper__wide"></div>
<div app-tlds-widget></div>
<div app-promotions-widget class="console-app__widget-wrapper__wide"></div>
<div app-promotions-widget class="console-app__widget-wrapper__wide"></div>
<div app-settings-widget class="console-app__widget-wrapper__wide"></div>
<div app-resources-widget></div>
<div app-billing-widget></div>
<div app-epp-widget></div>

View File

@@ -20,6 +20,7 @@
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-gap: 20px;
grid-auto-flow: dense;
mat-card {
height: 100%;

View File

@@ -1,13 +1,22 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<a
class="console-app__widget_left"
href="{{ driveFolderUrl }}"
(click)="openBillingDetails($event)"
>
<mat-icon class="console-app__widget-icon">account_balance</mat-icon>
<h1 class="console-app__widget-title">Billing Info</h1>
<h4 class="secondary-text text-center">
View important billing and payments information.
<span *ngIf="driveFolderUrl; else noDriveFolderUrl">
View important billing and payments information.
</span>
<ng-template #noDriveFolderUrl>
<span> Your billing folder is pending allocation. </span>
</ng-template>
</h4>
</div>
</a>
</div>
</mat-card-content>
</mat-card>

View File

@@ -13,11 +13,25 @@
// limitations under the License.
import { Component } from '@angular/core';
import { RegistrarService } from 'src/app/registrar/registrar.service';
@Component({
selector: '[app-billing-widget]',
templateUrl: './billing-widget.component.html',
})
export class BillingWidgetComponent {
constructor() {}
constructor(public registrarService: RegistrarService) {}
public get driveFolderUrl(): string {
if (this.registrarService?.registrar.driveFolderId) {
return `https://drive.google.com/drive/folders/${this.registrarService?.registrar.driveFolderId}`;
}
return '';
}
openBillingDetails(e: MouseEvent) {
if (!this.driveFolderUrl) {
e.preventDefault();
}
}
}

View File

@@ -13,13 +13,13 @@
Give us a Call
</button>
<p class="secondary-text">
Call Google Registry support at +1 (404) 978 8419
Call Google Registry support at <b>+1 (404) 978 8419</b>
</p>
<button mat-button color="primary" class="console-app__widget-link">
Send us an Email
</button>
<p class="secondary-text">
Email Google Registry at support@google.com
Email Google Registry at <b>support@google.com</b>
</p>
</div>
</div>

View File

@@ -1,13 +1,16 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<a
class="console-app__widget_left"
href="{{ userDataService.userData?.technicalDocsUrl }}"
>
<mat-icon class="console-app__widget-icon">menu_book</mat-icon>
<h1 class="console-app__widget-title">Resources</h1>
<h4 class="secondary-text text-center">
Use Google Drive to view onboarding FAQs, and technical documentation.
</h4>
</div>
</a>
</div>
</mat-card-content>
</mat-card>

View File

@@ -13,11 +13,12 @@
// limitations under the License.
import { Component } from '@angular/core';
import { UserDataService } from 'src/app/shared/services/userData.service';
@Component({
selector: '[app-resources-widget]',
templateUrl: './resources-widget.component.html',
})
export class ResourcesWidgetComponent {
constructor() {}
constructor(public userDataService: UserDataService) {}
}

View File

@@ -0,0 +1,53 @@
<mat-card class="console-app__widget-wrapper__wide">
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<mat-icon class="console-app__widget-icon">settings</mat-icon>
<h1 class="console-app__widget-title">Settings</h1>
<h4 class="secondary-text text-center">
Configure registrar settings, manage console users, and view activity
log.
</h4>
</div>
<div class="console-app__widget_right">
<button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openContactsPage()"
>
Contact Information
</button>
<p class="secondary-text">Manage Primary, Technical, etc contacts.</p>
<button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openSecurityPage()"
>
Security
</button>
<p class="secondary-text">
Manage IP allow lists and SSL certificates.
</p>
<button mat-button color="primary" class="console-app__widget-link">
Nomulus Password
</button>
<p class="secondary-text">Reset your Nomulus password.</p>
<button mat-button color="primary" class="console-app__widget-link">
User Management
</button>
<p class="secondary-text">Create and manage console user accounts</p>
<button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openRegistrarsPage()"
>
Registrar Management
</button>
<p class="secondary-text">Create and manage registrar accounts</p>
</div>
</div>
</mat-card-content>
</mat-card>

View File

@@ -0,0 +1,44 @@
// Copyright 2023 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.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { RegistrarComponent } from 'src/app/registrar/registrarsTable.component';
import ContactComponent from 'src/app/settings/contact/contact.component';
import SecurityComponent from 'src/app/settings/security/security.component';
import { SettingsComponent } from 'src/app/settings/settings.component';
@Component({
selector: '[app-settings-widget]',
templateUrl: './settings-widget.component.html',
})
export class SettingsWidgetComponent {
constructor(private router: Router) {}
openRegistrarsPage() {
this.navigate(RegistrarComponent.PATH);
}
openSecurityPage() {
this.navigate(SecurityComponent.PATH);
}
openContactsPage() {
this.navigate(ContactComponent.PATH);
}
private navigate(route: string) {
this.router.navigate([SettingsComponent.PATH, route]);
}
}

View File

@@ -14,9 +14,10 @@
import { Component } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { RegistrarService } from './registrar.service';
import { Subscription } from 'rxjs';
import { RegistrarService } from './registrar.service';
@Component({
selector: 'app-empty-registrar',
templateUrl: './emptyRegistrar.component.html',

View File

@@ -8,9 +8,9 @@
>
<mat-option
*ngFor="let registrar of registrarService.registrars"
[value]="registrar.registrarName"
[value]="registrar.registrarId"
>
{{ registrar.registrarName }}
{{ registrar.registrarId }}
</mat-option>
</mat-select>
</mat-form-field>

View File

@@ -39,7 +39,7 @@ describe('RegistrarGuard', () => {
it('should not be able to activate when activeRegistrarId is empty', () => {
guard = TestBed.inject(RegistrarGuard);
const res = guard.canActivate(dummyRoute);
const res = guard.canActivate();
expect(res).toBeFalsy();
});
@@ -48,14 +48,14 @@ describe('RegistrarGuard', () => {
useValue: { activeRegistrarId: 'value' },
});
guard = TestBed.inject(RegistrarGuard);
const res = guard.canActivate(dummyRoute);
const res = guard.canActivate();
expect(res).toBeTrue();
});
it('should navigate to registrars when activeRegistrarId is empty', () => {
const dummyRoute = { url: '/value' } as RouterStateSnapshot;
guard = TestBed.inject(RegistrarGuard);
guard.canActivate(dummyRoute);
guard.canActivate();
expect(routeSpy.navigate).toHaveBeenCalledOnceWith([
'/registrars',
{ nextUrl: '/value' },

View File

@@ -13,7 +13,8 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { Router, RouterStateSnapshot } from '@angular/router';
import { Router } from '@angular/router';
import { RegistrarService } from './registrar.service';
@Injectable({
@@ -25,10 +26,13 @@ export class RegistrarGuard {
private registrarService: RegistrarService
) {}
canActivate(state: RouterStateSnapshot): Promise<boolean> | boolean {
canActivate(): Promise<boolean> | boolean {
if (this.registrarService.activeRegistrarId) {
return true;
}
return this.router.navigate([`/empty-registrar`, { nextUrl: state.url }]);
// Get the full URL including any nested children (skip the initial '#/')
// NB: an empty nextUrl takes the user to the home page
const nextUrl = location.hash.split('#/')[1] || '';
return this.router.navigate([`/empty-registrar`, { nextUrl }]);
}
}

View File

@@ -13,14 +13,16 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { Observable, Subject, tap } from 'rxjs';
import { BackendService } from '../shared/services/backend.service';
import { Subject } from 'rxjs';
import {
GlobalLoader,
GlobalLoaderService,
} from '../shared/services/globalLoader.service';
import { MatSnackBar } from '@angular/material/snack-bar';
interface Address {
export interface Address {
street?: string[];
city?: string;
countryCode?: string;
@@ -30,16 +32,20 @@ interface Address {
export interface Registrar {
allowedTlds?: string[];
ipAddressAllowList?: string[];
emailAddress?: string;
billingAccountMap?: object;
driveFolderId?: string;
emailAddress?: string;
faxNumber?: string;
ianaIdentifier?: number;
icannReferralEmail?: string;
ipAddressAllowList?: string[];
localizedAddress?: Address;
phoneNumber?: string;
registrarId: string;
registrarName: string;
registryLockAllowed?: boolean;
url?: string;
whoisServer?: string;
}
@Injectable({
@@ -52,21 +58,39 @@ export class RegistrarService implements GlobalLoader {
constructor(
private backend: BackendService,
private globalLoader: GlobalLoaderService
private globalLoader: GlobalLoaderService,
private _snackBar: MatSnackBar
) {
this.backend.getRegistrars().subscribe((r) => {
this.loadRegistrars().subscribe((r) => {
this.globalLoader.stopGlobalLoader(this);
this.registrars = r;
});
this.globalLoader.startGlobalLoader(this);
}
public get registrar(): Registrar {
return this.registrars.filter(
(r) => r.registrarId === this.activeRegistrarId
)[0];
}
public updateRegistrar(registrarId: string) {
this.activeRegistrarId = registrarId;
this.activeRegistrarIdChange.next(registrarId);
}
public loadRegistrars(): Observable<Registrar[]> {
return this.backend.getRegistrars().pipe(
tap((registrars) => {
if (registrars) {
this.registrars = registrars;
}
})
);
}
loadingTimeout() {
// TODO: Decide what to do when timeout happens
this._snackBar.open('Timeout loading registrars', undefined, {
duration: 1500,
});
}
}

View File

@@ -21,6 +21,7 @@ import { Registrar, RegistrarService } from './registrar.service';
styleUrls: ['./registrarsTable.component.scss'],
})
export class RegistrarComponent {
public static PATH = 'registrars';
columns = [
{
columnDef: 'registrarId',

View File

@@ -129,7 +129,7 @@ export class ContactDetailsDialogComponent {
operationObservable.subscribe({
complete: this.onCloseCallback.bind(this),
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.statusText, undefined, {
this._snackBar.open(err.error, undefined, {
duration: 1500,
});
},
@@ -143,12 +143,15 @@ export class ContactDetailsDialogComponent {
styleUrls: ['./contact.component.scss'],
})
export default class ContactComponent {
public static PATH = 'contact';
loading: boolean = false;
constructor(
private dialog: MatDialog,
private bottomSheet: MatBottomSheet,
private breakpointObserver: BreakpointObserver,
public contactService: ContactService
public contactService: ContactService,
private _snackBar: MatSnackBar
) {
// TODO: Refactor to registrarId service
this.loading = true;
@@ -170,7 +173,13 @@ export default class ContactComponent {
deleteContact(contact: Contact) {
if (confirm(`Please confirm contact ${contact.name} delete`)) {
this.contactService.deleteContact(contact).subscribe();
this.contactService.deleteContact(contact).subscribe({
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, {
duration: 1500,
});
},
});
}
}

View File

@@ -17,8 +17,10 @@
dataSource.ipAddressAllowList.length > 0
"
>
<div *ngFor="let item of dataSource.ipAddressAllowList; index as index">
<div>{{ item.value }}</div>
<div
*ngFor="let item of dataSource.ipAddressAllowList; index as index"
class="settings-security__ipRecord"
>
<mat-form-field>
<input
matInput

View File

@@ -17,6 +17,9 @@
h1 {
margin: 0;
}
&__ipRecord {
margin-bottom: 1rem;
}
&__section {
display: flex;
align-items: stretch;

View File

@@ -13,9 +13,14 @@
// limitations under the License.
import { Component } from '@angular/core';
import { SecurityService, SecuritySettings } from './security.service';
import {
SecurityService,
SecuritySettings,
apiToUiConverter,
} from './security.service';
import { HttpErrorResponse } from '@angular/common/http';
import { MatSnackBar } from '@angular/material/snack-bar';
import { RegistrarService } from 'src/app/registrar/registrar.service';
@Component({
selector: 'app-security',
@@ -24,39 +29,27 @@ import { MatSnackBar } from '@angular/material/snack-bar';
providers: [SecurityService],
})
export default class SecurityComponent {
public static PATH = 'security';
loading: boolean = false;
inEdit: boolean = false;
dataSource: SecuritySettings = {};
constructor(
public securityService: SecurityService,
private _snackBar: MatSnackBar
private _snackBar: MatSnackBar,
public registrarService: RegistrarService
) {
this.loading = true;
this.securityService.fetchSecurityDetails().subscribe({
complete: () => {
this.dataSource = this.securityService.securitySettings;
this.loading = false;
},
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, {
duration: 1500,
});
this.loading = false;
},
});
this.dataSource = apiToUiConverter(this.registrarService.registrar);
}
enableEdit() {
this.inEdit = true;
this.dataSource = JSON.parse(
JSON.stringify(this.securityService.securitySettings)
);
}
disableEdit() {
cancel() {
this.inEdit = false;
this.dataSource = this.securityService.securitySettings;
this.resetDataSource();
}
createIpEntry() {
@@ -68,7 +61,7 @@ export default class SecurityComponent {
this.securityService.saveChanges(this.dataSource).subscribe({
complete: () => {
this.loading = false;
this.dataSource = this.securityService.securitySettings;
this.resetDataSource();
},
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, {
@@ -76,16 +69,15 @@ export default class SecurityComponent {
});
},
});
this.disableEdit();
}
cancel() {
this.dataSource = this.securityService.securitySettings;
this.inEdit = false;
this.cancel();
}
removeIpEntry(index: number) {
this.dataSource.ipAddressAllowList =
this.dataSource.ipAddressAllowList?.filter((_, i) => i != index);
}
resetDataSource() {
this.dataSource = apiToUiConverter(this.registrarService.registrar);
}
}

View File

@@ -13,7 +13,7 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { tap } from 'rxjs';
import { switchMap } from 'rxjs';
import { RegistrarService } from 'src/app/registrar/registrar.service';
import { BackendService } from 'src/app/shared/services/backend.service';
@@ -61,16 +61,6 @@ export class SecurityService {
private registrarService: RegistrarService
) {}
fetchSecurityDetails() {
return this.backend
.getSecuritySettings(this.registrarService.activeRegistrarId)
.pipe(
tap((securitySettings: SecuritySettingsBackendModel) => {
this.securitySettings = apiToUiConverter(securitySettings);
})
);
}
saveChanges(newSecuritySettings: SecuritySettings) {
return this.backend
.postSecuritySettings(
@@ -78,8 +68,8 @@ export class SecurityService {
uiToApiConverter(newSecuritySettings)
)
.pipe(
tap((_) => {
this.securitySettings = newSecuritySettings;
switchMap(() => {
return this.registrarService.loadRegistrars();
})
);
}

View File

@@ -20,4 +20,6 @@ import { Component, ViewEncapsulation } from '@angular/core';
styleUrls: ['./settings.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class SettingsComponent {}
export class SettingsComponent {
public static PATH = 'settings';
}

View File

@@ -19,4 +19,6 @@ import { Component } from '@angular/core';
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss'],
})
export default class UsersComponent {}
export default class UsersComponent {
public static PATH = 'users';
}

View File

@@ -1 +1,250 @@
<p>whois works!</p>
<div class="settings-whois">
<h2>WHOIS settings</h2>
<h3>
General registrar information for your WHOIS record. This information is
always visible in WHOIS.
</h3>
<div *ngIf="loading" class="settings-whois__loading">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>Name:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.registrarName"
disabled
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>IANA Identifier:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.ianaIdentifier"
disabled
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>ICANN Referral Email:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="email"
[(ngModel)]="registrar.icannReferralEmail"
disabled
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>WHOIS server:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.whoisServer"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>Referral URL:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.url"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>Email:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="email"
[(ngModel)]="registrar.emailAddress"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>Phone::</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.phoneNumber"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-description">
<h3>Fax:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
matInput
type="text"
[(ngModel)]="registrar.faxNumber"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>Address Line 1:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress?.street"
matInput
type="text"
[(ngModel)]="(registrar.localizedAddress?.street)![0]"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>City:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress"
matInput
type="text"
[(ngModel)]="registrar.localizedAddress.city"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>Address Line 2:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress?.street"
matInput
type="text"
[(ngModel)]="(registrar.localizedAddress?.street)![1]"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>State/Region:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress"
matInput
type="text"
[(ngModel)]="registrar.localizedAddress.state"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
</div>
<div class="settings-whois__section">
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>Address Line 3:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress?.street"
matInput
type="text"
[(ngModel)]="(registrar.localizedAddress?.street)![2]"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
<div class="settings-whois__section-address">
<div class="settings-whois__section-description">
<h3>Country Code:</h3>
</div>
<div class="settings-whois__section-form">
<mat-form-field>
<input
*ngIf="registrar.localizedAddress"
matInput
type="text"
[(ngModel)]="registrar.localizedAddress.countryCode"
[disabled]="!inEdit"
/>
</mat-form-field>
</div>
</div>
</div>
<div class="settings-whois__actions">
<ng-template [ngIf]="inEdit" [ngIfElse]="inView">
<button
class="actions-save"
mat-raised-button
color="primary"
(click)="save()"
>
Save
</button>
<button class="actions-cancel" mat-stroked-button (click)="cancel()">
Cancel
</button>
</ng-template>
<ng-template #inView>
<button #elseBlock mat-raised-button (click)="enableEdit()">Edit</button>
</ng-template>
</div>
</div>

View File

@@ -11,3 +11,49 @@
// 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.
.settings-whois {
margin-top: 1.5rem;
&__section {
display: flex;
flex-wrap: wrap;
margin-bottom: 10px;
min-width: 400px;
}
&__section-address {
display: flex;
flex-wrap: wrap;
margin-bottom: 5px;
min-width: 450px;
width: 50%;
max-width: 50%;
}
&__section-description {
display: inline-block;
margin-block-start: 1em;
min-width: 150px;
}
&__section-form {
display: inline-block;
width: 70%;
mat-form-field {
width: 90%;
min-width: 300px;
}
input:disabled {
border: 0;
}
}
&__loading {
margin: 2rem 0;
}
&__actions {
margin-top: 50px;
display: flex;
justify-content: flex-end;
margin-right: 50px;
button {
margin-left: 20px;
}
}
}

View File

@@ -12,11 +12,66 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { HttpErrorResponse } from '@angular/common/http';
import { Component } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
import {
Registrar,
RegistrarService,
} from 'src/app/registrar/registrar.service';
import { WhoisService } from './whois.service';
@Component({
selector: 'app-whois',
templateUrl: './whois.component.html',
styleUrls: ['./whois.component.scss'],
providers: [WhoisService],
})
export default class WhoisComponent {}
export default class WhoisComponent {
public static PATH = 'whois';
loading = false;
inEdit = false;
registrar: Registrar;
constructor(
public whoisService: WhoisService,
public registrarService: RegistrarService,
private _snackBar: MatSnackBar
) {
this.registrar = JSON.parse(
JSON.stringify(this.registrarService.registrar)
);
}
enableEdit() {
this.inEdit = true;
}
cancel() {
this.inEdit = false;
this.resetDataSource();
}
save() {
this.loading = true;
this.whoisService.saveChanges(this.registrar).subscribe({
complete: () => {
this.loading = false;
this.resetDataSource();
},
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error, undefined, {
duration: 1500,
});
},
});
this.cancel();
}
resetDataSource() {
this.registrar = JSON.parse(
JSON.stringify(this.registrarService.registrar)
);
}
}

View File

@@ -0,0 +1,45 @@
// Copyright 2023 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.
import { Injectable } from '@angular/core';
import { switchMap } from 'rxjs';
import { Address, RegistrarService } from 'src/app/registrar/registrar.service';
import { BackendService } from 'src/app/shared/services/backend.service';
export interface WhoisRegistrarFields {
ianaIdentifier?: number;
icannReferralEmail?: string;
localizedAddress?: Address;
registrarId?: string;
url?: string;
whoisServer?: string;
}
@Injectable()
export class WhoisService {
whoisRegistrarFields: WhoisRegistrarFields = {};
constructor(
private backend: BackendService,
private registrarService: RegistrarService
) {}
saveChanges(newWhoisRegistrarFields: WhoisRegistrarFields) {
return this.backend.postWhoisRegistrarFields(newWhoisRegistrarFields).pipe(
switchMap(() => {
return this.registrarService.loadRegistrars();
})
);
}
}

View File

@@ -19,6 +19,8 @@ import { SecuritySettingsBackendModel } from 'src/app/settings/security/security
import { Contact } from '../../settings/contact/contact.service';
import { Registrar } from '../../registrar/registrar.service';
import { UserData } from './userData.service';
import { WhoisRegistrarFields } from 'src/app/settings/whois/whois.service';
@Injectable()
export class BackendService {
@@ -90,4 +92,19 @@ export class BackendService {
securitySettings
);
}
getUserData(): Observable<UserData> {
return this.http
.get<UserData>(`/console-api/userdata`)
.pipe(catchError((err) => this.errorCatcher<UserData>(err)));
}
postWhoisRegistrarFields(
whoisRegistrarFields: WhoisRegistrarFields
): Observable<WhoisRegistrarFields> {
return this.http.post<WhoisRegistrarFields>(
'/console-api/settings/whois-fields',
whoisRegistrarFields
);
}
}

View File

@@ -0,0 +1,56 @@
// Copyright 2023 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.
import { Injectable } from '@angular/core';
import { Observable, tap } from 'rxjs';
import { BackendService } from './backend.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { GlobalLoader, GlobalLoaderService } from './globalLoader.service';
export interface UserData {
isAdmin: boolean;
globalRole: string;
technicalDocsUrl: string;
}
@Injectable({
providedIn: 'root',
})
export class UserDataService implements GlobalLoader {
public userData?: UserData;
constructor(
private backend: BackendService,
protected globalLoader: GlobalLoaderService,
private _snackBar: MatSnackBar
) {
this.getUserData().subscribe(() => {
this.globalLoader.stopGlobalLoader(this);
});
this.globalLoader.startGlobalLoader(this);
}
getUserData(): Observable<UserData> {
return this.backend.getUserData().pipe(
tap((userData: UserData) => {
this.userData = userData;
})
);
}
loadingTimeout() {
this._snackBar.open('Timeout loading user data', undefined, {
duration: 1500,
});
}
}

View File

@@ -31,22 +31,30 @@ body {
&__widget {
display: flex;
gap: 10px;
> a {
text-decoration: none;
color: initial;
}
> a[href=""] {
cursor: not-allowed;
}
&-wrapper__wide {
grid-column: span 2;
}
&-link {
padding: 0 !important;
text-align: left;
margin-bottom: 0.5rem;
height: 20px !important;
min-width: auto !important;
}
&-title {
color: var(--primary) !important;
}
&-icon {
font-size: 4rem;
line-height: 4rem;
height: 4rem !important;
width: 4rem !important;
font-size: 5rem;
line-height: 5rem;
height: 5rem !important;
width: 5rem !important;
}
&_left {
flex: 1;
@@ -58,6 +66,10 @@ body {
flex: 1;
border-left: 1px solid var(--secondary);
padding-left: 20px;
.secondary-text {
margin-bottom: 0.3rem;
font-size: 0.8rem;
}
}
}
}

View File

@@ -894,7 +894,7 @@ task runTestServer(dependsOn: copyJsFilesForTestServer, type: JavaExec) {
*
* ./gradlew test -P testFilter=*.FooBar,google.registry.tools.ShellCommandTest
*/
class FilteringTest extends Test {
abstract class FilteringTest extends Test {
FilteringTest() {
useJUnitPlatform();

View File

@@ -8,20 +8,20 @@ args4j:args4j:2.0.26=css
cglib:cglib-nodep:2.2=css
com.101tec:zkclient:0.10=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.beust:jcommander:1.60=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.14.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.15.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml:classmate:1.5.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ben-manes.caffeine:caffeine:2.7.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-api:3.3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport-zerodep:3.3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport:3.3.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-api:3.3.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport-zerodep:3.3.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport:3.3.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jffi:1.3.11=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-a64asm:1.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -33,117 +33,116 @@ com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,deploy_jar,nonprodCompileClassp
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.android:annotations:4.1.1.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-appengine:1.35.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-jackson2:1.32.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-jackson2:2.0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-java6:1.35.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-servlet:1.35.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client:1.35.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.22.6-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.38.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.162.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.162.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.23.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.105.14=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsublite-v1:1.12.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.22.6-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-common-protos:2.20.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:2.38.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.162.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.162.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.23.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.23.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-datastore-v1:0.106.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-firestore-v1:3.13.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.41.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.165.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.165.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.26.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.106.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsublite-v1:1.12.13=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-common-protos:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:2.41.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.165.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.165.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.26.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.26.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-datastore-v1:0.107.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-firestore-v1:3.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:1.64.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.20.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.105.14=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsublite-v1:1.12.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-v1:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.22.6-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.112.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.112.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.22.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.17.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.14.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:2.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.24.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.106.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsublite-v1:1.12.13=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-v1:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.113.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.24.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.18.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.16.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.32.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:2.32.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.33.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-appengine:v1-rev20230601-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-bigquery:v2-rev20220924-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20220828-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-appengine:v1-rev20230831-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-bigquery:v2-rev20230520-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20230129-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-dataflow:v1b3-rev20220920-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-dns:v2beta1-rev99-1.25.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-drive:v2-rev393-1.25.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-gmail:v1-rev20220404-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-groupssettings:v1-rev20210624-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-healthcare:v1-rev20220818-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-iamcredentials:v1-rev20210326-1.32.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-monitoring:v3-rev20230529-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-healthcare:v1-rev20230510-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-iamcredentials:v1-rev20211203-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-monitoring:v3-rev20230806-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sheets:v4-rev20230526-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20230607-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20230301-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
com.google.apis:google-api-services-storage:v1-rev20230617-2.0.0=testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sheets:v4-rev20230815-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20230831-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20230617-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-1.0-sdk:1.9.86=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
com.google.appengine:appengine-api-1.0-sdk:2.0.16=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-stubs:2.0.16=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-1.0-sdk:2.0.19=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-stubs:2.0.19=testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-testing:1.9.86=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service-annotations:1.1.1=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service:1.1.1=annotationProcessor
com.google.auto.value:auto-value-annotations:1.10.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.2=annotationProcessor,testAnnotationProcessor
com.google.auto.value:auto-value:1.10.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.4=annotationProcessor,testAnnotationProcessor
com.google.auto:auto-common:0.10=errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.auto:auto-common:1.2.1=annotationProcessor
com.google.closure-stylesheets:closure-stylesheets:1.5.0=css
com.google.cloud.bigdataoss:gcsio:2.2.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigdataoss:util:2.2.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigdataoss:gcsio:2.2.16=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigdataoss:util:2.2.16=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.datastore:datastore-v1-proto-client:2.15.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:jdbc-socket-factory-core:1.13.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:postgres-socket-factory:1.13.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigquerystorage:2.38.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable-stats:2.23.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable:2.23.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.datastore:datastore-v1-proto-client:2.16.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:jdbc-socket-factory-core:1.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:postgres-socket-factory:1.14.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigquerystorage:2.41.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable-stats:2.26.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable:2.26.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-firestore:3.13.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-firestore:3.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-monitoring:1.82.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
com.google.cloud:google-cloud-monitoring:3.20.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-monitoring:3.24.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-nio:0.126.19=testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsub:1.123.14=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsublite:1.12.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-secretmanager:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-spanner:6.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsub:1.124.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsublite:1.12.13=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-secretmanager:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-spanner:6.45.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.22.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-tasks:2.22.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-tasks:2.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:grpc-gcp:1.4.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.13.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.14.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.findbugs:jFormatString:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.code.findbugs:jsr305:3.0.1=css
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntime,nonprodRuntimeClasspath,runtime,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.7=css,soy
com.google.common.html.types:types:1.0.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
com.google.dagger:dagger-compiler:2.47=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger-producers:2.47=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger-spi:2.47=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger:2.47=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.9=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger-compiler:2.48=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger-producers:2.48=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger-spi:2.48=annotationProcessor,testAnnotationProcessor
com.google.dagger:dagger:2.48=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.devtools.ksp:symbol-processing-api:1.9.0-1.0.12=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotation:2.3.4=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.19.1=testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.18.0=annotationProcessor,testAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.21.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.3.4=errorprone,nonprodAnnotationProcessor
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle,soy
com.google.errorprone:error_prone_check_api:2.3.4=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
@@ -157,21 +156,19 @@ com.google.flogger:flogger:0.7.4=compileClasspath,deploy_jar,nonprodCompileClass
com.google.flogger:google-extensions:0.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.googlejavaformat:google-java-format:1.5=annotationProcessor,testAnnotationProcessor
com.google.guava:failureaccess:1.0.1=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava-parent:32.1.1-jre=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
com.google.guava:guava-parent:32.1.2-jre=annotationProcessor,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava-parent:32.1.2-jre=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava-testlib:32.1.2-jre=testCompileClasspath,testRuntimeClasspath
com.google.guava:guava:20.0=css
com.google.guava:guava:27.0.1-jre=errorprone,nonprodAnnotationProcessor
com.google.guava:guava:31.0.1-jre=checkstyle,soy
com.google.guava:guava:32.1.1-jre=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
com.google.guava:guava:32.1.2-jre=annotationProcessor,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,errorprone,nonprodAnnotationProcessor,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava:32.1.2-jre=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,checkstyle,compileClasspath,deploy_jar,errorprone,nonprodAnnotationProcessor,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
com.google.gwt:gwt-user:2.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-apache-v2:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-appengine:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-gson:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-jackson2:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-protobuf:1.43.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-protobuf:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client:1.43.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.inject.extensions:guice-multibindings:4.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
com.google.inject:guice:4.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -197,12 +194,10 @@ com.google.protobuf:protobuf-java:2.5.0=css
com.google.protobuf:protobuf-java:3.23.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.4.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.google.protobuf:protobuf-java:4.0.0-rc-2=soy
com.google.re2j:re2j:1.6=compileClasspath,nonprodCompileClasspath,testCompileClasspath
com.google.re2j:re2j:1.7=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
com.google.re2j:re2j:1.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.template:soy:2021-02-01=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
com.google.truth.extensions:truth-java8-extension:1.1.5=testCompileClasspath,testRuntimeClasspath
com.google.truth:truth:1.1.3=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
com.google.truth:truth:1.1.5=testCompileClasspath,testRuntimeClasspath
com.google.truth:truth:1.1.5=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.googlecode.java-diff-utils:diffutils:1.3.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
com.googlecode.json-simple:json-simple:1.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.ibm.icu:icu4j:57.1=compileClasspath,nonprodCompileClasspath,soy,testCompileClasspath
@@ -229,7 +224,6 @@ commons-beanutils:commons-beanutils:1.9.4=checkstyle
commons-codec:commons-codec:1.15=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-collections:commons-collections:3.2.2=checkstyle
commons-logging:commons-logging:1.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
dev.failsafe:failsafe:3.3.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
dnsjava:dnsjava:3.5.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
guru.nidi.com.eclipsesource.j2v8:j2v8_linux_x86_64:4.6.0=nonprodRuntime,runtime,testRuntimeClasspath
guru.nidi.com.eclipsesource.j2v8:j2v8_macosx_x86_64:4.6.0=nonprodRuntime,runtime,testRuntimeClasspath
@@ -248,21 +242,19 @@ io.github.java-diff-utils:java-diff-utils:4.12=deploy_jar,nonprodRuntimeClasspat
io.grpc:grpc-alts:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-census:1.55.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-census:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-googleapis:1.56.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-grpclb:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty:1.55.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-rls:1.55.3=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.55.1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-services:1.56.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-rls:1.56.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-stub:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.55.1=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.grpc:grpc-xds:1.56.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.56.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-buffer:4.1.87.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http2:4.1.87.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http:4.1.87.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -278,7 +270,8 @@ io.netty:netty-transport-native-unix-common:4.1.87.Final=compileClasspath,deploy
io.netty:netty-transport:4.1.87.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-api:0.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-exemplar-util:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.0=compileClasspath,nonprodCompileClasspath,testCompileClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.1=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-util:0.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-http-util:0.31.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-resource-util:0.31.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -306,12 +299,12 @@ javax.validation:validation-api:1.0.0.GA=compileClasspath,deploy_jar,nonprodComp
javax.xml.bind:jaxb-api:2.3.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.xml.bind:jaxb-api:2.4.0-b180830.0359=jaxb
jline:jline:1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.10=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.14=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
junit:junit:4.13.2=nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
net.arnx:nashorn-promise:0.1.1=nonprodRuntime,runtime,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.14.5=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy-agent:1.14.6=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.18=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
net.bytebuddy:byte-buddy:1.14.5=testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.14.6=testCompileClasspath,testRuntimeClasspath
net.java.dev.javacc:javacc:4.1=css
net.java.dev.jna:jna:5.12.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.ltgt.gradle.incap:incap:0.2=annotationProcessor,testAnnotationProcessor
@@ -321,26 +314,26 @@ org.apache.arrow:arrow-format:5.0.0=compileClasspath,deploy_jar,nonprodCompileCl
org.apache.arrow:arrow-memory-core:5.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.arrow:arrow-vector:5.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.avro:avro:1.8.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-fn-execution:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-job-management:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-pipeline:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-construction-java:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-java:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-direct-java:2.49.0=testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-java-fn-execution:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-core:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-expansion-service:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-arrow:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-avro:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-protobuf:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-fn-execution:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-harness:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-kafka:2.49.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-fn-execution:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-job-management:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-pipeline:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-construction-java:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-java:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-direct-java:2.50.0=testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-java-fn-execution:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-core:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-expansion-service:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-arrow:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-avro:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-protobuf:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-fn-execution:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-harness:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-kafka:2.50.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-grpc-1_54_0:0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-guava-26_0-jre:0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-guava-32_1_2-jre:0.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-compress:1.23.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-csv:1.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-exec:1.3=nonprodRuntime,runtime,testCompileClasspath,testRuntimeClasspath
@@ -355,7 +348,7 @@ org.apache.mina:mina-core:2.1.6=testCompileClasspath,testRuntimeClasspath
org.apache.sshd:sshd-core:2.0.0=testCompileClasspath,testRuntimeClasspath
org.apache.sshd:sshd-scp:2.0.0=testCompileClasspath,testRuntimeClasspath
org.apache.sshd:sshd-sftp:2.0.0=testCompileClasspath,testRuntimeClasspath
org.apache.tomcat:tomcat-annotations-api:11.0.0-M9=testCompileClasspath,testRuntimeClasspath
org.apache.tomcat:tomcat-annotations-api:11.0.0-M11=testCompileClasspath,testRuntimeClasspath
org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath
org.bouncycastle:bcpg-jdk15on:1.67=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.bouncycastle:bcpkix-jdk15on:1.67=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -365,8 +358,8 @@ org.checkerframework:checker-compat-qual:2.5.5=annotationProcessor,deploy_jar,no
org.checkerframework:checker-qual:3.0.0=errorprone,nonprodAnnotationProcessor
org.checkerframework:checker-qual:3.12.0=checkstyle,soy
org.checkerframework:checker-qual:3.31.0=nonprodRuntime,runtime
org.checkerframework:checker-qual:3.33.0=annotationProcessor,compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testAnnotationProcessor
org.checkerframework:checker-qual:3.35.0=testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.33.0=annotationProcessor,compileClasspath,nonprodCompileClasspath,testAnnotationProcessor
org.checkerframework:checker-qual:3.35.0=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:dataflow:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
org.checkerframework:javacutil:3.0.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
org.codehaus.jackson:jackson-core-asl:1.9.13=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
@@ -383,7 +376,7 @@ org.eclipse.jetty:jetty-server:9.4.49.v20220914=compileClasspath,deploy_jar,nonp
org.eclipse.jetty:jetty-servlet:9.4.49.v20220914=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util-ajax:9.4.49.v20220914=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.49.v20220914=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.flywaydb:flyway-core:9.21.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.flywaydb:flyway-core:9.22.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:jaxb-core:4.0.3=nonprodRuntime,runtime
org.glassfish.jaxb:jaxb-runtime:2.3.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:jaxb-runtime:4.0.3=nonprodRuntime,runtime
@@ -408,17 +401,17 @@ org.jboss.logging:jboss-logging:3.4.3.Final=compileClasspath,deploy_jar,nonprodC
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jboss:jandex:2.4.2.Final=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains.kotlin:kotlin-reflect:1.6.10=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib-common:1.8.20=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib-common:1.9.0=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.6.10=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.6.10=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib:1.8.20=annotationProcessor,testAnnotationProcessor
org.jetbrains.kotlin:kotlin-stdlib:1.9.0=annotationProcessor,testAnnotationProcessor
org.jetbrains:annotations:13.0=annotationProcessor,testAnnotationProcessor
org.jetbrains:annotations:17.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.joda:joda-money:1.0.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.json:json:20160212=soy
org.json:json:20230227=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.json:json:20230618=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jsoup:jsoup:1.16.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.junit-pioneer:junit-pioneer:2.0.1=testCompileClasspath,testRuntimeClasspath
org.junit-pioneer:junit-pioneer:2.1.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-api:5.10.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-engine:5.10.0=testCompileClasspath,testRuntimeClasspath
org.junit.jupiter:junit-jupiter-migrationsupport:5.10.0=testCompileClasspath,testRuntimeClasspath
@@ -432,8 +425,8 @@ org.junit.platform:junit-platform-suite-commons:1.10.0=testRuntimeClasspath
org.junit:junit-bom:5.10.0=testCompileClasspath,testRuntimeClasspath
org.jvnet.staxex:stax-ex:1.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:1.10.19=css
org.mockito:mockito-core:5.4.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-junit-jupiter:5.4.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-core:5.5.0=testCompileClasspath,testRuntimeClasspath
org.mockito:mockito-junit-jupiter:5.5.0=testCompileClasspath,testRuntimeClasspath
org.mortbay.jetty:jetty-util:6.1.26=testCompileClasspath,testRuntimeClasspath
org.mortbay.jetty:jetty:6.1.26=testCompileClasspath,testRuntimeClasspath
org.objenesis:objenesis:2.1=css
@@ -471,23 +464,23 @@ org.slf4j:jcl-over-slf4j:1.7.30=nonprodRuntime,runtime,testRuntimeClasspath
org.slf4j:jul-to-slf4j:1.7.30=nonprodRuntime,runtime,testRuntimeClasspath
org.slf4j:slf4j-api:1.7.30=nonprodRuntime,runtime
org.slf4j:slf4j-api:1.7.36=compileClasspath,nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath
org.slf4j:slf4j-api:2.0.7=deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-jdk14:2.0.7=deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.9=deploy_jar,runtimeClasspath,testRuntimeClasspath
org.slf4j:slf4j-jdk14:2.0.9=deploy_jar,runtimeClasspath,testRuntimeClasspath
org.springframework:spring-core:5.3.27=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-expression:5.3.27=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-jcl:5.3.27=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:database-commons:1.18.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:jdbc:1.18.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:junit-jupiter:1.18.3=testCompileClasspath,testRuntimeClasspath
org.testcontainers:postgresql:1.18.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:selenium:1.18.3=testCompileClasspath,testRuntimeClasspath
org.testcontainers:testcontainers:1.18.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:database-commons:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:jdbc:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:junit-jupiter:1.19.0=testCompileClasspath,testRuntimeClasspath
org.testcontainers:postgresql:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:selenium:1.19.0=testCompileClasspath,testRuntimeClasspath
org.testcontainers:testcontainers:1.19.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.threeten:threetenbp:1.6.8=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.tukaani:xz:1.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.w3c.css:sac:1.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.webjars.npm:viz.js-graphviz-java:2.1.3=nonprodRuntime,runtime,testRuntimeClasspath
org.xerial.snappy:snappy-java:1.1.10.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.yaml:snakeyaml:1.33=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.xerial.snappy:snappy-java:1.1.10.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.yaml:snakeyaml:2.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-api:16.10.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-diagram:16.10.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-tools:16.10.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath

View File

@@ -27,6 +27,10 @@ import static google.registry.beam.rde.RdePipeline.TupleTags.REVISION_ID;
import static google.registry.beam.rde.RdePipeline.TupleTags.SUPERORDINATE_DOMAINS;
import static google.registry.model.reporting.HistoryEntryDao.RESOURCE_TYPES_TO_HISTORY_TYPES;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.SafeSerializationUtils.safeDeserializeCollection;
import static google.registry.util.SafeSerializationUtils.serializeCollection;
import static google.registry.util.SerializeUtils.decodeBase64;
import static google.registry.util.SerializeUtils.encodeBase64;
import static org.apache.beam.sdk.values.TypeDescriptors.kvs;
import com.google.common.collect.ImmutableList;
@@ -65,11 +69,7 @@ import google.registry.rde.PendingDeposit.PendingDepositCoder;
import google.registry.rde.RdeMarshaller;
import google.registry.util.UtilsModule;
import google.registry.xml.ValidationMode;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashSet;
import javax.inject.Inject;
@@ -658,14 +658,8 @@ public class RdePipeline implements Serializable {
*/
@SuppressWarnings("unchecked")
static ImmutableSet<PendingDeposit> decodePendingDeposits(String encodedPendingDeposits) {
try (ObjectInputStream ois =
new ObjectInputStream(
new ByteArrayInputStream(
BaseEncoding.base64Url().omitPadding().decode(encodedPendingDeposits)))) {
return (ImmutableSet<PendingDeposit>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
throw new IllegalArgumentException("Unable to parse encoded pending deposit map.", e);
}
return ImmutableSet.copyOf(
safeDeserializeCollection(PendingDeposit.class, decodeBase64(encodedPendingDeposits)));
}
/**
@@ -674,12 +668,7 @@ public class RdePipeline implements Serializable {
*/
public static String encodePendingDeposits(ImmutableSet<PendingDeposit> pendingDeposits)
throws IOException {
try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(pendingDeposits);
oos.flush();
return BaseEncoding.base64Url().omitPadding().encode(baos.toByteArray());
}
return encodeBase64(serializeCollection(pendingDeposits));
}
public static void main(String[] args) throws IOException, ClassNotFoundException {

View File

@@ -11,3 +11,7 @@
# Set the default logging level for all loggers to INFO.
.level = INFO
# Turn off logging in Hibernate classes for misleading ERROR-level logs
org.hibernate.engine.jdbc.batch.internal.BatchingBatch.level=OFF
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.level=OFF

View File

@@ -11,3 +11,7 @@
# Set the default logging level for all loggers to INFO.
.level = INFO
# Turn off logging in Hibernate classes for misleading ERROR-level logs
org.hibernate.engine.jdbc.batch.internal.BatchingBatch.level=OFF
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.level=OFF

View File

@@ -11,3 +11,7 @@
# Set the default logging level for all loggers to INFO.
.level = INFO
# Turn off logging in Hibernate classes for misleading ERROR-level logs
org.hibernate.engine.jdbc.batch.internal.BatchingBatch.level=OFF
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.level=OFF

View File

@@ -11,3 +11,7 @@
# Set the default logging level for all loggers to INFO.
.level = INFO
# Turn off logging in Hibernate classes for misleading ERROR-level logs
org.hibernate.engine.jdbc.batch.internal.BatchingBatch.level=OFF
org.hibernate.engine.jdbc.spi.SqlExceptionHelper.level=OFF

View File

@@ -16,6 +16,7 @@ package google.registry.flows;
import static com.google.common.base.MoreObjects.toStringHelper;
import static google.registry.request.RequestParameters.extractOptionalHeader;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
@@ -33,6 +34,7 @@ import google.registry.request.Header;
import google.registry.util.CidrAddressBlock;
import google.registry.util.ProxyHttpHeaders;
import java.net.InetAddress;
import java.security.MessageDigest;
import java.util.Optional;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
@@ -137,8 +139,16 @@ public class TlsCredentials implements TransportCredentials {
throw new MissingRegistrarCertificateException();
}
// Check if the certificate hash is equal to the one on file for the registrar.
if (!clientCertificateHash.equals(registrar.getClientCertificateHash())
&& !clientCertificateHash.equals(registrar.getFailoverClientCertificateHash())) {
byte[] certBytes = clientCertificateHash.get().getBytes(UTF_8);
if (!MessageDigest.isEqual(
certBytes,
registrar.getClientCertificateHash().map(x -> x.getBytes(UTF_8)).orElse(null))
&& !MessageDigest.isEqual(
certBytes,
registrar
.getFailoverClientCertificateHash()
.map(x -> x.getBytes(UTF_8))
.orElse(null))) {
logger.atWarning().log(
"Non-matching certificate hash (%s) for %s, wanted either %s or %s.",
clientCertificateHash,

View File

@@ -53,8 +53,8 @@ import google.registry.flows.custom.DomainRenewFlowCustomLogic.BeforeResponseRet
import google.registry.flows.custom.DomainRenewFlowCustomLogic.BeforeSaveParameters;
import google.registry.flows.custom.EntityChanges;
import google.registry.flows.domain.token.AllocationTokenFlowUtils;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemoveDomainTokenOnBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.RemoveDomainTokenOnNonBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemoveBulkPricingTokenOnBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.RemoveBulkPricingTokenOnNonBulkPricingDomainException;
import google.registry.model.ImmutableObject;
import google.registry.model.billing.BillingBase.Reason;
import google.registry.model.billing.BillingEvent;
@@ -121,8 +121,8 @@ import org.joda.time.Duration;
* @error {@link DomainFlowUtils.RegistrarMustBeActiveForThisOperationException}
* @error {@link DomainFlowUtils.UnsupportedFeeAttributeException}
* @error {@link DomainRenewFlow.IncorrectCurrentExpirationDateException}
* @error {@link MissingRemoveDomainTokenOnBulkPricingDomainException}
* @error {@link RemoveDomainTokenOnNonBulkPricingDomainException}
* @error {@link MissingRemoveBulkPricingTokenOnBulkPricingDomainException}
* @error {@link RemoveBulkPricingTokenOnNonBulkPricingDomainException}
* @error {@link
* google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForDomainException}
* @error {@link
@@ -328,7 +328,7 @@ public final class DomainRenewFlow implements MutatingFlow {
checkHasBillingAccount(registrarId, existingDomain.getTld());
}
verifyUnitIsYears(command.getPeriod());
// We only allow __REMOVEDOMAIN__ token on bulk pricing domains for now
// We only allow __REMOVE_BULK_PRICING__ token on bulk pricing domains for now
verifyTokenAllowedOnDomain(existingDomain, allocationToken);
// If the date they specify doesn't match the expiration, fail. (This is an idempotence check).
if (!command.getCurrentExpirationDate().equals(

View File

@@ -243,21 +243,21 @@ public class AllocationTokenFlowUtils {
Domain domain, Optional<AllocationToken> allocationToken) throws EppException {
boolean domainHasBulkToken = domain.getCurrentBulkToken().isPresent();
boolean hasRemoveDomainToken =
boolean hasRemoveBulkPricingToken =
allocationToken.isPresent()
&& TokenBehavior.REMOVE_DOMAIN.equals(allocationToken.get().getTokenBehavior());
&& TokenBehavior.REMOVE_BULK_PRICING.equals(allocationToken.get().getTokenBehavior());
if (hasRemoveDomainToken && !domainHasBulkToken) {
throw new RemoveDomainTokenOnNonBulkPricingDomainException();
} else if (!hasRemoveDomainToken && domainHasBulkToken) {
throw new MissingRemoveDomainTokenOnBulkPricingDomainException();
if (hasRemoveBulkPricingToken && !domainHasBulkToken) {
throw new RemoveBulkPricingTokenOnNonBulkPricingDomainException();
} else if (!hasRemoveBulkPricingToken && domainHasBulkToken) {
throw new MissingRemoveBulkPricingTokenOnBulkPricingDomainException();
}
}
public static Domain maybeApplyBulkPricingRemovalToken(
Domain domain, Optional<AllocationToken> allocationToken) {
if (!allocationToken.isPresent()
|| !TokenBehavior.REMOVE_DOMAIN.equals(allocationToken.get().getTokenBehavior())) {
|| !TokenBehavior.REMOVE_BULK_PRICING.equals(allocationToken.get().getTokenBehavior())) {
return domain;
}
@@ -338,19 +338,19 @@ public class AllocationTokenFlowUtils {
}
}
/** The __REMOVEDOMAIN__ token is missing on a bulk pricing domain command */
public static class MissingRemoveDomainTokenOnBulkPricingDomainException
/** The __REMOVE_BULK_PRICING__ token is missing on a bulk pricing domain command */
public static class MissingRemoveBulkPricingTokenOnBulkPricingDomainException
extends AssociationProhibitsOperationException {
MissingRemoveDomainTokenOnBulkPricingDomainException() {
MissingRemoveBulkPricingTokenOnBulkPricingDomainException() {
super("Domains that are inside bulk pricing cannot be explicitly renewed or transferred");
}
}
/** The __REMOVEDOMAIN__ token is not allowed on non bulk pricing domains */
public static class RemoveDomainTokenOnNonBulkPricingDomainException
/** The __REMOVE_BULK_PRICING__ token is not allowed on non bulk pricing domains */
public static class RemoveBulkPricingTokenOnNonBulkPricingDomainException
extends AssociationProhibitsOperationException {
RemoveDomainTokenOnNonBulkPricingDomainException() {
super("__REMOVEDOMAIN__ token is not allowed on non bulk pricing domains");
RemoveBulkPricingTokenOnNonBulkPricingDomainException() {
super("__REMOVE_BULK_PRICING__ token is not allowed on non bulk pricing domains");
}
}
}

View File

@@ -14,6 +14,7 @@
package google.registry.model;
import static com.google.common.collect.ImmutableSortedMap.toImmutableSortedMap;
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
import static com.google.common.collect.Ordering.natural;
import com.fasterxml.jackson.core.JsonGenerator;
@@ -29,6 +30,7 @@ import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.StdSerializer;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator.Feature;
import com.google.common.collect.ImmutableSortedSet;
import google.registry.model.common.TimedTransitionProperty;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.tld.Tld.TldState;
@@ -39,6 +41,7 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.SortedMap;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
@@ -65,6 +68,57 @@ public class EntityYamlUtils {
return mapper;
}
/**
* A custom serializer for String Set to sort the order and make YAML generation deterministic.
*/
public static class SortedSetSerializer extends StdSerializer<Set<String>> {
public SortedSetSerializer() {
this(null);
}
public SortedSetSerializer(Class<Set<String>> t) {
super(t);
}
@Override
public void serialize(Set<String> value, JsonGenerator g, SerializerProvider provider)
throws IOException {
ImmutableSortedSet<String> sorted =
value.stream()
.collect(toImmutableSortedSet(String::compareTo)); // sort the entries into a new set
g.writeStartArray();
for (String entry : sorted) {
g.writeString(entry);
}
g.writeEndArray();
}
}
/** A custom serializer for Enum Set to sort the order and make YAML generation deterministic. */
public static class SortedEnumSetSerializer extends StdSerializer<Set<Enum>> {
public SortedEnumSetSerializer() {
this(null);
}
public SortedEnumSetSerializer(Class<Set<Enum>> t) {
super(t);
}
@Override
public void serialize(Set<Enum> value, JsonGenerator g, SerializerProvider provider)
throws IOException {
ImmutableSortedSet<String> sorted =
value.stream()
.map(Enum::name)
.collect(toImmutableSortedSet(String::compareTo)); // sort the entries into a new set
g.writeStartArray();
for (String entry : sorted) {
g.writeString(entry);
}
g.writeEndArray();
}
}
/** A custom JSON serializer for {@link Money}. */
public static class MoneySerializer extends StdSerializer<Money> {

View File

@@ -77,10 +77,10 @@ import org.joda.time.DateTime;
public class AllocationToken extends UpdateAutoTimestampEntity implements Buildable {
private static final long serialVersionUID = -3954475393220876903L;
private static final String REMOVE_DOMAIN = "__REMOVEDOMAIN__";
private static final String REMOVE_BULK_PRICING = "__REMOVE_BULK_PRICING__";
private static final ImmutableMap<String, TokenBehavior> STATIC_TOKEN_BEHAVIORS =
ImmutableMap.of(REMOVE_DOMAIN, TokenBehavior.REMOVE_DOMAIN);
ImmutableMap.of(REMOVE_BULK_PRICING, TokenBehavior.REMOVE_BULK_PRICING);
// Promotions should only move forward, and ENDED / CANCELLED are terminal states.
private static final ImmutableMultimap<TokenStatus, TokenStatus> VALID_TOKEN_STATUS_TRANSITIONS =
@@ -91,10 +91,10 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
private static final ImmutableMap<String, AllocationToken> BEHAVIORAL_TOKENS =
ImmutableMap.of(
REMOVE_DOMAIN,
REMOVE_BULK_PRICING,
new AllocationToken.Builder()
.setTokenType(TokenType.UNLIMITED_USE)
.setToken(REMOVE_DOMAIN)
.setToken(REMOVE_BULK_PRICING)
.build());
public static Optional<AllocationToken> maybeGetStaticTokenInstance(String name) {
@@ -142,10 +142,10 @@ public class AllocationToken extends UpdateAutoTimestampEntity implements Builda
/** No special behavior */
DEFAULT,
/**
* REMOVE_DOMAIN triggers domain removal from a bulk pricing package, bypasses DEFAULT token
* validations.
* REMOVE_BULK_PRICING triggers domain removal from a bulk pricing package, bypasses DEFAULT
* token validations.
*/
REMOVE_DOMAIN
REMOVE_BULK_PRICING
}
/** The status of this token with regard to any potential promotion. */

View File

@@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Maps.toMap;
import static google.registry.config.RegistryConfig.getSingletonCacheRefreshDuration;
import static google.registry.model.EntityYamlUtils.createObjectMapper;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import static google.registry.util.DateTimeUtils.END_OF_TIME;
@@ -28,6 +29,8 @@ import static org.joda.money.CurrencyUnit.USD;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.github.benmanes.caffeine.cache.CacheLoader;
@@ -50,6 +53,8 @@ import google.registry.model.EntityYamlUtils.CurrencyDeserializer;
import google.registry.model.EntityYamlUtils.CurrencySerializer;
import google.registry.model.EntityYamlUtils.OptionalDurationSerializer;
import google.registry.model.EntityYamlUtils.OptionalStringSerializer;
import google.registry.model.EntityYamlUtils.SortedEnumSetSerializer;
import google.registry.model.EntityYamlUtils.SortedSetSerializer;
import google.registry.model.EntityYamlUtils.TimedTransitionPropertyMoneyDeserializer;
import google.registry.model.EntityYamlUtils.TimedTransitionPropertyTldStateDeserializer;
import google.registry.model.EntityYamlUtils.TokenVKeyListDeserializer;
@@ -124,6 +129,20 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
public static final Money DEFAULT_SERVER_STATUS_CHANGE_BILLING_COST = Money.of(USD, 20);
public static final Money DEFAULT_REGISTRY_LOCK_OR_UNLOCK_BILLING_COST = Money.of(USD, 0);
public boolean equalYaml(Tld tldToCompare) {
if (this.equals(tldToCompare)) {
return true;
}
ObjectMapper mapper = createObjectMapper();
try {
String thisYaml = mapper.writeValueAsString(this);
String otherYaml = mapper.writeValueAsString(tldToCompare);
return thisYaml.equals(otherYaml);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
/** The type of TLD, which determines things like backups and escrow policy. */
public enum TldType {
/**
@@ -255,6 +274,7 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
* <p>All entries of this list must be valid keys for the map of {@code DnsWriter}s injected by
* {@code @Inject Map<String, DnsWriter>}
*/
@JsonSerialize(using = SortedSetSerializer.class)
@Column(nullable = false)
Set<String> dnsWriters;
@@ -354,6 +374,7 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
/** The set of reserved list names that are applicable to this tld. */
@JsonSerialize(using = SortedSetSerializer.class)
@Column(name = "reserved_list_names")
Set<String> reservedListNames;
@@ -493,10 +514,14 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
DateTime claimsPeriodEnd = END_OF_TIME;
/** An allowlist of clients allowed to be used on domains on this TLD (ignored if empty). */
@Nullable Set<String> allowedRegistrantContactIds;
@Nullable
@JsonSerialize(using = SortedSetSerializer.class)
Set<String> allowedRegistrantContactIds;
/** An allowlist of hosts allowed to be used on domains on this TLD (ignored if empty). */
@Nullable Set<String> allowedFullyQualifiedHostNames;
@Nullable
@JsonSerialize(using = SortedSetSerializer.class)
Set<String> allowedFullyQualifiedHostNames;
/**
* Indicates when the TLD is being modified using locally modified files to override the source
@@ -521,6 +546,7 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
List<VKey<AllocationToken>> defaultPromoTokens;
/** A set of allowed {@link IdnTableEnum}s for this TLD, or empty if we should use the default. */
@JsonSerialize(using = SortedEnumSetSerializer.class)
Set<IdnTableEnum> idnTables;
public String getTldStr() {
@@ -980,7 +1006,7 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
return this;
}
private static final Pattern ROID_SUFFIX_PATTERN = Pattern.compile("^[A-Z\\d_]{1,8}$");
public static final Pattern ROID_SUFFIX_PATTERN = Pattern.compile("^[A-Z\\d_]{1,8}$");
public Builder setRoidSuffix(String roidSuffix) {
checkArgument(

View File

@@ -26,6 +26,7 @@ import google.registry.request.RequestComponentBuilder;
import google.registry.request.RequestModule;
import google.registry.request.RequestScope;
import google.registry.ui.server.console.ConsoleDomainGetAction;
import google.registry.ui.server.console.ConsoleUserDataAction;
import google.registry.ui.server.console.RegistrarsAction;
import google.registry.ui.server.console.settings.ContactAction;
import google.registry.ui.server.console.settings.SecurityAction;
@@ -52,28 +53,29 @@ import google.registry.ui.server.registrar.RegistryLockVerifyAction;
WhiteboxModule.class,
})
interface FrontendRequestComponent {
ConsoleDomainGetAction consoleDomainGetAction();
ConsoleOteSetupAction consoleOteSetupAction();
ConsoleRegistrarCreatorAction consoleRegistrarCreatorAction();
ConsoleUiAction consoleUiAction();
ConsoleUserDataAction consoleUserDataAction();
ContactAction contactAction();
EppTlsAction eppTlsAction();
FlowComponent.Builder flowComponentBuilder();
OteStatusAction oteStatusAction();
RegistrarsAction registrarsAction();
RegistrarSettingsAction registrarSettingsAction();
RegistryLockGetAction registryLockGetAction();
RegistryLockPostAction registryLockPostAction();
RegistryLockVerifyAction registryLockVerifyAction();
ConsoleDomainGetAction consoleDomainGetAction();
ContactAction contactAction();
RegistrarsAction registrarsAction();
SecurityAction securityAction();
WhoisRegistrarFieldsAction whoisRegistrarFieldsAction();
@Subcomponent.Builder

View File

@@ -16,6 +16,8 @@ package google.registry.persistence;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import static google.registry.util.SafeSerializationUtils.safeDeserialize;
import static google.registry.util.SerializeUtils.decodeBase64;
import static java.util.function.Function.identity;
import com.google.common.base.Joiner;
@@ -97,7 +99,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
throw new IllegalArgumentException(
String.format("\"%s\" missing from the string: %s", LOOKUP_KEY, keyString));
}
return VKey.create(classType, SerializeUtils.parse(Serializable.class, kvs.get(LOOKUP_KEY)));
return VKey.create(classType, safeDeserialize(decodeBase64(kvs.get(LOOKUP_KEY))));
}
/** Returns the type of the entity. */

View File

@@ -0,0 +1,112 @@
// Copyright 2023 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.transaction;
import autovalue.shaded.com.google.common.collect.ImmutableList;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Joiner;
import java.sql.SQLException;
import java.util.Optional;
import javax.persistence.PersistenceException;
/**
* Wraps an exception thrown by the JPA framework and captures the SQL error details (state and
* status code) in the {@link #getMessage message}.
*
* <p>The {@link SQLException} class has its own chain of exceptions that describe multiple error
* conditions encontered during a transaction. A typical logger relying on the {@link
* Throwable#getCause() chain of causes} in {@code Throwable} instances cannot capture all details
* of errors thrown from the database drivers. This exception captures all error details in its
* message text.
*
* <p>The {@link TransactionManager} wraps every persistence exception in an instance of this class.
* This allows us to disable logging in specific Hibernate classes that logs at {@code ERROR}-level
* and rethrows. These {@code ERROR} logs are misleading, since the impacted transactions often
* succeeds on retries.
*
* <p>See the {@code logging.properties} files in the {@code env} package for the specific Hibernate
* classes that have logging suppressed.
*/
class DatabaseException extends PersistenceException {
private transient String cachedMessage;
@VisibleForTesting
DatabaseException(Throwable throwable) {
super(throwable);
}
@Override
public String getMessage() {
if (cachedMessage == null) {
cachedMessage = getSqlError(getCause());
}
return cachedMessage;
}
/**
* Throws an unchecked exception on behalf of the {@code original} {@link Throwable}.
*
* <p>If the {@code original Throwable} has at least one {@link SQLException} in its chain of
* causes, a {@link DatabaseException} is thrown; otherwise this does nothing.
*/
static void tryWrapAndThrow(Throwable original) {
Throwable t = original;
do {
if (t instanceof SQLException) {
throw new DatabaseException(original);
}
} while ((t = t.getCause()) != null);
}
/**
* Returns the SQL state and error code of every {@link SQLException} in the chain of causes, or
* empty string if such information is not found.
*/
static String getSqlError(Throwable t) {
ImmutableList.Builder<String> errMessageBuilder = new ImmutableList.Builder<>();
do {
if (t instanceof SQLException) {
SQLException e = (SQLException) t;
getSqlExceptionDetails(e).ifPresent(errMessageBuilder::add);
}
t = t.getCause();
} while (t != null);
return Joiner.on("\n").join(errMessageBuilder.build());
}
static Optional<String> getSqlExceptionDetails(SQLException sqlException) {
ImmutableList.Builder<String> errBuilder = new ImmutableList.Builder<>();
while (sqlException != null) {
if (sqlException.getErrorCode() > 0 || sqlException.getSQLState() != null) {
errBuilder.add(
"\tSQL Error: "
+ sqlException.getErrorCode()
+ ", SQLState: "
+ sqlException.getSQLState()
+ ", message: "
+ sqlException.getMessage()
+ ".");
}
sqlException = sqlException.getNextException();
}
ImmutableList<String> errors = errBuilder.build();
if (errors.isEmpty()) {
return Optional.empty();
}
return Optional.of(Joiner.on("\n").join(errors));
}
}

View File

@@ -19,6 +19,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableMap.toImmutableMap;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.config.RegistryConfig.getHibernatePerTransactionIsolationEnabled;
import static google.registry.persistence.transaction.DatabaseException.tryWrapAndThrow;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import static java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.joining;
@@ -213,6 +214,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
} catch (Throwable rollbackException) {
logger.atSevere().withCause(rollbackException).log("Rollback failed; suppressing error.");
}
tryWrapAndThrow(e);
throw e;
} finally {
txnInfo.clear();

View File

@@ -14,18 +14,23 @@
package google.registry.rde;
import static com.google.common.base.Preconditions.checkState;
import com.google.auto.value.AutoValue;
import google.registry.model.common.Cursor.CursorType;
import google.registry.model.rde.RdeMode;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.OutputStream;
import java.io.Serializable;
import java.util.Optional;
import javax.annotation.Nullable;
import org.apache.beam.sdk.coders.AtomicCoder;
import org.apache.beam.sdk.coders.BooleanCoder;
import org.apache.beam.sdk.coders.NullableCoder;
import org.apache.beam.sdk.coders.SerializableCoder;
import org.apache.beam.sdk.coders.StringUtf8Coder;
import org.apache.beam.sdk.coders.VarIntCoder;
import org.joda.time.DateTime;
@@ -35,6 +40,12 @@ import org.joda.time.Duration;
* Container representing a single RDE or BRDA XML escrow deposit that needs to be created.
*
* <p>There are some {@code @Nullable} fields here because Optionals aren't Serializable.
*
* <p>Note that this class is serialized in two ways: by Beam pipelines using custom serialization
* mechanism and the {@code Coder} API, and by Java serialization when passed as command-line
* arguments (see {@code RdePipeline#decodePendingDeposits}). The latter requires safe
* deserialization because the data crosses credential boundaries (See {@code
* SafeObjectInputStream}).
*/
@AutoValue
public abstract class PendingDeposit implements Serializable {
@@ -95,11 +106,61 @@ public abstract class PendingDeposit implements Serializable {
PendingDeposit() {}
/**
* Specifies that {@link SerializedForm} be used for {@code SafeObjectInputStream}-compatible
* custom-serialization of {@link AutoValue_PendingDeposit the AutoValue implementation class}.
*
* <p>This method is package-protected so that the AutoValue implementation class inherits this
* behavior.
*
* <p>This method leverages {@link PendingDepositCoder} to serializes an instance. However, it is
* not invoked in Beam pipelines.
*/
Object writeReplace() throws ObjectStreamException {
return new SerializedForm(this);
}
/**
* Proxy for custom-serialization of {@link PendingDeposit}. This is necessary because the actual
* class to be (de)serialized is the generated AutoValue implementation. See also {@link
* #writeReplace}.
*
* <p>This class leverages {@link PendingDepositCoder} to safely deserializes an instance.
* However, it is not used in Beam pipelines.
*/
private static class SerializedForm implements Serializable {
private static final long serialVersionUID = 3141095605225904433L;
private PendingDeposit value;
private SerializedForm(PendingDeposit value) {
this.value = value;
}
private void writeObject(ObjectOutputStream os) throws IOException {
checkState(value != null, "Non-null value expected for serialization.");
PendingDepositCoder.INSTANCE.encode(value, os);
}
private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
checkState(value == null, "Non-null value unexpected for deserialization.");
this.value = PendingDepositCoder.INSTANCE.decode(is);
}
@SuppressWarnings("unused")
private Object readResolve() throws ObjectStreamException {
return this.value;
}
}
/**
* A deterministic coder for {@link PendingDeposit} used during a GroupBy transform.
*
* <p>We cannot use a {@link SerializableCoder} directly because it does not guarantee
* determinism, which is required by GroupBy.
* <p>We cannot use a {@code SerializableCoder} directly for two reasons: the default
* serialization does not guarantee determinism, which is required by GroupBy in Beam; and the
* default deserialization is not robust against deserialization-based attacks (See {@code
* SafeObjectInputStream} for more information).
*/
public static class PendingDepositCoder extends AtomicCoder<PendingDeposit> {
@@ -117,10 +178,15 @@ public abstract class PendingDeposit implements Serializable {
public void encode(PendingDeposit value, OutputStream outStream) throws IOException {
BooleanCoder.of().encode(value.manual(), outStream);
StringUtf8Coder.of().encode(value.tld(), outStream);
SerializableCoder.of(DateTime.class).encode(value.watermark(), outStream);
SerializableCoder.of(RdeMode.class).encode(value.mode(), outStream);
NullableCoder.of(SerializableCoder.of(CursorType.class)).encode(value.cursor(), outStream);
NullableCoder.of(SerializableCoder.of(Duration.class)).encode(value.interval(), outStream);
StringUtf8Coder.of().encode(value.watermark().toString(), outStream);
StringUtf8Coder.of().encode(value.mode().name(), outStream);
NullableCoder.of(StringUtf8Coder.of())
.encode(
Optional.ofNullable(value.cursor()).map(CursorType::name).orElse(null), outStream);
NullableCoder.of(StringUtf8Coder.of())
.encode(
Optional.ofNullable(value.interval()).map(Duration::toString).orElse(null),
outStream);
NullableCoder.of(StringUtf8Coder.of()).encode(value.directoryWithTrailingSlash(), outStream);
NullableCoder.of(VarIntCoder.of()).encode(value.revision(), outStream);
}
@@ -130,10 +196,14 @@ public abstract class PendingDeposit implements Serializable {
return new AutoValue_PendingDeposit(
BooleanCoder.of().decode(inStream),
StringUtf8Coder.of().decode(inStream),
SerializableCoder.of(DateTime.class).decode(inStream),
SerializableCoder.of(RdeMode.class).decode(inStream),
NullableCoder.of(SerializableCoder.of(CursorType.class)).decode(inStream),
NullableCoder.of(SerializableCoder.of(Duration.class)).decode(inStream),
DateTime.parse(StringUtf8Coder.of().decode(inStream)),
RdeMode.valueOf(StringUtf8Coder.of().decode(inStream)),
Optional.ofNullable(NullableCoder.of(StringUtf8Coder.of()).decode(inStream))
.map(CursorType::valueOf)
.orElse(null),
Optional.ofNullable(NullableCoder.of(StringUtf8Coder.of()).decode(inStream))
.map(Duration::parse)
.orElse(null),
NullableCoder.of(StringUtf8Coder.of()).decode(inStream),
NullableCoder.of(VarIntCoder.of()).decode(inStream));
}

View File

@@ -26,6 +26,7 @@ import com.google.appengine.api.users.User;
import com.google.common.collect.ImmutableSet;
import com.google.common.flogger.FluentLogger;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import javax.inject.Inject;
import javax.servlet.http.HttpServletRequest;
@@ -80,7 +81,10 @@ public class OAuthAuthenticationMechanism implements AuthenticationMechanism {
// Assume that, if a bearer token is found, it's what OAuthService will use to attempt
// authentication. This is not technically guaranteed by the contract of OAuthService; see
// OAuthTokenInfo for more information.
String rawAccessToken = header.substring(BEARER_PREFIX.length());
String rawAccessToken =
RegistryEnvironment.get() == RegistryEnvironment.PRODUCTION
? "Raw token redacted in prod"
: header.substring(BEARER_PREFIX.length());
// Get the OAuth information. The various oauthService method calls use a single cached
// authentication result, so we can call them one by one.

View File

@@ -0,0 +1,228 @@
// Copyright 2023 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.tools;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.model.tld.Tld.Builder.ROID_SUFFIX_PATTERN;
import static google.registry.model.tld.Tlds.getTlds;
import static google.registry.util.ListNamingUtils.convertFilePathToName;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.CharMatcher;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import com.google.common.flogger.FluentLogger;
import google.registry.model.tld.Tld;
import google.registry.model.tld.label.PremiumList;
import google.registry.model.tld.label.PremiumListDao;
import google.registry.tools.params.PathParameter;
import google.registry.util.Idn;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import javax.inject.Inject;
import javax.inject.Named;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.joda.time.DateTime;
import org.yaml.snakeyaml.Yaml;
/** Command to create or update a {@link Tld} using a YAML file. */
@Parameters(separators = " =", commandDescription = "Create or update TLD using YAML")
public class ConfigureTldCommand extends MutatingCommand {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Parameter(
names = {"-i", "--input"},
description = "Filename of TLD YAML file.",
validateWith = PathParameter.InputFile.class,
required = true)
Path inputFile;
@Parameter(
names = {"-b", "--breakglass"},
description =
"Sets the breakglass field on the TLD to true, preventing Cloud Build from overwriting"
+ " these new changes until the TLD configuration file stored internally matches the"
+ " configuration in the database.")
boolean breakglass;
@Inject ObjectMapper mapper;
@Inject
@Named("dnsWriterNames")
Set<String> validDnsWriterNames;
/** Indicates if the passed in file contains new changes to the TLD */
boolean newDiff = true;
/**
* Indicates if the existing TLD is currently in breakglass mode and should not be modified unless
* the breakglass flag is used
*/
boolean oldTldInBreakglass = false;
@Override
protected void init() throws Exception {
String name = convertFilePathToName(inputFile);
Map<String, Object> tldData = new Yaml().load(Files.newBufferedReader(inputFile));
checkName(name, tldData);
checkForMissingFields(tldData);
Tld oldTld = getTlds().contains(name) ? Tld.get(name) : null;
Tld newTld = mapper.readValue(inputFile.toFile(), Tld.class);
if (oldTld != null) {
oldTldInBreakglass = oldTld.getBreakglassMode();
newDiff = !oldTld.equalYaml(newTld);
}
if (!newDiff && !oldTldInBreakglass) {
// Don't construct a new object if there is no new diff
return;
}
if (oldTldInBreakglass && !breakglass) {
checkArgument(
!newDiff,
"Changes can not be applied since TLD is in breakglass mode but the breakglass flag was"
+ " not used");
// if there are no new diffs, then the YAML file has caught up to the database and the
// breakglass mode should be removed
logger.atInfo().log("Breakglass mode removed from TLD: %s", name);
}
checkPremiumList(newTld);
checkDnsWriters(newTld);
checkCurrency(newTld);
// Set the new TLD to breakglass mode if breakglass flag was used
if (breakglass) {
newTld = newTld.asBuilder().setBreakglassMode(true).build();
}
stageEntityChange(oldTld, newTld);
}
@Override
protected boolean dontRunCommand() {
if (!newDiff) {
if (oldTldInBreakglass && !breakglass) {
// Run command to remove breakglass mode
return false;
}
logger.atInfo().log("TLD YAML file contains no new changes");
checkArgument(
!breakglass || oldTldInBreakglass,
"Breakglass mode can only be set when making new changes to a TLD configuration");
return true;
}
return false;
}
private void checkName(String name, Map<String, Object> tldData) {
checkArgument(CharMatcher.ascii().matchesAllOf(name), "A TLD name must be in plain ASCII");
checkArgument(!Character.isDigit(name.charAt(0)), "TLDs cannot begin with a number");
checkArgument(
tldData.get("tldStr").equals(name),
"The input file name must match the name of the TLD it represents");
checkArgument(
tldData.get("tldUnicode").equals(Idn.toUnicode(name)),
"The value for tldUnicode must equal the unicode representation of the TLD name");
checkArgument(
ROID_SUFFIX_PATTERN.matcher((CharSequence) tldData.get("roidSuffix")).matches(),
"ROID suffix must be in format %s",
ROID_SUFFIX_PATTERN.pattern());
}
private void checkForMissingFields(Map<String, Object> tldData) {
Set<String> tldFields =
Arrays.stream(Tld.class.getDeclaredFields())
.filter(field -> !Modifier.isStatic(field.getModifiers()))
.filter(field -> field.getAnnotation(JsonIgnore.class) == null)
.map(Field::getName)
.collect(Collectors.toSet());
Set<String> missingFields = new HashSet<>();
for (String field : tldFields) {
if (!tldData.containsKey(field)) {
missingFields.add(field);
}
}
checkArgument(
missingFields.isEmpty(),
"The input file is missing data for the following fields: %s",
missingFields);
}
private void checkPremiumList(Tld newTld) {
Optional<String> premiumListName = newTld.getPremiumListName();
if (!premiumListName.isPresent()) {
return;
}
Optional<PremiumList> premiumList = PremiumListDao.getLatestRevision(premiumListName.get());
checkArgument(
premiumList.isPresent(),
"The premium list with the name %s does not exist",
premiumListName.get());
checkArgument(
premiumList.get().getCurrency().equals(newTld.getCurrency()),
"The premium list must use the TLD's currency");
}
private void checkDnsWriters(Tld newTld) {
ImmutableSet<String> dnsWriters = newTld.getDnsWriters();
SetView<String> invalidDnsWriters = Sets.difference(dnsWriters, validDnsWriterNames);
checkArgument(
invalidDnsWriters.isEmpty(), "Invalid DNS writer name(s) specified: %s", invalidDnsWriters);
}
private void checkCurrency(Tld newTld) {
CurrencyUnit currencyUnit = newTld.getCurrency();
checkArgument(
currencyUnit.equals(newTld.getCreateBillingCost().getCurrencyUnit()),
"createBillingCost must use the same currency as the TLD");
checkArgument(
currencyUnit.equals(newTld.getRestoreBillingCost().getCurrencyUnit()),
"restoreBillingCost must use the same currency as the TLD");
checkArgument(
currencyUnit.equals(newTld.getServerStatusChangeBillingCost().getCurrencyUnit()),
"serverStatusChangeBillingCost must use the same currency as the TLD");
checkArgument(
currencyUnit.equals(newTld.getRegistryLockOrUnlockBillingCost().getCurrencyUnit()),
"registryLockOrUnlockBillingCost must use the same currency as the TLD");
ImmutableSortedMap<DateTime, Money> renewBillingCostTransitions =
newTld.getRenewBillingCostTransitions();
for (Money renewBillingCost : renewBillingCostTransitions.values()) {
checkArgument(
renewBillingCost.getCurrencyUnit().equals(currencyUnit),
"All Money values in the renewBillingCostTransitions map must use the TLD's currency"
+ " unit");
}
ImmutableSortedMap<DateTime, Money> eapFeeSchedule = newTld.getEapFeeScheduleAsMap();
for (Money eapFee : eapFeeSchedule.values()) {
checkArgument(
eapFee.getCurrencyUnit().equals(currencyUnit),
"All Money values in the eapFeeSchedule map must use the TLD's currency unit");
}
}
}

View File

@@ -15,9 +15,12 @@
package google.registry.tools;
import static google.registry.tools.CommandUtilities.promptForYes;
import static java.nio.charset.StandardCharsets.UTF_8;
import com.beust.jcommander.Parameter;
import com.google.common.base.Strings;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
/** A {@link Command} that implements a confirmation step before executing. */
public abstract class ConfirmingCommand implements Command {
@@ -27,23 +30,37 @@ public abstract class ConfirmingCommand implements Command {
description = "Do not prompt before executing")
boolean force;
public PrintStream printStream;
public PrintStream errorPrintStream;
protected ConfirmingCommand() {
try {
printStream = new PrintStream(System.out, false, UTF_8.name());
errorPrintStream = new PrintStream(System.err, false, UTF_8.name());
} catch (UnsupportedEncodingException e) {
throw new RuntimeException(e);
}
}
@Override
public final void run() throws Exception {
if (checkExecutionState()) {
init();
printLineIfNotEmpty(prompt());
printLineIfNotEmpty(prompt(), printStream);
if (dontRunCommand()) {
// This typically happens when all of the work is accomplished inside of prompt(), so do
// nothing further.
return;
} else if (force || promptForYes("Perform this command?")) {
System.out.println("Running ... ");
System.out.println(execute());
printLineIfNotEmpty(postExecute());
printStream.println("Running ... ");
printStream.println(execute());
printLineIfNotEmpty(postExecute(), printStream);
} else {
System.out.println("Command aborted.");
printStream.println("Command aborted.");
}
}
printStream.close();
errorPrintStream.close();
}
/** Run any pre-execute command checks and return true if they all pass. */
@@ -76,9 +93,9 @@ public abstract class ConfirmingCommand implements Command {
}
/** Prints the provided text with a trailing newline, if text is not null or empty. */
private static void printLineIfNotEmpty(String text) {
private static void printLineIfNotEmpty(String text, PrintStream printStream) {
if (!Strings.isNullOrEmpty(text)) {
System.out.println(text);
printStream.println(text);
}
}
}

View File

@@ -78,7 +78,7 @@ final class CreateDomainCommand extends CreateOrUpdateDomainCommand {
Money createCost = prices.getCreateCost();
currency = createCost.getCurrencyUnit().getCode();
cost = createCost.multipliedBy(period).getAmount().toString();
System.out.printf(
printStream.printf(
"NOTE: %s is premium at %s per year; sending total cost for %d year(s) of %s %s.\n",
domain, createCost, period, currency, cost);
}

View File

@@ -25,8 +25,8 @@ import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Sets;
import com.google.common.collect.Sets.SetView;
import google.registry.model.pricing.StaticPremiumListPricingEngine;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldState;
@@ -39,6 +39,7 @@ import google.registry.tools.params.OptionalStringParameter;
import google.registry.tools.params.StringListParameter;
import google.registry.tools.params.TransitionListParameter.BillingCostTransitions;
import google.registry.tools.params.TransitionListParameter.TldStateTransitions;
import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
@@ -233,12 +234,11 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
@Nullable
@Parameter(
names = {"--num_dns_publish_locks"},
description =
"The number of publish locks we allow in parallel for DNS updates under this tld "
+ "(1 for TLD-wide locks)",
arity = 1
)
names = {"--num_dns_publish_locks"},
description =
"The number of publish locks we allow in parallel for DNS updates under this tld "
+ "(1 for TLD-wide locks)",
arity = 1)
Integer numDnsPublishShards;
@Nullable
@@ -301,7 +301,7 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
protected abstract void initTldCommand();
@Override
protected final void init() {
protected final void init() throws UnsupportedEncodingException {
assertAllowedEnvironment();
initTldCommand();
String duplicates = Joiner.on(", ").join(findDuplicates(mainParameters));
@@ -360,7 +360,7 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
if (!renewBillingCostTransitions.isEmpty()) {
// TODO(b/20764952): need invoicing support for multiple renew billing costs.
if (renewBillingCostTransitions.size() > 1) {
System.err.println(
errorPrintStream.println(
"----------------------\n"
+ "WARNING: Do not set multiple renew cost transitions "
+ "until b/20764952 is fixed.\n"
@@ -409,8 +409,7 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
if (dnsWriters != null) {
ImmutableSet<String> dnsWritersSet = ImmutableSet.copyOf(dnsWriters);
ImmutableSortedSet<String> invalidDnsWriters =
ImmutableSortedSet.copyOf(Sets.difference(dnsWritersSet, validDnsWriterNames));
SetView<String> invalidDnsWriters = Sets.difference(dnsWritersSet, validDnsWriterNames);
checkArgument(
invalidDnsWriters.isEmpty(),
"Invalid DNS writer name(s) specified: %s",
@@ -464,7 +463,8 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
}
}
private void checkReservedListValidityForTld(String tld, Set<String> reservedListNames) {
private void checkReservedListValidityForTld(String tld, Set<String> reservedListNames)
throws UnsupportedEncodingException {
ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
for (String reservedListName : reservedListNames) {
if (!reservedListName.startsWith("common_") && !reservedListName.startsWith(tld + "_")) {
@@ -477,7 +477,7 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
Joiner.on(", ").join(invalidNames),
tld);
if (overrideReservedListRules) {
System.err.println("Error overridden: " + errMsg);
errorPrintStream.println("Error overridden: " + errMsg);
} else {
throw new IllegalArgumentException(errMsg);
}

View File

@@ -85,7 +85,7 @@ final class DeleteAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
if (!dryRun) {
tm().delete(tokensToDelete);
}
System.out.printf(
printStream.printf(
"%s tokens: %s\n",
dryRun ? "Would delete" : "Deleted",
JOINER.join(tokensToDelete.stream().map(VKey::getKey).sorted().collect(toImmutableList())));

View File

@@ -14,6 +14,7 @@
package google.registry.tools;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.collect.ImmutableMap;
@@ -86,17 +87,17 @@ class LoadTestCommand extends ConfirmingCommand implements CommandWithConnection
@Override
protected boolean checkExecutionState() {
if (RegistryToolEnvironment.get() == RegistryToolEnvironment.PRODUCTION) {
System.err.println("You may not run a load test against production.");
errorPrintStream.println("You may not run a load test against production.");
return false;
}
// Check validity of TLD and Client Id.
if (!Tlds.getTlds().contains(tld)) {
System.err.printf("No such TLD: %s\n", tld);
errorPrintStream.printf("No such TLD: %s\n", tld);
return false;
}
if (!Registrar.loadByRegistrarId(clientId).isPresent()) {
System.err.printf("No such client: %s\n", clientId);
errorPrintStream.printf("No such client: %s\n", clientId);
return false;
}
@@ -112,7 +113,7 @@ class LoadTestCommand extends ConfirmingCommand implements CommandWithConnection
@Override
protected String execute() throws Exception {
System.err.println("Initiating load test...");
errorPrintStream.println("Initiating load test...");
ImmutableMap<String, Object> params = new ImmutableMap.Builder<String, Object>()
.put("tld", tld)

View File

@@ -71,7 +71,7 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand {
}
String duplicates = Joiner.on(", ").join(findDuplicates(mainParameters));
checkArgument(duplicates.isEmpty(), "Duplicate domain arguments found: '%s'", duplicates);
System.out.println(
printStream.println(
"== ENSURE THAT YOU HAVE AUTHENTICATED THE REGISTRAR BEFORE RUNNING THIS COMMAND ==");
}

View File

@@ -33,6 +33,7 @@ public final class RegistryTool {
.put("canonicalize_labels", CanonicalizeLabelsCommand.class)
.put("check_domain", CheckDomainCommand.class)
.put("check_domain_claims", CheckDomainClaimsCommand.class)
.put("configure_tld", ConfigureTldCommand.class)
.put("convert_idn", ConvertIdnCommand.class)
.put("count_domains", CountDomainsCommand.class)
.put("create_anchor_tenant", CreateAnchorTenantCommand.class)

View File

@@ -90,6 +90,8 @@ interface RegistryToolComponent {
void inject(CheckDomainCommand command);
void inject(ConfigureTldCommand command);
void inject(CountDomainsCommand command);
void inject(CreateAnchorTenantCommand command);

View File

@@ -42,6 +42,7 @@ import google.registry.model.poll.PollMessage;
import google.registry.model.reporting.HistoryEntry.Type;
import google.registry.util.Clock;
import google.registry.util.NonFinalForTesting;
import java.io.UnsupportedEncodingException;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
@@ -76,7 +77,7 @@ class UnrenewDomainCommand extends ConfirmingCommand {
StatusValue.SERVER_UPDATE_PROHIBITED);
@Override
protected void init() {
protected void init() throws UnsupportedEncodingException {
checkArgument(period >= 1 && period <= 9, "Period must be in the range 1-9");
DateTime now = clock.nowUtc();
ImmutableSet.Builder<String> domainsNonexistentBuilder = new ImmutableSet.Builder<>();
@@ -116,20 +117,24 @@ class UnrenewDomainCommand extends ConfirmingCommand {
&& domainsDeleting.isEmpty()
&& domainsWithDisallowedStatuses.isEmpty()
&& domainsExpiringTooSoon.isEmpty());
if (foundInvalidDomains) {
System.err.print("Found domains that cannot be unrenewed for the following reasons:\n\n");
errorPrintStream.print(
"Found domains that cannot be unrenewed for the following reasons:\n\n");
}
if (!domainsNonexistent.isEmpty()) {
System.err.printf("Domains that don't exist: %s\n\n", domainsNonexistent);
errorPrintStream.printf("Domains that don't exist: %s\n\n", domainsNonexistent);
}
if (!domainsDeleting.isEmpty()) {
System.err.printf("Domains that are deleted or pending delete: %s\n\n", domainsDeleting);
errorPrintStream.printf(
"Domains that are deleted or pending delete: %s\n\n", domainsDeleting);
}
if (!domainsWithDisallowedStatuses.isEmpty()) {
System.err.printf("Domains with disallowed statuses: %s\n\n", domainsWithDisallowedStatuses);
errorPrintStream.printf(
"Domains with disallowed statuses: %s\n\n", domainsWithDisallowedStatuses);
}
if (!domainsExpiringTooSoon.isEmpty()) {
System.err.printf("Domains expiring too soon: %s\n\n", domainsExpiringTooSoon);
errorPrintStream.printf("Domains expiring too soon: %s\n\n", domainsExpiringTooSoon);
}
checkArgument(!foundInvalidDomains, "Aborting because some domains cannot be unrenewed");
}
@@ -154,7 +159,7 @@ class UnrenewDomainCommand extends ConfirmingCommand {
protected String execute() {
for (String domainName : mainParameters) {
tm().transact(() -> unrenewDomain(domainName));
System.out.printf("Unrenewed %s\n", domainName);
printStream.printf("Unrenewed %s\n", domainName);
}
return "Successfully unrenewed all domains.";
}

View File

@@ -208,7 +208,7 @@ final class UpdateAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
if (!dryRun) {
tm().putAll(batch);
}
System.out.printf(
printStream.printf(
"%s tokens: %s\n",
dryRun ? "Would update" : "Updated",
JOINER.join(

View File

@@ -70,14 +70,14 @@ public class CreateCancellationsForBillingEventsCommand extends ConfirmingComman
}
});
billingEventsToCancel = billingEventsBuilder.build();
System.out.printf("Found %d BillingEvent(s) to cancel\n", billingEventsToCancel.size());
printStream.printf("Found %d BillingEvent(s) to cancel\n", billingEventsToCancel.size());
ImmutableSet<Long> missingIds = missingIdsBuilder.build();
if (!missingIds.isEmpty()) {
System.out.printf("Missing BillingEvent(s) for IDs %s\n", missingIds);
printStream.printf("Missing BillingEvent(s) for IDs %s\n", missingIds);
}
ImmutableSet<Long> alreadyCancelledIds = alreadyCancelledIdsBuilder.build();
if (!alreadyCancelledIds.isEmpty()) {
System.out.printf(
printStream.printf(
"The following BillingEvent IDs were already cancelled: %s\n", alreadyCancelledIds);
}
}
@@ -96,7 +96,7 @@ public class CreateCancellationsForBillingEventsCommand extends ConfirmingComman
tm().transact(
() -> {
if (alreadyCancelled(billingEvent)) {
System.out.printf(
printStream.printf(
"BillingEvent %d already cancelled, this is unexpected.\n",
billingEvent.getId());
return 0;
@@ -111,7 +111,7 @@ public class CreateCancellationsForBillingEventsCommand extends ConfirmingComman
.setReason(BillingBase.Reason.ERROR)
.setTargetId(billingEvent.getTargetId())
.build());
System.out.printf(
printStream.printf(
"Added BillingCancellation for BillingEvent with ID %d\n",
billingEvent.getId());
return 1;

View File

@@ -0,0 +1,83 @@
// Copyright 2023 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.console;
import static google.registry.request.Action.Method.GET;
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.collect.ImmutableMap;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.console.User;
import google.registry.request.Action;
import google.registry.request.Response;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.UserAuthInfo;
import google.registry.ui.server.registrar.JsonGetAction;
import javax.inject.Inject;
import org.json.JSONObject;
@Action(
service = Action.Service.DEFAULT,
path = ConsoleUserDataAction.PATH,
method = {GET},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class ConsoleUserDataAction implements JsonGetAction {
public static final String PATH = "/console-api/userdata";
private final AuthResult authResult;
private final Response response;
private final String technicalDocsUrl;
@Inject
public ConsoleUserDataAction(
AuthResult authResult,
Response response,
@Config("technicalDocsUrl") String technicalDocsUrl) {
this.response = response;
this.authResult = authResult;
this.technicalDocsUrl = technicalDocsUrl;
}
@Override
public void run() {
UserAuthInfo authInfo = authResult.userAuthInfo().get();
if (!authInfo.consoleUser().isPresent()) {
response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
return;
}
User user = authInfo.consoleUser().get();
JSONObject json =
new JSONObject(
ImmutableMap.of(
// Both isAdmin and globalRole flags are used by UI as an indicator to hide / show
// specific set of widgets and screens.
// For example:
// - Admin sees everything and can create other users
// - Empty global role indicates registrar user, with access to registrar specific
// screens and widgets.
// This however is merely for visual representation, as any back-end action contains
// auth checks.
"isAdmin", user.getUserRoles().isAdmin(),
"globalRole", user.getUserRoles().getGlobalRole(),
// Is used by UI to construct a link to registry resources
"technicalDocsUrl", technicalDocsUrl));
response.setPayload(json.toString());
response.setStatus(HttpStatusCodes.STATUS_CODE_OK);
}
}

View File

@@ -93,7 +93,7 @@ public class RegistrarsAction implements JsonGetAction {
return;
}
ImmutableList<Registrar> registrars =
Streams.stream(Registrar.loadAllCached())
Streams.stream(Registrar.loadAll())
.filter(r -> r.getType() == Registrar.Type.REAL)
.collect(ImmutableList.toImmutableList());

View File

@@ -1,105 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.xjc;
import static java.nio.charset.StandardCharsets.UTF_8;
import google.registry.xml.XmlException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
/**
* JAXB element wrapper for java object serialization.
*
* Instances of {@link JaxbFragment} wrap a non-serializable JAXB element instance, and provide
* hooks into the java object serialization process that allow the elements to be safely
* marshalled and unmarshalled using {@link ObjectOutputStream} and {@link ObjectInputStream},
* respectively.
*/
public class JaxbFragment<T> implements Serializable {
private static final long serialVersionUID = 5651243983008818813L;
private T instance;
/** Stores a JAXB element in a {@link JaxbFragment} */
public static <T> JaxbFragment<T> create(T object) {
JaxbFragment<T> fragment = new JaxbFragment<>();
fragment.instance = object;
return fragment;
}
/** Serializes a JAXB element into xml bytes. */
private static <T> byte[] freezeInstance(T instance) throws IOException {
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
XjcXmlTransformer.marshalLenient(instance, bout, UTF_8);
return bout.toByteArray();
} catch (XmlException e) {
throw new IOException(e);
}
}
/** Deserializes a JAXB element from xml bytes. */
private static <T> T unfreezeInstance(byte[] instanceData, Class<T> instanceType)
throws IOException {
try {
ByteArrayInputStream bin = new ByteArrayInputStream(instanceData);
return XjcXmlTransformer.unmarshal(instanceType, bin);
} catch (XmlException e) {
throw new IOException(e);
}
}
/**
* Retrieves the JAXB element that is wrapped by this fragment.
*/
public T getInstance() {
return instance;
}
@Override
public String toString() {
try {
return new String(freezeInstance(instance), UTF_8);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
private void writeObject(ObjectOutputStream out) throws IOException {
// write instanceType, then instanceData
out.writeObject(instance.getClass());
out.writeObject(freezeInstance(instance));
}
@SuppressWarnings("unchecked")
private void readObject(ObjectInputStream in) throws IOException {
// read instanceType, then instanceData
Class<T> instanceType;
byte[] instanceData;
try {
instanceType = (Class<T>) in.readObject();
instanceData = (byte[]) in.readObject();
} catch (ClassNotFoundException e) {
throw new RuntimeException(e);
}
instance = unfreezeInstance(instanceData, instanceType);
}
}

View File

@@ -77,8 +77,8 @@ import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTok
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AllocationTokenNotValidForTldException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.AlreadyRedeemedAllocationTokenException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.InvalidAllocationTokenException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemoveDomainTokenOnBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.RemoveDomainTokenOnNonBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.MissingRemoveBulkPricingTokenOnBulkPricingDomainException;
import google.registry.flows.domain.token.AllocationTokenFlowUtils.RemoveBulkPricingTokenOnNonBulkPricingDomainException;
import google.registry.flows.exceptions.ResourceStatusProhibitsOperationException;
import google.registry.model.billing.BillingBase.Flag;
import google.registry.model.billing.BillingBase.Reason;
@@ -1276,12 +1276,13 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "token"));
EppException thrown =
assertThrows(MissingRemoveDomainTokenOnBulkPricingDomainException.class, this::runFlow);
assertThrows(
MissingRemoveBulkPricingTokenOnBulkPricingDomainException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailsToRenewBulkPricingDomainNoRemoveDomainToken() throws Exception {
void testFailsToRenewBulkPricingDomainNoRemoveBulkPricingToken() throws Exception {
AllocationToken token =
persistResource(
new AllocationToken.Builder()
@@ -1299,25 +1300,26 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
setEppInput("domain_renew.xml", ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "5"));
EppException thrown =
assertThrows(MissingRemoveDomainTokenOnBulkPricingDomainException.class, this::runFlow);
assertThrows(
MissingRemoveBulkPricingTokenOnBulkPricingDomainException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testFailsToRenewNonBulkPricingDomainWithRemoveDomainToken() throws Exception {
void testFailsToRenewNonBulkPricingDomainWithRemoveBulkPricingToken() throws Exception {
persistDomain();
setEppInput(
"domain_renew_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVEDOMAIN__"));
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVE_BULK_PRICING__"));
EppException thrown =
assertThrows(RemoveDomainTokenOnNonBulkPricingDomainException.class, this::runFlow);
assertThrows(RemoveBulkPricingTokenOnNonBulkPricingDomainException.class, this::runFlow);
assertAboutEppExceptions().that(thrown).marshalsToXml();
}
@Test
void testSuccesfullyAppliesRemoveDomainToken() throws Exception {
void testSuccesfullyAppliesRemoveBulkPricingToken() throws Exception {
AllocationToken token =
persistResource(
new AllocationToken.Builder()
@@ -1333,7 +1335,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
reloadResourceByForeignKey().asBuilder().setCurrentBulkToken(token.createVKey()).build());
setEppInput(
"domain_renew_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVEDOMAIN__"));
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVE_BULK_PRICING__"));
doSuccessfulTest(
"domain_renew_response.xml",
@@ -1347,7 +1349,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
}
@Test
void testDryRunRemoveDomainToken() throws Exception {
void testDryRunRemoveBulkPricingToken() throws Exception {
AllocationToken token =
persistResource(
new AllocationToken.Builder()
@@ -1364,7 +1366,7 @@ class DomainRenewFlowTest extends ResourceFlowTestCase<DomainRenewFlow, Domain>
setEppInput(
"domain_renew_allocationtoken.xml",
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVEDOMAIN__"));
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2", "TOKEN", "__REMOVE_BULK_PRICING__"));
dryRunFlowAssertResponse(
loadFile(

View File

@@ -0,0 +1,119 @@
// Copyright 2023 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.transaction;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.persistence.transaction.DatabaseException.getSqlError;
import static google.registry.persistence.transaction.DatabaseException.getSqlExceptionDetails;
import static google.registry.persistence.transaction.DatabaseException.tryWrapAndThrow;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.sql.SQLException;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link DatabaseException}. */
public class DatabaseExceptionTest {
@Test
void getSqlError_singleNonSqlException() {
assertThat(getSqlError(new Exception())).isEmpty();
}
@Test
void getSqlExceptionDetails_chainedNoSqlExceptions() {
assertThat(getSqlError(new Exception(new Exception()))).isEmpty();
}
@Test
void getSqlError_sqlExceptionNoDetails() {
assertThat(getSqlError(new java.sql.SQLException())).isEmpty();
}
@Test
void getSqlError_sqlExceptionWithSqlState() {
assertThat(getSqlError(new java.sql.SQLException("msg", "state")))
.contains("\tSQL Error: 0, SQLState: state, message: msg.");
}
@Test
void getSqlError_sqlExceptionWithAllDetails() {
assertThat(getSqlError(new java.sql.SQLException("msg", "state", 1)))
.contains("\tSQL Error: 1, SQLState: state, message: msg.");
}
@Test
void getSqlError_chainedSqlExceptionWithAllDetails() {
SQLException sqlException = new java.sql.SQLException("msg", "state", 1);
assertThat(getSqlError(new Exception("not-captured", sqlException)))
.contains("\tSQL Error: 1, SQLState: state, message: msg.");
}
@Test
void getSqlError_multipleChainedSqlExceptionWithAllDetails() {
SQLException lower = new java.sql.SQLException("lower", "lower-state", 1);
SQLException higher =
new java.sql.SQLException("higher", "higher-state", 2, new Exception(lower));
assertThat(getSqlError(new Exception(higher)))
.contains(
"\tSQL Error: 2, SQLState: higher-state, message: higher.\n"
+ "\tSQL Error: 1, SQLState: lower-state, message: lower.");
}
@Test
void getSqlExceptionDetails_singleNoDetails() {
assertThat(getSqlExceptionDetails(new SQLException())).isEmpty();
}
@Test
void getSqlExceptionDetails_singleWithDetails() {
assertThat(getSqlExceptionDetails(new SQLException("msg", "state", 1)))
.hasValue("\tSQL Error: 1, SQLState: state, message: msg.");
}
@Test
void getSqlExceptionDetails_multipleWithDetails() {
SQLException first = new SQLException("msg", "state", 1);
first.setNextException(new SQLException("msg2", "state2", 2));
assertThat(getSqlExceptionDetails(first))
.hasValue(
"\tSQL Error: 1, SQLState: state, message: msg.\n"
+ "\tSQL Error: 2, SQLState: state2, message: msg2.");
}
@Test
void tryWrapAndThrow_notSQLException() {
RuntimeException orig = new RuntimeException(new Exception());
tryWrapAndThrow(orig);
}
@Test
void tryWrapAndThrow_hasSQLException() {
Throwable orig = new Throwable(new SQLException());
assertThrows(DatabaseException.class, () -> tryWrapAndThrow(orig));
}
@Test
void getMessage_cachedMessageReused() {
SQLException sqlException = mock(SQLException.class);
DatabaseException databaseException = new DatabaseException(sqlException);
databaseException.getMessage();
databaseException.getMessage();
verify(sqlException, times(1)).getCause();
}
}

View File

@@ -0,0 +1,160 @@
// Copyright 2023 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.transaction;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.logging.Logger.getLogger;
import com.google.common.testing.TestLogHandler;
import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.Logger;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/**
* Verifies that specific {@code ERROR}-level logging by Hibernate does not appear in the log files.
*
* <p>Please refer to the class javadoc of {@link DatabaseException} for more information.
*/
public class HibernateLoggingSuppressionTest {
private static final String LOG_SUPPRESSION_TARGET =
"org.hibernate.engine.jdbc.spi.SqlExceptionHelper";
// The line that should be added to the `logging.properties` file.
private static final String LOGGING_PROPERTIES_LINE = LOG_SUPPRESSION_TARGET + ".level=OFF\n";
@RegisterExtension
public final JpaUnitTestExtension jpa =
new JpaTestExtensions.Builder()
.withoutCannedData()
.withEntityClass(TestEntity.class)
.buildUnitTestExtension();
private Logger logger;
private TestLogHandler testLogHandler;
@BeforeEach
void setup() {
testLogHandler = new TestLogHandler();
logger = getLogger(LOG_SUPPRESSION_TARGET);
logger.addHandler(testLogHandler);
}
@AfterEach
void teardown() {
logger.removeHandler(testLogHandler);
}
// Updates logging configs to suppress logging. Call `revertSuppressionOfHibernateLogs` to revert.
void suppressHibernateLogs() throws IOException {
try (ByteArrayInputStream additionalProperties =
new ByteArrayInputStream(LOGGING_PROPERTIES_LINE.getBytes(UTF_8))) {
LogManager.getLogManager()
.updateConfiguration(
additionalProperties,
x ->
(o, n) -> {
if (!x.startsWith(LOG_SUPPRESSION_TARGET)) {
return o;
}
checkArgument(o == null, "Cannot override old value in this test");
return n;
});
}
}
void revertSuppressionOfHibernateLogs() throws IOException {
try (ByteArrayInputStream additionalProperties =
new ByteArrayInputStream(LOGGING_PROPERTIES_LINE.getBytes(UTF_8))) {
LogManager.getLogManager()
.updateConfiguration(
additionalProperties,
x ->
(o, n) -> {
if (!x.startsWith(LOG_SUPPRESSION_TARGET)) {
return o;
}
return null;
});
}
}
@Test
void noLoggingSuppression() {
try {
tm().transact(() -> tm().insert(new TestEntity(1, 1)));
tm().transact(() -> tm().insert(new TestEntity(1, 1)));
} catch (DatabaseException e) {
assertThat(e).hasMessageThat().contains("SQLState: ");
}
assertThat(
testLogHandler.getStoredLogRecords().stream()
.anyMatch(
logRecord ->
logRecord.getLevel().equals(Level.SEVERE)
&& logRecord.getMessage().contains("duplicate key")))
.isTrue();
}
@Test
void withLoggingSuppression() throws Exception {
suppressHibernateLogs();
try {
tm().transact(() -> tm().insert(new TestEntity(1, 1)));
tm().transact(() -> tm().insert(new TestEntity(1, 1)));
} catch (DatabaseException e) {
assertThat(e).hasMessageThat().contains("SQLState: ");
}
assertThat(
testLogHandler.getStoredLogRecords().stream()
.anyMatch(
logRecord ->
logRecord.getLevel().equals(Level.SEVERE)
&& logRecord.getMessage().contains("duplicate key")))
.isFalse();
revertSuppressionOfHibernateLogs();
}
@Entity
static class TestEntity {
@Id long id;
int value;
// For Hibernate
TestEntity() {}
TestEntity(long id, int value) {
this.id = id;
this.value = value;
}
TestEntity incValue() {
this.value++;
return this;
}
}
}

View File

@@ -64,8 +64,9 @@ public class JpaTransactionManagerExtensionTest {
TestEntity testEntity = new TestEntity("foo", "bar");
assertThat(
assertThrows(
PersistenceException.class,
() -> replicaTm().transact(() -> replicaTm().put(testEntity))))
PersistenceException.class,
() -> replicaTm().transact(() -> replicaTm().put(testEntity)))
.getCause())
.hasMessageThat()
.isEqualTo("Error while committing the transaction");
}

View File

@@ -49,6 +49,7 @@ import javax.persistence.EntityManager;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.OptimisticLockException;
import javax.persistence.PersistenceException;
import javax.persistence.RollbackException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
@@ -353,7 +354,11 @@ class JpaTransactionManagerImplTest {
tm().transact(() -> tm().insert(theEntity));
assertThat(existsInDb(theEntity)).isTrue();
assertThat(loadByKey(theEntityKey)).isEqualTo(theEntity);
assertThrows(RollbackException.class, () -> tm().transact(() -> tm().insert(theEntity)));
assertThat(
assertThrows(
PersistenceException.class, () -> tm().transact(() -> tm().insert(theEntity)))
.getCause())
.isInstanceOf(RollbackException.class);
}
@Test
@@ -389,7 +394,8 @@ class JpaTransactionManagerImplTest {
void saveAllNew_rollsBackWhenFailure() {
moreEntities.forEach(entity -> assertThat(tm().transact(() -> tm().exists(entity))).isFalse());
insertInDb(moreEntities.get(0));
assertThrows(RollbackException.class, () -> insertInDb(moreEntities));
assertThat(assertThrows(PersistenceException.class, () -> insertInDb(moreEntities)).getCause())
.isInstanceOf(RollbackException.class);
assertThat(tm().transact(() -> tm().exists(moreEntities.get(0)))).isTrue();
assertThat(tm().transact(() -> tm().exists(moreEntities.get(1)))).isFalse();
assertThat(tm().transact(() -> tm().exists(moreEntities.get(2)))).isFalse();

View File

@@ -0,0 +1,59 @@
// Copyright 2023 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.rde;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.common.Cursor.CursorType.RDE_STAGING;
import static google.registry.model.rde.RdeMode.FULL;
import static google.registry.util.SafeSerializationUtils.safeDeserialize;
import static google.registry.util.SerializeUtils.deserialize;
import static google.registry.util.SerializeUtils.serialize;
import org.joda.time.DateTime;
import org.joda.time.Duration;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link PendingDeposit}. */
public class PendingDepositTest {
private final DateTime now = DateTime.parse("2000-01-01TZ");
PendingDeposit pendingDeposit =
PendingDeposit.create("soy", now, FULL, RDE_STAGING, Duration.standardDays(1));
PendingDeposit manualPendingDeposit =
PendingDeposit.createInManualOperation("soy", now, FULL, "/", null);
@Test
void deserialize_normalDeposit_success() {
assertThat(deserialize(PendingDeposit.class, serialize(pendingDeposit)))
.isEqualTo(pendingDeposit);
}
@Test
void deserialize_manualDeposit_success() {
assertThat(deserialize(PendingDeposit.class, serialize(manualPendingDeposit)))
.isEqualTo(manualPendingDeposit);
}
@Test
void safeDeserialize_normalDeposit_success() {
assertThat(safeDeserialize(serialize(pendingDeposit))).isEqualTo(pendingDeposit);
}
@Test
void safeDeserialize_manualDeposit_success() {
assertThat(safeDeserialize(serialize(manualPendingDeposit))).isEqualTo(manualPendingDeposit);
}
}

View File

@@ -198,7 +198,7 @@ public abstract class CommandTestCase<C extends Command> {
}
void assertInStderr(String... expected) {
String stderror = new String(stderr.toByteArray(), UTF_8);
String stderror = getStderrAsString();
for (String line : expected) {
assertThat(stderror).contains(line);
}

View File

@@ -0,0 +1,573 @@
// Copyright 2023 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.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EntityYamlUtils.createObjectMapper;
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistPremiumList;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.LogsSubject.assertAboutLogs;
import static google.registry.testing.TestDataHelper.loadFile;
import static google.registry.tldconfig.idn.IdnTableEnum.EXTENDED_LATIN;
import static google.registry.tldconfig.idn.IdnTableEnum.JA;
import static google.registry.tldconfig.idn.IdnTableEnum.UNCONFUSABLE_LATIN;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.logging.Level.INFO;
import static org.joda.money.CurrencyUnit.JPY;
import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.exc.InvalidFormatException;
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException;
import com.google.common.base.Ascii;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.io.Files;
import com.google.common.testing.TestLogHandler;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.tld.Tld;
import google.registry.model.tld.label.PremiumList;
import google.registry.model.tld.label.PremiumListDao;
import java.io.File;
import java.util.logging.Logger;
import org.joda.money.Money;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.testcontainers.shaded.com.google.common.collect.ImmutableMap;
/** Unit tests for {@link ConfigureTldCommand} */
public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand> {
PremiumList premiumList;
ObjectMapper objectMapper = createObjectMapper();
private final TestLogHandler logHandler = new TestLogHandler();
private final Logger logger = Logger.getLogger(ConfigureTldCommand.class.getCanonicalName());
@BeforeEach
void beforeEach() {
command.mapper = objectMapper;
premiumList = persistPremiumList("test", USD, "silver,USD 50", "gold,USD 80");
command.validDnsWriterNames = ImmutableSet.of("VoidDnsWriter", "FooDnsWriter");
logger.addHandler(logHandler);
}
private void testTldConfiguredSuccessfully(Tld tld, String filename)
throws JsonProcessingException {
String yaml = objectMapper.writeValueAsString(tld);
assertThat(yaml).isEqualTo(loadFile(getClass(), filename));
}
@Test
void testSuccess_createNewTld() throws Exception {
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile);
Tld tld = Tld.get("tld");
assertThat(tld).isNotNull();
assertThat(tld.getDriveFolderId()).isEqualTo("driveFolder");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
testTldConfiguredSuccessfully(tld, "tld.yaml");
assertThat(tld.getBreakglassMode()).isFalse();
}
@Test
void testSuccess_updateTld() throws Exception {
Tld tld = createTld("tld");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 13));
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
assertThat(updatedTld.getBreakglassMode()).isFalse();
}
@Test
void testSuccess_noDiff() throws Exception {
Tld tld = createTld("idns");
persistResource(
tld.asBuilder()
.setIdnTables(ImmutableSet.of(JA, UNCONFUSABLE_LATIN, EXTENDED_LATIN))
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("zeta", "alpha", "gamma", "beta"))
.build());
File tldFile = tmpDir.resolve("idns.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "idns.yaml"));
runCommandForced("--input=" + tldFile);
assertAboutLogs()
.that(logHandler)
.hasLogAtLevelWithMessage(INFO, "TLD YAML file contains no new changes");
}
@Test
void testSuccess_outOfOrderFieldsOnCreate() throws Exception {
File tldFile = tmpDir.resolve("outoforderfields.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "outoforderfields.yaml"));
runCommandForced("--input=" + tldFile);
Tld tld = Tld.get("outoforderfields");
// Cannot test that created TLD converted to YAML is equal to original YAML since the created
// TLD's YAML will contain the fields in the correct order
assertThat(tld).isNotNull();
assertThat(tld.getDriveFolderId()).isEqualTo("driveFolder");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
assertThat(tld.getPremiumListName().get()).isEqualTo("test");
}
@Test
void testSuccess_outOfOrderFieldsOnUpdate() throws Exception {
Tld tld = createTld("outoforderfields");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 13));
File tldFile = tmpDir.resolve("outoforderfields.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "outoforderfields.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("outoforderfields");
// Cannot test that created TLD converted to YAML is equal to original YAML since the created
// TLD's YAML will contain the fields in the correct order
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
}
@Test
void testFailure_fileMissingNullableFieldsOnCreate() throws Exception {
File tldFile = tmpDir.resolve("missingnullablefields.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "missingnullablefields.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"The input file is missing data for the following fields: [tldStateTransitions,"
+ " premiumListName, currency, numDnsPublishLocks]");
}
@Test
void testFailure_fileMissingNullableFieldOnUpdate() throws Exception {
Tld tld = createTld("missingnullablefields");
persistResource(
tld.asBuilder().setNumDnsPublishLocks(5).build()); // numDnsPublishLocks is nullable
File tldFile = tmpDir.resolve("missingnullablefields.yaml").toFile();
Files.asCharSink(tldFile, UTF_8)
.write(
loadFile(
getClass(), "missingnullablefields.yaml")); // file is missing numDnsPublishLocks
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"The input file is missing data for the following fields: [tldStateTransitions,"
+ " premiumListName, currency, numDnsPublishLocks]");
}
@Test
void testSuccess_nullableFieldsAllNullOnCreate() throws Exception {
File tldFile = tmpDir.resolve("nullablefieldsallnull.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "nullablefieldsallnull.yaml"));
runCommandForced("--input=" + tldFile);
Tld tld = Tld.get("nullablefieldsallnull");
assertThat(tld).isNotNull();
assertThat(tld.getDriveFolderId()).isEqualTo(null);
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
// cannot test that created TLD converted to YAML is equal to original YAML since the created
// TLD's YAML will contain empty sets for some of the null fields
assertThat(tld.getIdnTables()).isEmpty();
assertThat(tld.getDefaultPromoTokens()).isEmpty();
}
@Test
void testSuccess_nullableFieldsAllNullOnUpdate() throws Exception {
Tld tld = createTld("nullablefieldsallnull");
persistResource(
tld.asBuilder().setIdnTables(ImmutableSet.of(JA)).setDriveFolderId("drive").build());
File tldFile = tmpDir.resolve("nullablefieldsallnull.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "nullablefieldsallnull.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("nullablefieldsallnull");
assertThat(updatedTld).isNotNull();
assertThat(updatedTld.getDriveFolderId()).isEqualTo(null);
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
// cannot test that created TLD converted to YAML is equal to original YAML since the created
// TLD's YAML will contain empty sets for some of the null fields
assertThat(updatedTld.getIdnTables()).isEmpty();
assertThat(updatedTld.getDefaultPromoTokens()).isEmpty();
}
@Test
void testFailure_fileContainsExtraFields() throws Exception {
File tldFile = tmpDir.resolve("extrafield.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "extrafield.yaml"));
assertThrows(UnrecognizedPropertyException.class, () -> runCommandForced("--input=" + tldFile));
}
@Test
void testFailure_fileNameDoesNotMatchTldName() throws Exception {
File tldFile = tmpDir.resolve("othertld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo("The input file name must match the name of the TLD it represents");
}
@Test
void testFailure_tldUnicodeDoesNotMatch() throws Exception {
File tldFile = tmpDir.resolve("badunicode.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "badunicode.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"The value for tldUnicode must equal the unicode representation of the TLD name");
}
@Test
void testFailure_tldUpperCase() throws Exception {
String name = "TLD";
File tldFile = tmpDir.resolve("TLD.yaml").toFile();
Files.asCharSink(tldFile, UTF_8)
.write(
loadFile(
getClass(),
"wildcard.yaml",
ImmutableMap.of(
"TLDSTR", name, "TLDUNICODE", name, "ROIDSUFFIX", Ascii.toUpperCase(name))));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"The value for tldUnicode must equal the unicode representation of the TLD name");
}
@Test
void testSuccess_asciiNameWithOptionalPunycode() throws Exception {
String name = "xn--q9jyb4c";
File tldFile = tmpDir.resolve(name + ".yaml").toFile();
String fileContents =
loadFile(
getClass(),
"wildcard.yaml",
ImmutableMap.of(
"TLDSTR",
"\"" + name + "\"",
"TLDUNICODE",
"\"みんな\"",
"ROIDSUFFIX",
"\"Q9JYB4C\""));
Files.asCharSink(tldFile, UTF_8).write(fileContents);
runCommandForced("--input=" + tldFile);
Tld tld = Tld.get(name);
assertThat(tld).isNotNull();
assertThat(tld.getDriveFolderId()).isEqualTo("driveFolder");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
String yaml = objectMapper.writeValueAsString(tld);
assertThat(yaml).isEqualTo(fileContents);
}
@Test
void testFailure_punycodeDoesNotMatch() throws Exception {
String name = "xn--q9jyb4c";
File tldFile = tmpDir.resolve(name + ".yaml").toFile();
String fileContents =
loadFile(
getClass(),
"wildcard.yaml",
ImmutableMap.of(
"TLDSTR",
"\"" + name + "\"",
"TLDUNICODE",
"\"yoyo\"",
"ROIDSUFFIX",
"\"Q9JYB4C\""));
Files.asCharSink(tldFile, UTF_8).write(fileContents);
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"The value for tldUnicode must equal the unicode representation of the TLD name");
}
@Test
@Disabled
void testFailure_pzunycodeName() throws Exception {
String name = "みんな";
File tldFile = tmpDir.resolve(name + ".yaml").toFile();
String fileContents =
loadFile(
getClass(),
"wildcard.yaml",
ImmutableMap.of(
"TLDSTR",
"\"" + name + "\"",
"TLDUNICODE",
"\"みんな\"",
"ROIDSUFFIX",
"\"Q9JYB4C\""));
Files.asCharSink(tldFile, UTF_8).write(fileContents);
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage()).isEqualTo("A TLD name must be in plain ASCII");
}
@Test
void testFailure_invalidRoidSuffix() throws Exception {
String name = "tld";
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8)
.write(
loadFile(
getClass(),
"wildcard.yaml",
ImmutableMap.of(
"TLDSTR", name, "TLDUNICODE", name, "ROIDSUFFIX", "TLLLLLLLLLLLLLLLLLLLLLLD")));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage()).isEqualTo("ROID suffix must be in format ^[A-Z\\d_]{1,8}$");
}
@Test
void testFailure_invalidIdnTable() throws Exception {
File tldFile = tmpDir.resolve("badidn.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "badidn.yaml"));
assertThrows(InvalidFormatException.class, () -> runCommandForced("--input=" + tldFile));
}
@Test
void testFailure_tldNameStartsWithNumber() throws Exception {
File tldFile = tmpDir.resolve("1tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "1tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage()).isEqualTo("TLDs cannot begin with a number");
}
@Test
void testFailure_invalidDnsWriter() throws Exception {
command.validDnsWriterNames = ImmutableSet.of("foo");
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo("Invalid DNS writer name(s) specified: [VoidDnsWriter]");
}
@Test
void testFailure_mismatchedCurrencyUnitsOnCreate() throws Exception {
File tldFile = tmpDir.resolve("wrongcurrency.yaml").toFile();
Files.asCharSink(tldFile, UTF_8)
.write(
loadFile(
getClass(),
"wrongcurrency.yaml",
ImmutableMap.of("RESTORECURRENCY", "EUR", "RENEWCURRENCY", "USD")));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo("restoreBillingCost must use the same currency as the TLD");
File tldFile2 = tmpDir.resolve("wrongcurrency.yaml").toFile();
Files.asCharSink(tldFile2, UTF_8)
.write(
loadFile(
getClass(),
"wrongcurrency.yaml",
ImmutableMap.of("RESTORECURRENCY", "USD", "RENEWCURRENCY", "EUR")));
thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile2));
assertThat(thrown.getMessage())
.isEqualTo(
"All Money values in the renewBillingCostTransitions map must use the TLD's currency"
+ " unit");
}
@Test
void testFailure_mismatchedCurrencyUnitsOnUpdate() throws Exception {
createTld("wrongcurreency");
File tldFile = tmpDir.resolve("wrongcurrency.yaml").toFile();
Files.asCharSink(tldFile, UTF_8)
.write(
loadFile(
getClass(),
"wrongcurrency.yaml",
ImmutableMap.of("RESTORECURRENCY", "EUR", "RENEWCURRENCY", "USD")));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo("restoreBillingCost must use the same currency as the TLD");
File tldFile2 = tmpDir.resolve("wrongcurrency.yaml").toFile();
Files.asCharSink(tldFile2, UTF_8)
.write(
loadFile(
getClass(),
"wrongcurrency.yaml",
ImmutableMap.of("RESTORECURRENCY", "USD", "RENEWCURRENCY", "EUR")));
thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile2));
assertThat(thrown.getMessage())
.isEqualTo(
"All Money values in the renewBillingCostTransitions map must use the TLD's currency"
+ " unit");
}
@Test
void testSuccess_emptyStringClearsDefaultPromoTokens() throws Exception {
Tld tld = createTld("tld");
AllocationToken defaultToken =
persistResource(
new AllocationToken.Builder()
.setToken("bbbbb")
.setTokenType(DEFAULT_PROMO)
.setAllowedTlds(ImmutableSet.of("tld"))
.build());
persistResource(
tld.asBuilder().setDefaultPromoTokens(ImmutableList.of(defaultToken.createVKey())).build());
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getDefaultPromoTokens()).isEmpty();
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
}
@Test
void testSuccess_emptyStringClearsIdnTables() throws Exception {
Tld tld = createTld("tld");
persistResource(tld.asBuilder().setIdnTables(ImmutableSet.of(EXTENDED_LATIN, JA)).build());
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getIdnTables()).isEmpty();
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
}
@Test
void testFailure_premiumListDoesNotExist() throws Exception {
PremiumListDao.delete(premiumList);
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage()).isEqualTo("The premium list with the name test does not exist");
}
@Test
void testFailure_premiumListWrongCurrency() throws Exception {
PremiumListDao.delete(premiumList);
persistPremiumList("test", JPY, "bronze,JPY 80");
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage()).isEqualTo("The premium list must use the TLD's currency");
}
@Test
void testFailure_breakglassFlag_NoChanges() throws Exception {
Tld tld = createTld("idns");
persistResource(
tld.asBuilder()
.setIdnTables(ImmutableSet.of(JA, UNCONFUSABLE_LATIN, EXTENDED_LATIN))
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("zeta", "alpha", "gamma", "beta"))
.build());
File tldFile = tmpDir.resolve("idns.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "idns.yaml"));
IllegalArgumentException thrown =
assertThrows(
IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile, "-b"));
assertThat(thrown.getMessage())
.isEqualTo(
"Breakglass mode can only be set when making new changes to a TLD configuration");
}
@Test
void testSuccess_breakglassFlag_startsBreakglassMode() throws Exception {
Tld tld = createTld("tld");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 13));
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile, "--breakglass");
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
assertThat(updatedTld.getBreakglassMode()).isTrue();
}
@Test
void testSuccess_breakglassFlag_continuesBreakglassMode() throws Exception {
Tld tld = createTld("tld");
assertThat(tld.getCreateBillingCost()).isEqualTo(Money.of(USD, 13));
persistResource(tld.asBuilder().setBreakglassMode(true).build());
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile, "--breakglass");
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
assertThat(updatedTld.getBreakglassMode()).isTrue();
}
@Test
void testSuccess_NoDiffNoBreakglassFlag_endsBreakglassMode() throws Exception {
Tld tld = createTld("idns");
persistResource(
tld.asBuilder()
.setIdnTables(ImmutableSet.of(JA, UNCONFUSABLE_LATIN, EXTENDED_LATIN))
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("zeta", "alpha", "gamma", "beta"))
.setBreakglassMode(true)
.build());
File tldFile = tmpDir.resolve("idns.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "idns.yaml"));
runCommandForced("--input=" + tldFile);
Tld updatedTld = Tld.get("idns");
assertThat(updatedTld.getBreakglassMode()).isFalse();
assertAboutLogs()
.that(logHandler)
.hasLogAtLevelWithMessage(INFO, "Breakglass mode removed from TLD: idns");
}
@Test
void testSuccess_noDiffBreakglassFlag_continuesBreakglassMode() throws Exception {
Tld tld = createTld("idns");
persistResource(
tld.asBuilder()
.setIdnTables(ImmutableSet.of(JA, UNCONFUSABLE_LATIN, EXTENDED_LATIN))
.setAllowedFullyQualifiedHostNames(ImmutableSet.of("zeta", "alpha", "gamma", "beta"))
.setBreakglassMode(true)
.build());
File tldFile = tmpDir.resolve("idns.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "idns.yaml"));
runCommandForced("--input=" + tldFile, "-b");
Tld updatedTld = Tld.get("idns");
assertThat(updatedTld.getBreakglassMode()).isTrue();
assertAboutLogs()
.that(logHandler)
.hasLogAtLevelWithMessage(INFO, "TLD YAML file contains no new changes");
}
@Test
void testFailure_noBreakglassFlag_inBreakglassMode() throws Exception {
Tld tld = createTld("tld");
persistResource(tld.asBuilder().setBreakglassMode(true).build());
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
IllegalArgumentException thrown =
assertThrows(IllegalArgumentException.class, () -> runCommandForced("--input=" + tldFile));
assertThat(thrown.getMessage())
.isEqualTo(
"Changes can not be applied since TLD is in breakglass mode but the breakglass flag"
+ " was not used");
}
}

View File

@@ -38,6 +38,7 @@ class CreateDomainCommandTest extends EppToolCommandTestCase<CreateDomainCommand
@BeforeEach
void beforeEach() {
command.passwordGenerator = new DeterministicStringGenerator("abcdefghijklmnopqrstuvwxyz");
command.printStream = System.out;
}
@Test

View File

@@ -68,6 +68,7 @@ class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand>
2048,
ImmutableSet.of("secp256r1", "secp384r1"),
fakeClock);
command.printStream = System.out;
}
@Test

View File

@@ -37,6 +37,7 @@ class CreateRegistrarGroupsCommandTest extends CommandTestCase<CreateRegistrarGr
@Test
void test_createGroupsForTwoRegistrars() throws Exception {
command.printStream = System.out;
runCommandForced("NewRegistrar", "TheRegistrar");
verify(connection)
.sendPostRequest(

View File

@@ -521,6 +521,7 @@ class CreateTldCommandTest extends CommandTestCase<CreateTldCommand> {
@Test
void testSuccess_setCommonAndReservedListFromOtherTld_withOverride() throws Exception {
command.errorPrintStream = System.err;
runReservedListsTestOverride("common_abuse,tld_banned");
String errMsg =
"Error overridden: The reserved list(s) tld_banned "
@@ -632,7 +633,7 @@ class CreateTldCommandTest extends CommandTestCase<CreateTldCommand> {
"xn--q9jyb4c", "--roid_suffix=Q9JYB4C", "--dns_writers=Invalid,Deadbeef"));
assertThat(thrown)
.hasMessageThat()
.contains("Invalid DNS writer name(s) specified: [Deadbeef, Invalid]");
.contains("Invalid DNS writer name(s) specified: [Invalid, Deadbeef]");
}
@Test

View File

@@ -53,6 +53,7 @@ class DeleteAllocationTokensCommandTest extends CommandTestCase<DeleteAllocation
preNot2 = persistToken("prefix8ZZZhs8", null, false);
othrRed = persistToken("h97987sasdfhh", null, true);
othrNot = persistToken("asdgfho7HASDS", null, false);
command.printStream = System.out;
}
@Test

View File

@@ -16,11 +16,18 @@ package google.registry.tools;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.persistPremiumList;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.TestDataHelper.loadFile;
import static org.joda.money.CurrencyUnit.USD;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.EntityYamlUtils;
import google.registry.model.tld.Tld;
import google.registry.model.tld.label.PremiumList;
import org.joda.money.Money;
import org.joda.time.Duration;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -34,8 +41,16 @@ class GetTldCommandTest extends CommandTestCase<GetTldCommand> {
@Test
void testSuccess() throws Exception {
createTld("xn--q9jyb4c");
runCommand("xn--q9jyb4c");
Tld tld = createTld("tld");
PremiumList premiumList = persistPremiumList("test", USD, "silver,USD 50", "gold,USD 80");
persistResource(
tld.asBuilder()
.setDnsAPlusAaaaTtl(Duration.millis(900))
.setDriveFolderId("driveFolder")
.setCreateBillingCost(Money.of(USD, 25))
.setPremiumList(premiumList)
.build());
runCommand("tld");
assertInStdout(loadFile(getClass(), "tld.yaml"));
}

View File

@@ -37,6 +37,8 @@ class LoadTestCommandTest extends CommandTestCase<LoadTestCommand> {
command.setConnection(connection);
createTld("example");
persistNewRegistrar("acme", "ACME", Registrar.Type.REAL, 99L);
command.printStream = System.out;
command.errorPrintStream = System.err;
}
@Test

View File

@@ -50,6 +50,7 @@ class LockDomainCommandTest extends CommandTestCase<LockDomainCommand> {
new DeterministicStringGenerator(Alphabets.BASE_58),
"adminreg",
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
command.printStream = System.out;
}
@Test

View File

@@ -61,6 +61,7 @@ class UniformRapidSuspensionCommandTest
ImmutableSet.of(
DomainDsData.create(1, 2, 3, new HexBinaryAdapter().unmarshal("dead")),
DomainDsData.create(4, 5, 6, new HexBinaryAdapter().unmarshal("beef")));
command.printStream = System.out;
}
private void persistDomainWithHosts(

View File

@@ -53,6 +53,7 @@ class UnlockDomainCommandTest extends CommandTestCase<UnlockDomainCommand> {
new DeterministicStringGenerator(Alphabets.BASE_58),
"adminreg",
new CloudTasksHelper(fakeClock).getTestCloudTasksUtils());
command.printStream = System.out;
}
private Domain persistLockedDomain(String domainName, String registrarId) {

View File

@@ -55,6 +55,7 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
createTld("tld");
fakeClock.setTo(DateTime.parse("2016-12-06T13:55:01Z"));
command.clock = fakeClock;
command.printStream = System.out;
}
@Test
@@ -178,6 +179,7 @@ public class UnrenewDomainCommandTest extends CommandTestCase<UnrenewDomainComma
@Test
void test_varietyOfInvalidDomains_displaysErrors() {
command.errorPrintStream = System.err;
DateTime now = fakeClock.nowUtc();
persistResource(
DatabaseHelper.newDomain("deleting.tld")

View File

@@ -1048,6 +1048,7 @@ class UpdateTldCommandTest extends CommandTestCase<UpdateTldCommand> {
@Test
void testSuccess_setCommonAndReservedListFromOtherTld_withOverride() throws Exception {
command.errorPrintStream = System.err;
runReservedListsTestOverride("common_abuse,tld_banned");
String errMsg =
"Error overridden: The reserved list(s) tld_banned "

View File

@@ -34,6 +34,7 @@ import google.registry.model.reporting.HistoryEntryDao;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import google.registry.tools.CommandTestCase;
import java.io.PrintStream;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.jupiter.api.BeforeEach;
@@ -59,6 +60,7 @@ public class CreateCancellationsForBillingEventsCommandTest
fakeClock.nowUtc(),
fakeClock.nowUtc().plusYears(2));
billingEventToCancel = createBillingEvent();
command.printStream = System.out;
}
@Test
@@ -97,8 +99,10 @@ public class CreateCancellationsForBillingEventsCommandTest
@Test
void testAlreadyCancelled() throws Exception {
// multiple runs / cancellations should be a no-op
command.printStream = new PrintStream(tmpDir.resolve("test.txt").toFile());
runCommandForced(String.valueOf(billingEventToCancel.getId()));
assertBillingEventCancelled();
command.printStream = System.out;
runCommandForced(String.valueOf(billingEventToCancel.getId()));
assertBillingEventCancelled();
assertThat(DatabaseHelper.loadAllOf(BillingCancellation.class)).hasSize(1);

View File

@@ -0,0 +1,85 @@
// Copyright 2023 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.console;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.Mockito.mock;
import com.google.api.client.http.HttpStatusCodes;
import com.google.gson.Gson;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.RequestModule;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthSettings.AuthLevel;
import google.registry.request.auth.UserAuthInfo;
import google.registry.testing.FakeResponse;
import java.io.IOException;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;
/** Tests for {@link google.registry.ui.server.console.ConsoleUserDataAction}. */
class ConsoleUserDataActionTest {
private final HttpServletRequest request = mock(HttpServletRequest.class);
private RegistrarPoc testRegistrarPoc;
private static final Gson GSON = RequestModule.provideGson();
private FakeResponse response = new FakeResponse();
@RegisterExtension
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
@Test
void testSuccess_getContactInfo() throws IOException {
User user =
new User.Builder()
.setEmailAddress("email@email.com")
.setGaiaId("gaiaId")
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
.build();
ConsoleUserDataAction action =
createAction(AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user)));
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
Map jsonObject = GSON.fromJson(response.getPayload(), Map.class);
assertThat(jsonObject)
.containsExactly("isAdmin", false, "technicalDocsUrl", "test", "globalRole", "FTE");
}
@Test
void testFailure_notAConsoleUser() throws IOException {
ConsoleUserDataAction action =
createAction(
AuthResult.create(
AuthLevel.USER,
UserAuthInfo.create(
new com.google.appengine.api.users.User(
"JohnDoe@theregistrar.com", "theregistrar.com"),
false)));
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
}
private ConsoleUserDataAction createAction(AuthResult authResult) throws IOException {
return new ConsoleUserDataAction(authResult, response, "test");
}
}

View File

@@ -1,56 +0,0 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.xjc;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.TestDataHelper.loadFile;
import static java.nio.charset.StandardCharsets.UTF_8;
import google.registry.xjc.rdehost.XjcRdeHostElement;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link JaxbFragment}. */
class JaxbFragmentTest {
private static final String HOST_FRAGMENT = loadFile(XjcObjectTest.class, "host_fragment.xml");
/** Verifies that a {@link JaxbFragment} can be serialized and deserialized successfully. */
@SuppressWarnings("unchecked")
@Test
void testJavaSerialization() throws Exception {
// Load rdeHost xml fragment into a jaxb object, wrap it, marshal, unmarshal, verify host.
// The resulting host name should be "ns1.example1.test", from the original xml fragment.
try (InputStream source = new ByteArrayInputStream(HOST_FRAGMENT.getBytes(UTF_8))) {
// Load xml
JaxbFragment<XjcRdeHostElement> hostFragment =
JaxbFragment.create(XjcXmlTransformer.unmarshal(XjcRdeHostElement.class, source));
// Marshal
ByteArrayOutputStream bout = new ByteArrayOutputStream();
new ObjectOutputStream(bout).writeObject(hostFragment);
// Unmarshal
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
JaxbFragment<XjcRdeHostElement> restoredHostFragment =
(JaxbFragment<XjcRdeHostElement>) in.readObject();
// Verify host name
assertThat(restoredHostFragment.getInstance().getValue().getName())
.isEqualTo("ns1.example1.test");
}
}
}

View File

@@ -18,8 +18,8 @@ dnsDsTtl: null
dnsNsTtl: null
dnsPaused: false
dnsWriters:
- "baz"
- "bang"
- "baz"
driveFolderId: null
eapFeeSchedule:
"1970-01-01T00:00:00.000Z":
@@ -33,8 +33,8 @@ eapFeeSchedule:
amount: 0.00
escrowEnabled: false
idnTables:
- "JA"
- "EXTENDED_LATIN"
- "JA"
invoicingEnabled: false
lordnUsername: null
numDnsPublishLocks: 1

View File

@@ -5,6 +5,7 @@ PATH CLASS METHODS OK AUT
/console-api/settings/contacts ContactAction GET,POST n API,LEGACY USER PUBLIC
/console-api/settings/security SecurityAction POST n API,LEGACY USER PUBLIC
/console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n API,LEGACY USER PUBLIC
/console-api/userdata ConsoleUserDataAction GET n API,LEGACY USER PUBLIC
/registrar ConsoleUiAction GET n API,LEGACY NONE PUBLIC
/registrar-create ConsoleRegistrarCreatorAction POST,GET n API,LEGACY NONE PUBLIC
/registrar-ote-setup ConsoleOteSetupAction POST,GET n API,LEGACY NONE PUBLIC

View File

@@ -0,0 +1,55 @@
addGracePeriodLength: 432000000
allowedFullyQualifiedHostNames: []
allowedRegistrantContactIds: []
anchorTenantAddGracePeriodLength: 2592000000
autoRenewGracePeriodLength: 3888000000
automaticTransferLength: 432000000
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
createBillingCost:
currency: "USD"
amount: 25.00
creationTime: "2022-09-01T00:00:00.000Z"
currency: "USD"
defaultPromoTokens: []
dnsAPlusAaaaTtl: 900
dnsDsTtl: null
dnsNsTtl: null
dnsPaused: false
dnsWriters:
- "VoidDnsWriter"
driveFolderId: "driveFolder"
eapFeeSchedule:
"1970-01-01T00:00:00.000Z":
currency: "USD"
amount: 0.00
escrowEnabled: false
idnTables: []
invoicingEnabled: false
lordnUsername: null
numDnsPublishLocks: 1
pendingDeleteLength: 432000000
premiumListName: "test"
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
redemptionGracePeriodLength: 2592000000
registryLockOrUnlockBillingCost:
currency: "USD"
amount: 0.00
renewBillingCostTransitions:
"1970-01-01T00:00:00.000Z":
currency: "USD"
amount: 11.00
renewGracePeriodLength: 432000000
reservedListNames: []
restoreBillingCost:
currency: "USD"
amount: 17.00
roidSuffix: "1TLD"
serverStatusChangeBillingCost:
currency: "USD"
amount: 19.00
tldStateTransitions:
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
tldStr: "1tld"
tldType: "REAL"
tldUnicode: "1tld"
transferGracePeriodLength: 432000000

View File

@@ -0,0 +1,56 @@
addGracePeriodLength: 432000000
allowedFullyQualifiedHostNames: []
allowedRegistrantContactIds: []
anchorTenantAddGracePeriodLength: 2592000000
autoRenewGracePeriodLength: 3888000000
automaticTransferLength: 432000000
claimsPeriodEnd: "294247-01-10T04:00:54.775Z"
createBillingCost:
currency: "USD"
amount: 25.00
creationTime: "2022-09-01T00:00:00.000Z"
currency: "USD"
defaultPromoTokens: []
dnsAPlusAaaaTtl: 900
dnsDsTtl: null
dnsNsTtl: null
dnsPaused: false
dnsWriters:
- "VoidDnsWriter"
driveFolderId: "driveFolder"
eapFeeSchedule:
"1970-01-01T00:00:00.000Z":
currency: "USD"
amount: 0.00
escrowEnabled: false
idnTables:
- "foo"
invoicingEnabled: false
lordnUsername: null
numDnsPublishLocks: 1
pendingDeleteLength: 432000000
premiumListName: "test"
pricingEngineClassName: "google.registry.model.pricing.StaticPremiumListPricingEngine"
redemptionGracePeriodLength: 2592000000
registryLockOrUnlockBillingCost:
currency: "USD"
amount: 0.00
renewBillingCostTransitions:
"1970-01-01T00:00:00.000Z":
currency: "USD"
amount: 11.00
renewGracePeriodLength: 432000000
reservedListNames: []
restoreBillingCost:
currency: "USD"
amount: 17.00
roidSuffix: "BADIDN"
serverStatusChangeBillingCost:
currency: "USD"
amount: 19.00
tldStateTransitions:
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
tldStr: "badidn"
tldType: "REAL"
tldUnicode: "badidn"
transferGracePeriodLength: 432000000

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