1
0
mirror of https://github.com/google/nomulus synced 2026-07-08 09:06:58 +00:00

Compare commits

...

15 Commits

Author SHA1 Message Date
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
Pavlo Tkach 1929654f8c Replace less with scss, add homepage widgets, add registrars selector and registrars page (#2114)
* Replace less compiler with scss

* Replace less with scss, add homepage widgets, add registrars selector and registrars page
2023-09-01 11:48:30 -04:00
119 changed files with 14806 additions and 1776 deletions
+6
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
+2 -2
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")
}
}
}
+4 -4
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
+1 -1
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
+13 -7
View File
@@ -7,7 +7,7 @@
"projectType": "application",
"schematics": {
"@schematics/angular:component": {
"style": "less"
"style": "scss"
}
},
"root": "",
@@ -22,15 +22,18 @@
"main": "src/main.ts",
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"inlineStyleLanguage": "less",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.less"
"src/theme.scss",
"src/styles.scss"
],
"stylePreprocessorOptions": {
"includePaths": ["node_modules/"]
},
"scripts": []
},
"configurations": {
@@ -91,15 +94,18 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"inlineStyleLanguage": "less",
"inlineStyleLanguage": "scss",
"assets": [
"src/favicon.ico",
"src/assets"
],
"styles": [
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.less"
"src/theme.scss",
"src/styles.scss"
],
"stylePreprocessorOptions": {
"includePaths": ["node_modules/"]
},
"scripts": []
}
},
+11061 -383
View File
File diff suppressed because it is too large Load Diff
+10 -5
View File
@@ -18,51 +18,56 @@ import { TldsComponent } from './tlds/tlds.component';
import { HomeComponent } from './home/home.component';
import { SettingsComponent } from './settings/settings.component';
import SettingsContactComponent from './settings/contact/contact.component';
import SettingsRegistrarsComponent from './settings/registrars/registrars.component';
import SettingsWhoisComponent from './settings/whois/whois.component';
import SettingsUsersComponent from './settings/users/users.component';
import SettingsSecurityComponent from './settings/security/security.component';
import { RegistrarGuard } from './registrar/registrar.guard';
import { RegistrarComponent } from './registrar/registrar.component';
import { RegistrarComponent } from './registrar/registrarsTable.component';
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
{ path: 'registrars', component: RegistrarComponent },
{ path: 'empty-registrar', component: EmptyRegistrar },
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
{
path: 'settings',
component: SettingsComponent,
canActivate: [RegistrarGuard],
children: [
{
path: '',
redirectTo: 'contact',
redirectTo: 'registrars',
pathMatch: 'full',
},
{
path: 'contact',
component: SettingsContactComponent,
canActivate: [RegistrarGuard],
},
{
path: 'whois',
component: SettingsWhoisComponent,
canActivate: [RegistrarGuard],
},
{
path: 'security',
component: SettingsSecurityComponent,
canActivate: [RegistrarGuard],
},
{
path: 'epp-password',
component: SettingsSecurityComponent,
canActivate: [RegistrarGuard],
},
{
path: 'users',
component: SettingsUsersComponent,
canActivate: [RegistrarGuard],
},
{
path: 'registrars',
component: SettingsRegistrarsComponent,
component: RegistrarComponent,
},
],
},
+4 -4
View File
@@ -12,13 +12,13 @@
<a mat-list-item [routerLink]="'/settings'" routerLinkActive="active">
Settings
</a>
<a mat-list-item [routerLink]="'/registrars'" routerLinkActive="active">
Select Registrar
</a>
</mat-nav-list>
</mat-sidenav>
<mat-sidenav-content class="console-app__content-wrapper">
<div class="console-app__content">
<div *ngIf="globalLoader.isLoading" class="console-app__global-spinner">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<div class="console-app__content" *ngIf="renderRouter">
<router-outlet></router-outlet>
</div>
</mat-sidenav-content>
@@ -13,8 +13,8 @@
// limitations under the License.
:host {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
font-family: Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
"Segoe UI Emoji", "Segoe UI Symbol" !important;
font-size: 14px;
color: #333;
box-sizing: border-box;
@@ -47,4 +47,7 @@
max-width: 1340px;
margin: 0 auto;
}
&__global-spinner {
margin-bottom: 2rem;
}
}
+17 -2
View File
@@ -13,10 +13,25 @@
// limitations under the License.
import { Component } from '@angular/core';
import { RegistrarService } from './registrar/registrar.service';
import { GlobalLoaderService } from './shared/services/globalLoader.service';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.less'],
styleUrls: ['./app.component.scss'],
})
export class AppComponent {}
export class AppComponent {
renderRouter: boolean = true;
constructor(
protected registrarService: RegistrarService,
protected globalLoader: GlobalLoaderService
) {
registrarService.activeRegistrarIdChange.subscribe(() => {
this.renderRouter = false;
setTimeout(() => {
this.renderRouter = true;
}, 400);
});
}
}
+43 -11
View File
@@ -31,31 +31,63 @@ import SettingsContactComponent, {
ContactDetailsDialogComponent,
} from './settings/contact/contact.component';
import { HttpClientModule } from '@angular/common/http';
import { RegistrarComponent } from './registrar/registrar.component';
import { RegistrarComponent } from './registrar/registrarsTable.component';
import { RegistrarGuard } from './registrar/registrar.guard';
import SecurityComponent from './settings/security/security.component';
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
import { RegistrarSelectorComponent } from './registrar/registrar-selector.component';
import { GlobalLoaderService } from './shared/services/globalLoader.service';
import { ContactWidgetComponent } from './home/widgets/contact-widget.component';
import { PromotionsWidgetComponent } from './home/widgets/promotions-widget.component';
import { TldsWidgetComponent } from './home/widgets/tlds-widget.component';
import { ResourcesWidgetComponent } from './home/widgets/resources-widget.component';
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';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
TldsComponent,
BillingWidgetComponent,
ContactDetailsDialogComponent,
ContactWidgetComponent,
DomainsWidgetComponent,
EmptyRegistrar,
EppWidgetComponent,
HeaderComponent,
HomeComponent,
PromotionsWidgetComponent,
RegistrarComponent,
RegistrarSelectorComponent,
ResourcesWidgetComponent,
SecurityComponent,
SettingsComponent,
SettingsContactComponent,
ContactDetailsDialogComponent,
RegistrarComponent,
SecurityComponent,
SettingsWidgetComponent,
TldsComponent,
TldsWidgetComponent,
],
imports: [
HttpClientModule,
FormsModule,
MaterialModule,
BrowserModule,
AppRoutingModule,
BrowserAnimationsModule,
BrowserModule,
FormsModule,
HttpClientModule,
MaterialModule,
],
providers: [
BackendService,
GlobalLoaderService,
RegistrarGuard,
{
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: {
subscriptSizing: 'dynamic',
},
},
],
providers: [BackendService, RegistrarGuard],
bootstrap: [AppComponent],
})
export class AppModule {}
@@ -3,8 +3,17 @@
<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">
<mat-icon>question_mark</mat-icon>
</button>
@@ -12,6 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
.console-app {
&__logo {
color: inherit;
text-decoration: none;
}
}
.spacer {
flex: 1;
}
@@ -17,7 +17,7 @@ import { Component, EventEmitter, Output } from '@angular/core';
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.less'],
styleUrls: ['./header.component.scss'],
})
export class HeaderComponent {
private isNavOpen = false;
+13 -21
View File
@@ -1,21 +1,13 @@
<h3>Recent Activity</h3>
<table
mat-table
[dataSource]="dataSource"
class="mat-elevation-z8 console-home__activity"
>
<ng-container
*ngFor="let column of columns"
[matColumnDef]="column.columnDef"
>
<th mat-header-cell *matHeaderCellDef>
{{ column.header }}
</th>
<td mat-cell *matCellDef="let row">
{{ column.cell(row) }}
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<div class="console-app__home">
<h1>Welcome to the Google Registry Console</h1>
<div class="console-app__home-widgets">
<div app-domains-widget class="console-app__widget-wrapper__wide"></div>
<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-settings-widget class="console-app__widget-wrapper__wide"></div>
<div app-resources-widget></div>
<div app-billing-widget></div>
<div app-epp-widget></div>
</div>
</div>
@@ -11,3 +11,22 @@
// 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.
.console-app {
&__home {
margin-top: 1rem;
}
&__home-widgets {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
grid-gap: 20px;
grid-auto-flow: dense;
mat-card {
height: 100%;
h1 {
margin-top: 1rem;
}
}
}
}
+4 -212
View File
@@ -12,220 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
import { Component } from '@angular/core';
export interface ActivityRecord {
eventType: string;
userName: string;
registrarName: string;
timestamp: string;
details: string;
}
const MOCK_DATA: ActivityRecord[] = [
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Export DUMS',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Update Contact',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
{
eventType: 'Delete Domain',
userName: 'user3',
registrarName: 'registrar1',
timestamp: '2022-03-15T19:46:39.007',
details: 'All Domains under management exported as .csv file',
},
];
import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.less'],
styleUrls: ['./home.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class HomeComponent {
columns = [
{
columnDef: 'eventType',
header: 'Event Type',
cell: (record: ActivityRecord) => `${record.eventType}`,
},
{
columnDef: 'userName',
header: 'User',
cell: (record: ActivityRecord) => `${record.userName}`,
},
{
columnDef: 'registrarName',
header: 'Registrar',
cell: (record: ActivityRecord) => `${record.registrarName}`,
},
{
columnDef: 'timestamp',
header: 'Timestamp',
cell: (record: ActivityRecord) => `${record.timestamp}`,
},
{
columnDef: 'details',
header: 'Details',
cell: (record: ActivityRecord) => `${record.details}`,
},
];
dataSource = MOCK_DATA;
displayedColumns = this.columns.map((c) => c.columnDef);
}
export class HomeComponent {}
@@ -0,0 +1,22 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<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">
<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>
</a>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,37 @@
// 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 { RegistrarService } from 'src/app/registrar/registrar.service';
@Component({
selector: '[app-billing-widget]',
templateUrl: './billing-widget.component.html',
})
export class BillingWidgetComponent {
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();
}
}
}
@@ -0,0 +1,27 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<mat-icon class="console-app__widget-icon">call</mat-icon>
<h1 class="console-app__widget-title">Contact Support</h1>
<h4 class="secondary-text text-center">
View Google Registry support email and phone information
</h4>
</div>
<div class="console-app__widget_right">
<button mat-button color="primary" class="console-app__widget-link">
Give us a Call
</button>
<p class="secondary-text">
Call Google Registry support at +1 (404) 978 8419
</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
</p>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -15,8 +15,9 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-registrars',
templateUrl: './registrars.component.html',
styleUrls: ['./registrars.component.less'],
selector: '[app-contact-widget]',
templateUrl: './contact-widget.component.html',
})
export default class RegistrarsComponent {}
export class ContactWidgetComponent {
constructor() {}
}
@@ -0,0 +1,25 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<mat-icon class="console-app__widget-icon">view_list</mat-icon>
<h1 class="console-app__widget-title">Domains</h1>
<h4 class="secondary-text text-center">
Manage domain names and registry lock settings.
</h4>
</div>
<div class="console-app__widget_right">
<button mat-button color="primary" class="console-app__widget-link">
Create a Domain
</button>
<p class="secondary-text">Register a new domain name</p>
<button mat-button color="primary" class="console-app__widget-link">
View DUMs
</button>
<p class="secondary-text">
Download a csv of all domains under management
</p>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,23 @@
// 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';
@Component({
selector: '[app-domains-widget]',
templateUrl: './domains-widget.component.html',
})
export class DomainsWidgetComponent {
constructor() {}
}
@@ -0,0 +1,13 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<mat-icon class="console-app__widget-icon">computer</mat-icon>
<h1 class="console-app__widget-title">EPP Console</h1>
<h4 class="secondary-text text-center">
Test run and execute EPP commands using XML files.
</h4>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -11,3 +11,13 @@
// 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';
@Component({
selector: '[app-epp-widget]',
templateUrl: './epp-widget.component.html',
})
export class EppWidgetComponent {
constructor() {}
}
@@ -0,0 +1,27 @@
<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">subject</mat-icon>
<h1 class="console-app__widget-title">Promotions</h1>
<h4 class="secondary-text text-center">
Manage Google Registry promotions and view onboarding process.
</h4>
</div>
<div class="console-app__widget_right">
<button mat-button color="primary" class="console-app__widget-link">
Manage Preferred Partner Program
</button>
<p class="secondary-text">
Onboard or view current preferred partner status
</p>
<button mat-button color="primary" class="console-app__widget-link">
Manage Registry Lock Program
</button>
<p class="secondary-text">
Onboard or view current registry lock status
</p>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,23 @@
// 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';
@Component({
selector: '[app-promotions-widget]',
templateUrl: './promotions-widget.component.html',
})
export class PromotionsWidgetComponent {
constructor() {}
}
@@ -0,0 +1,13 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<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>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,23 @@
// 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';
@Component({
selector: '[app-resources-widget]',
templateUrl: './resources-widget.component.html',
})
export class ResourcesWidgetComponent {
constructor() {}
}
@@ -0,0 +1,38 @@
<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">
Contact Information
</button>
<p class="secondary-text">Manage Primary, Technical, etc contacts.</p>
<button mat-button color="primary" class="console-app__widget-link">
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">
Registrar Management
</button>
<p class="secondary-text">Create and manage registrar accounts</p>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -0,0 +1,23 @@
// 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';
@Component({
selector: '[app-settings-widget]',
templateUrl: './settings-widget.component.html',
})
export class SettingsWidgetComponent {
constructor() {}
}
@@ -0,0 +1,13 @@
<mat-card>
<mat-card-content>
<div class="console-app__widget">
<div class="console-app__widget_left">
<mat-icon class="console-app__widget-icon">list_alt</mat-icon>
<h1 class="console-app__widget-title">TLDs</h1>
<h4 class="secondary-text text-center">
View launch phase information for all onboarded and available TLDs.
</h4>
</div>
</div>
</mat-card-content>
</mat-card>
@@ -1,4 +1,4 @@
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
// 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.
@@ -12,11 +12,12 @@
// See the License for the specific language governing permissions and
// limitations under the License.
html,
body {
height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
import { Component } from '@angular/core';
@Component({
selector: '[app-tlds-widget]',
templateUrl: './tlds-widget.component.html',
})
export class TldsWidgetComponent {
constructor() {}
}
@@ -44,6 +44,7 @@ import { CdkMenuModule } from '@angular/cdk/menu';
import { DialogModule } from '@angular/cdk/dialog';
import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatPaginatorModule } from '@angular/material/paginator';
@NgModule({
exports: [
@@ -79,6 +80,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
OverlayModule,
DialogModule,
MatSnackBarModule,
MatPaginatorModule,
],
})
export class MaterialModule {}
@@ -0,0 +1,7 @@
<div class="console-app__emty-registrar">
<h1>
<mat-icon class="console-app__emty-registrar-icon">block</mat-icon>
</h1>
<h1>No registrar selected</h1>
<h4 class="mat-body-2">Please select a registrar</h4>
</div>
@@ -0,0 +1,17 @@
.console-app {
&__emty-registrar {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
&-icon {
transform: scale(3);
margin-bottom: 0.5rem;
}
}
}
@@ -13,33 +13,32 @@
// limitations under the License.
import { Component } from '@angular/core';
import { RegistrarService } from './registrar.service';
import { ActivatedRoute, Router } from '@angular/router';
import { RegistrarService } from './registrar.service';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-registrar',
templateUrl: './registrar.component.html',
styleUrls: ['./registrar.component.less'],
selector: 'app-empty-registrar',
templateUrl: './emptyRegistrar.component.html',
styleUrls: ['./emptyRegistrar.component.scss'],
})
export class RegistrarComponent {
private lastActiveRegistrarId: string;
export class EmptyRegistrar {
private registrarIdChangeSubscription?: Subscription;
constructor(
private route: ActivatedRoute,
protected registrarService: RegistrarService,
private router: Router
) {
this.lastActiveRegistrarId = registrarService.activeRegistrarId;
this.registrarIdChangeSubscription =
registrarService.activeRegistrarIdChange.subscribe((newRegistrarId) => {
if (newRegistrarId) {
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
}
});
}
ngDoCheck() {
if (
this.registrarService.activeRegistrarId &&
this.registrarService.activeRegistrarId !== this.lastActiveRegistrarId &&
this.route.snapshot.paramMap.get('nextUrl')
) {
this.lastActiveRegistrarId = this.registrarService.activeRegistrarId;
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
}
ngOnDestroy() {
this.registrarIdChangeSubscription?.unsubscribe();
}
}
@@ -0,0 +1,18 @@
<div class="console-app__registrar">
<div>
<mat-form-field class="mat-form-field-density-5" appearance="fill">
<mat-label>Registrar</mat-label>
<mat-select
[ngModel]="registrarService.activeRegistrarId"
(selectionChange)="registrarService.updateRegistrar($event.value)"
>
<mat-option
*ngFor="let registrar of registrarService.registrars"
[value]="registrar.registrarId"
>
{{ registrar.registrarId }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
</div>
@@ -0,0 +1,18 @@
.console-app {
&__registrar {
display: flex;
justify-content: center;
align-items: baseline;
// Fix for angular v15 label issue
// https://github.com/angular/components/issues/26579
.mat-mdc-floating-label {
display: inline !important;
}
.mat-mdc-select-arrow-wrapper {
transform: translateY(0) !important;
}
}
&__title {
margin-right: 1rem;
}
}
@@ -14,18 +14,18 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import RegistrarsComponent from './registrars.component';
import { RegistrarSelectorComponent } from './registrar-selector.component';
describe('RegistrarsComponent', () => {
let component: RegistrarsComponent;
let fixture: ComponentFixture<RegistrarsComponent>;
describe('RegistrarSelectorComponent', () => {
let component: RegistrarSelectorComponent;
let fixture: ComponentFixture<RegistrarSelectorComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [RegistrarsComponent],
declarations: [RegistrarSelectorComponent],
}).compileComponents();
fixture = TestBed.createComponent(RegistrarsComponent);
fixture = TestBed.createComponent(RegistrarSelectorComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
@@ -0,0 +1,25 @@
// 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 { RegistrarService } from './registrar.service';
@Component({
selector: 'app-registrar-selector',
templateUrl: './registrar-selector.component.html',
styleUrls: ['./registrar-selector.component.scss'],
})
export class RegistrarSelectorComponent {
constructor(protected registrarService: RegistrarService) {}
}
@@ -1,17 +0,0 @@
<div class="console-app__registrar">
<h4 class="console-app__title">
{{ registrarService.activeRegistrarId === "" ? "Select" : "Switch" }}
registrar:
</h4>
<mat-form-field>
<mat-label>Registrar</mat-label>
<mat-select [(ngModel)]="registrarService.activeRegistrarId">
<mat-option
*ngFor="let registrar of registrarService.registrars"
[value]="registrar"
>
{{ registrar }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
@@ -1,11 +0,0 @@
.console-app {
&__registrar {
display: flex;
justify-content: center;
align-items: center;
margin-top: 1rem;
}
&__title {
margin-right: 1rem;
}
}
@@ -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' },
@@ -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,12 @@ 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([`/registrars`, { nextUrl: state.url }]);
// Get the full URL including any nested children (skip the initial '#/')
const nextUrl = location.hash.split('#/')[1];
return this.router.navigate([`/empty-registrar`, { nextUrl }]);
}
}
@@ -14,16 +14,74 @@
import { Injectable } from '@angular/core';
import { BackendService } from '../shared/services/backend.service';
import { Observable, Subject, tap } from 'rxjs';
import {
GlobalLoader,
GlobalLoaderService,
} from '../shared/services/globalLoader.service';
interface Address {
street?: string[];
city?: string;
countryCode?: string;
zip?: string;
state?: string;
}
export interface Registrar {
allowedTlds?: string[];
ipAddressAllowList?: string[];
emailAddress?: string;
billingAccountMap?: object;
driveFolderId?: string;
ianaIdentifier?: number;
icannReferralEmail?: string;
localizedAddress?: Address;
registrarId: string;
registrarName: string;
registryLockAllowed?: boolean;
}
@Injectable({
providedIn: 'root',
})
export class RegistrarService {
export class RegistrarService implements GlobalLoader {
activeRegistrarId: string = '';
registrars: string[] = [];
constructor(private backend: BackendService) {
this.backend.getRegistrars().subscribe((r) => {
this.registrars = r;
registrars: Registrar[] = [];
activeRegistrarIdChange: Subject<string> = new Subject<string>();
constructor(
private backend: BackendService,
private globalLoader: GlobalLoaderService
) {
this.loadRegistrars().subscribe((r) => {
this.globalLoader.stopGlobalLoader(this);
});
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
}
}
@@ -0,0 +1,25 @@
<div class="console-app__registrars">
<table
mat-table
[dataSource]="registrarService.registrars"
class="mat-elevation-z8"
>
<ng-container
*ngFor="let column of columns"
[matColumnDef]="column.columnDef"
>
<th mat-header-cell *matHeaderCellDef>
{{ column.header }}
</th>
<td mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
</table>
<mat-paginator
class="mat-elevation-z8"
[pageSizeOptions]="[5, 10, 20]"
showFirstLastButtons
></mat-paginator>
</div>
@@ -0,0 +1,5 @@
.console-app {
&__registrars {
margin-top: 1.5rem;
}
}
@@ -14,7 +14,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RegistrarComponent } from './registrar.component';
import { RegistrarComponent } from './registrarsTable.component';
import { BackendService } from '../shared/services/backend.service';
import { ActivatedRoute } from '@angular/router';
import { HttpClientTestingModule } from '@angular/common/http/testing';
@@ -0,0 +1,75 @@
// 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 { Registrar, RegistrarService } from './registrar.service';
@Component({
selector: 'app-registrar',
templateUrl: './registrarsTable.component.html',
styleUrls: ['./registrarsTable.component.scss'],
})
export class RegistrarComponent {
columns = [
{
columnDef: 'registrarId',
header: 'Registrar Id',
cell: (record: Registrar) => `${record.registrarId || ''}`,
},
{
columnDef: 'registrarName',
header: 'Name',
cell: (record: Registrar) => `${record.registrarName || ''}`,
},
{
columnDef: 'allowedTlds',
header: 'TLDs',
cell: (record: Registrar) => `${(record.allowedTlds || []).join(', ')}`,
},
{
columnDef: 'emailAddress',
header: 'Username',
cell: (record: Registrar) => `${record.emailAddress || ''}`,
},
{
columnDef: 'ianaIdentifier',
header: 'IANA ID',
cell: (record: Registrar) => `${record.ianaIdentifier || ''}`,
},
{
columnDef: 'billingAccountMap',
header: 'Billing Accounts',
cell: (record: Registrar) =>
// @ts-ignore - completely legit line, but TS keeps complaining
`${Object.entries(record.billingAccountMap).reduce(
(acc, [key, val]) => {
return `${acc}${key}=${val}<br/>`;
},
''
)}`,
},
{
columnDef: 'registryLockAllowed',
header: 'Registry Lock',
cell: (record: Registrar) => `${record.registryLockAllowed}`,
},
{
columnDef: 'driveId',
header: 'Drive ID',
cell: (record: Registrar) => `${record.driveFolderId || ''}`,
},
];
displayedColumns = this.columns.map((c) => c.columnDef);
constructor(protected registrarService: RegistrarService) {}
}
@@ -2,6 +2,15 @@
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<div *ngIf="!loading">
<div
class="contact__empty-contacts"
*ngIf="contactService.contacts.length === 0"
>
<mat-icon class="contact__empty-contacts-icon secondary-text"
>apps_outage</mat-icon
>
<h1>No contacts found</h1>
</div>
<div *ngFor="let group of groupedData">
<div class="contact__cards-wrapper" *ngIf="group.contacts.length">
<h3>{{ group.label }}s</h3>
@@ -37,6 +37,18 @@
justify-content: flex-start;
margin: 2rem 0;
}
&__empty-contacts {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
&__empty-contacts-icon {
width: 4rem;
height: 4rem;
font-size: 4rem;
margin-top: 1.5rem;
}
}
.contact-details {
&__input {
@@ -77,7 +77,7 @@ class ContactDetailsEventsResponder {
@Component({
selector: 'app-contact-details-dialog',
templateUrl: 'contact-details.component.html',
styleUrls: ['./contact.component.less'],
styleUrls: ['./contact.component.scss'],
})
export class ContactDetailsDialogComponent {
contact: Contact;
@@ -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,
});
},
@@ -140,7 +140,7 @@ export class ContactDetailsDialogComponent {
@Component({
selector: 'app-contact',
templateUrl: './contact.component.html',
styleUrls: ['./contact.component.less'],
styleUrls: ['./contact.component.scss'],
})
export default class ContactComponent {
loading: boolean = false;
@@ -148,7 +148,8 @@ export default class ContactComponent {
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;
@@ -158,7 +159,7 @@ export default class ContactComponent {
}
public get groupedData() {
return this.contactService.contacts.reduce((acc, contact) => {
return this.contactService.contacts?.reduce((acc, contact) => {
contact.types.forEach((type) => {
acc
.find((group: GroupedContacts) => group.value === type)
@@ -170,7 +171,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,
});
},
});
}
}
@@ -1 +0,0 @@
<p>registrars component works!</p>
@@ -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
@@ -17,6 +17,9 @@
h1 {
margin: 0;
}
&__ipRecord {
margin-bottom: 1rem;
}
&__section {
display: flex;
align-items: stretch;
@@ -13,14 +13,19 @@
// 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',
templateUrl: './security.component.html',
styleUrls: ['./security.component.less'],
styleUrls: ['./security.component.scss'],
providers: [SecurityService],
})
export default class SecurityComponent {
@@ -30,33 +35,19 @@ export default class SecurityComponent {
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 +59,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 +67,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);
}
}
@@ -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();
})
);
}
@@ -17,7 +17,7 @@ import { Component, ViewEncapsulation } from '@angular/core';
@Component({
selector: 'app-settings',
templateUrl: './settings.component.html',
styleUrls: ['./settings.component.less'],
styleUrls: ['./settings.component.scss'],
encapsulation: ViewEncapsulation.None,
})
export class SettingsComponent {}
@@ -17,6 +17,6 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.less'],
styleUrls: ['./users.component.scss'],
})
export default class UsersComponent {}
@@ -17,6 +17,6 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-whois',
templateUrl: './whois.component.html',
styleUrls: ['./whois.component.less'],
styleUrls: ['./whois.component.scss'],
})
export default class WhoisComponent {}
@@ -18,6 +18,7 @@ import { catchError, Observable, of } from 'rxjs';
import { SecuritySettingsBackendModel } from 'src/app/settings/security/security.service';
import { Contact } from '../../settings/contact/contact.service';
import { Registrar } from '../../registrar/registrar.service';
@Injectable()
export class BackendService {
@@ -60,10 +61,10 @@ export class BackendService {
);
}
getRegistrars(): Observable<string[]> {
getRegistrars(): Observable<Registrar[]> {
return this.http
.get<string[]>('/console-api/registrars')
.pipe(catchError((err) => this.errorCatcher<string[]>(err)));
.get<Registrar[]>('/console-api/registrars')
.pipe(catchError((err) => this.errorCatcher<Registrar[]>(err)));
}
getSecuritySettings(
@@ -0,0 +1,60 @@
// 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, Subscription, timeout } from 'rxjs';
export interface GlobalLoader {
loadingTimeout: () => void;
}
/**
* This class responsible for global application loading indicator
*
* <p>Only to be used for when the activity should indicate that the entire application is busy
* For instance - when initial user information is loading, which is crucial for any subsequent
* interaction with the application
*/
@Injectable({
providedIn: 'root',
})
export class GlobalLoaderService {
private static readonly TIMEOUT_MS = 3000;
private loaders = new Map<GlobalLoader, Subscription>();
public isLoading: boolean = false;
private syncLoading() {
this.isLoading = this.loaders.size > 0;
}
startGlobalLoader(c: GlobalLoader) {
const subscription = new Observable(() => {})
.pipe(timeout(GlobalLoaderService.TIMEOUT_MS))
.subscribe({
error: () => {
this.loaders.delete(c);
c.loadingTimeout();
this.syncLoading();
},
});
this.loaders.set(c, subscription);
this.syncLoading();
}
stopGlobalLoader(c: GlobalLoader) {
this.loaders.get(c)?.unsubscribe();
this.loaders.delete(c);
this.syncLoading();
}
}
@@ -17,6 +17,6 @@ import { Component } from '@angular/core';
@Component({
selector: 'app-tlds',
templateUrl: './tlds.component.html',
styleUrls: ['./tlds.component.less'],
styleUrls: ['./tlds.component.scss'],
})
export class TldsComponent {}
+74
View File
@@ -0,0 +1,74 @@
// Copyright 2022 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.
@use "@angular/material" as mat;
@import "app/registrar/registrar-selector.component.scss";
html,
body {
height: 100%;
}
body {
margin: 0;
font-family: Roboto, "Helvetica Neue", sans-serif;
}
.text-center {
text-align: center;
}
.console-app {
&__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;
height: 20px !important;
}
&-title {
color: var(--primary) !important;
}
&-icon {
font-size: 4rem;
line-height: 4rem;
height: 4rem !important;
width: 4rem !important;
}
&_left {
flex: 1;
display: flex;
flex-direction: column;
align-items: center;
}
&_right {
flex: 1;
border-left: 1px solid var(--secondary);
padding-left: 20px;
.secondary-text {
margin-bottom: 0.3rem;
font-size: 0.8rem;
}
}
}
}
+69
View File
@@ -0,0 +1,69 @@
@use "sass:map";
@use "@angular/material" as mat;
/** Copied from docs section **/
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
@include mat.core();
// Define the palettes for your theme using the Material Design palettes available in palette.scss
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
// hue. Available color palettes: https://material.io/design/color/
$theme-primary: mat.define-palette(mat.$indigo-palette);
$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
// The warn palette is optional (defaults to red).
$theme-warn: mat.define-palette(mat.$red-palette);
// Create the theme object. A theme consists of configurations for individual
// theming systems such as "color" or "typography".
$theme: mat.define-light-theme(
(
color: (
primary: $theme-primary,
accent: $theme-accent,
warn: $theme-warn,
),
density: 0,
)
);
/** Application specific section **/
@mixin form-field-density($density) {
$field-typography: mat.define-typography-config(
$body-1: mat.define-typography-level(12px, 24px, 400),
);
@include mat.typography-level($field-typography, "body-1");
@include mat.form-field-density($density);
}
// Define lowest possible density class to be used in application
// In the same manner -1...-5 classes can be defined
.mat-form-field-density-5 {
@include form-field-density(-5);
}
$foreground: map.merge($theme, mat.$light-theme-foreground-palette);
// Access and define a class with secondary color exposed
.secondary-text {
color: map.get($foreground, "secondary-text");
}
:root {
--primary: #{mat.get-color-from-palette($theme-primary, 500)};
--secondary: #{map.get($foreground, "secondary-text")};
}
@include mat.all-component-themes($theme);
@import "@angular/material/theming";
// Define application specific typography settings, font-family, etc
$typography-configuration: mat-typography-config(
$font-family: 'Roboto, "Helvetica Neue", sans-serif',
);
@include angular-material-typography($typography-configuration);
+1 -1
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();
+141 -148
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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
@@ -980,7 +980,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(
@@ -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
@@ -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));
}
}
@@ -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();
@@ -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.
@@ -0,0 +1,172 @@
// 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 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 {
@Parameter(
names = {"-i", "--input"},
description = "Filename of TLD YAML file.",
validateWith = PathParameter.InputFile.class,
required = true)
Path inputFile;
@Inject ObjectMapper mapper;
@Inject
@Named("dnsWriterNames")
Set<String> validDnsWriterNames;
// TODO(sarahbot@): Add a breakglass setting to this tool to indicate when a TLD has been modified
// outside of source control
// TODO(sarahbot@): Add a check for diffs between passed in file and current TLD and exit if there
// is no diff. Treat nulls and empty sets as the same value.
@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);
checkPremiumList(newTld);
checkDnsWriters(newTld);
checkCurrency(newTld);
stageEntityChange(oldTld, newTld);
}
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");
}
}
}
@@ -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;
@@ -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",
@@ -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)
@@ -90,6 +90,8 @@ interface RegistryToolComponent {
void inject(CheckDomainCommand command);
void inject(ConfigureTldCommand command);
void inject(CountDomainsCommand command);
void inject(CreateAnchorTenantCommand command);
@@ -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);
}
}
@@ -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());
@@ -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();
}
}
@@ -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;
}
}
}
@@ -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");
}
@@ -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();
@@ -0,0 +1,450 @@
// 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.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.TestDataHelper.loadFile;
import static google.registry.tldconfig.idn.IdnTableEnum.EXTENDED_LATIN;
import static google.registry.tldconfig.idn.IdnTableEnum.JA;
import static java.nio.charset.StandardCharsets.UTF_8;
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 google.registry.model.EntityYamlUtils;
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 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 = EntityYamlUtils.createObjectMapper();
@BeforeEach
void beforeEach() {
command.mapper = objectMapper;
premiumList = persistPremiumList("test", USD, "silver,USD 50", "gold,USD 80");
command.validDnsWriterNames = ImmutableSet.of("VoidDnsWriter", "FooDnsWriter");
}
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");
}
@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");
}
@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");
}
}
@@ -632,7 +632,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
@@ -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"));
}
@@ -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");
}
}
@@ -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
@@ -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
@@ -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
@@ -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: "TLD"
serverStatusChangeBillingCost:
currency: "USD"
amount: 19.00
tldStateTransitions:
"1970-01-01T00:00:00.000Z": "GENERAL_AVAILABILITY"
tldStr: "badunicode"
tldType: "REAL"
tldUnicode: "tld"
transferGracePeriodLength: 432000000

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