1
0
mirror of https://github.com/google/nomulus synced 2026-05-20 23:01:53 +00:00

Compare commits

...

19 Commits

Author SHA1 Message Date
Lai Jiang
e82cbe60a9 Do not log nested transactions in production (#2251)
This might be the cause of the SQL performance degradation that we are
observing during the recent launch. The change went in a month ago but
there hasn't been enough increase in mutating traffic to make it
problematic until the launch.

Note that presubmits should run faster too with this chance, which
serves as an evidence that excessive logging is the culprit.
2023-12-07 19:02:16 -05:00
Weimin Yu
923bc13e3a Start using Tld's bsaEnrollStartTime field (#2239)
* Start using Tld's bsaEnrollStartTime field

    Longer-term change is tracked in b/309175410
2023-12-06 17:11:36 -05:00
Lai Jiang
4893ea307b Check for null error stream (#2249) 2023-12-06 13:30:37 -05:00
Pavlo Tkach
01f868cefc Increase number of service to 5 in cloudbuild-deploy (#2248) 2023-12-06 13:21:17 -05:00
Weimin Yu
1b0919eaff Add the BsaDomainRefresh table (#2247)
Add the BsaDomainRefresh table which tracks the refresh actions.

The refresh actions checks for changes in the set of registered and
reserved domains, which are called unblockables to BSA.
2023-12-06 11:55:42 -05:00
Lai Jiang
92b23bac16 Use the error stream when HTTP response code is non-200 (#2245) 2023-12-06 10:42:19 -05:00
gbrodman
cc9b3f5965 Filter in SQL when updating/deleting alloc tokens (#2244)
This doesn't fix any issues with dead/livelocks when deleting or
updating allocation tokens, but it at least will significantly reduce
the time to load the tokens that we'll want to update/delete.
2023-12-04 19:24:17 -05:00
gbrodman
dd86c56ddc Return the correct renewal fee for anchor tenants in domain checks (#2238)
The code as previously written assumed that creation fees would be the
same as renewal fees -- this is not the case for anchor tenants, where
the renewal fee is always the standard cost for the TLD (instead of any
premium cost). This was already handled properly in the actual billing
implementation, but we didn't tell the user the right renewal cost in
domain checks.

This also removes some warning logs related to nested transactions
2023-12-01 15:37:05 -05:00
Pavlo Tkach
08551f7bc7 Enable static ip for bsa service production (#2240) 2023-12-01 14:25:38 -05:00
Lai Jiang
e7171a326b Use reTransact when loading caches (#2234)
Similar to #2179, but adds a few calls missed in that PR.
2023-11-30 15:13:36 -05:00
gbrodman
c3eae7b76f Add an optional search term for ConsoleDomainListAction (#2225)
It's a case-insensitive query and it can appear anywhere (including
TLDs)
2023-11-30 11:42:50 -05:00
Pavlo Tkach
2687181045 Update console file naming to be camelCase like (#2235) 2023-11-30 11:42:36 -05:00
gbrodman
68750569db Pretty-print reserved list updates in the CLI (#2226)
We shouldn't have to parse through every single entry to see what
changed

Note: we don't do this for premium lists because those can be HUGE and
we don't want/need to load and display every entry. This was an explicit
choice made in https://github.com/google/nomulus/pull/1482
2023-11-30 11:32:12 -05:00
Lai Jiang
028e5cc958 Make read-only transactions more performant (#2233)
Since the replica SQL instance is read-only, any transaction performed
on it should be explicitly read-only, which would allow PostgreSQL to
optimize away (some) use of predicate locks.

Also changed the EPP cache to read from the replica. The foreign key
cache already behaves this way.

See: https://www.postgresql.org/docs/current/transaction-iso.html
2023-11-29 15:55:50 -05:00
Weimin Yu
853e571d01 Add more BSA configs (#2230)
* Add more BSA configs

Added urls for reporting order and domains to BSA.

Also added operational configs.
2023-11-28 16:40:36 -05:00
Lai Jiang
9b79f5af2c Add a dedicated IP header to accommodate Java 17 on GAE (#2224)
For reasons unclear at this point, Java 17's servlet implementation on
GAE injects IP addresses (including unroutable private IPs) into the
standard X-Forwarded-For header, which we currently use to embed
registrar IP addresses to check against the allow list. This results in
the server not properly parsing the header and rejecting legitimate
connections.

This PR sets a custom header that should not be interfered with by any
JVM implementation to store the IP address, while maintaining the old
header as a fallback. The proxy will set both headers to allow the
server to gracefully migrate from Java 8 and Java 17 (and potentially
rollback).

Also removed some headers and logic that are not used.
2023-11-28 13:20:01 -05:00
Weimin Yu
4195871541 Fix misconfiguration in new BSA service (#2227)
Also add dependency locking to services:bsa
2023-11-27 20:18:34 -05:00
Weimin Yu
504d7ccaac Preparing renaming BsaDomainInUse table (#2228)
Add the replacement table: BsaUnblockableDomain
2023-11-27 19:55:47 -05:00
gbrodman
36a8908712 Add a basic domain-list page to the new console (#2219)
This does not include any styling for now, just wanted to make sure
we're all good with regards to the basic approach. I'm open to suggestion on
which columns to include.

Note: filter searching is not implemented yet because the backend does
not allow for it (yet)
2023-11-27 14:58:48 -05:00
90 changed files with 3965 additions and 2674 deletions

View File

@@ -28,6 +28,7 @@ import ContactComponent from './settings/contact/contact.component';
import WhoisComponent from './settings/whois/whois.component';
import SecurityComponent from './settings/security/security.component';
import UsersComponent from './settings/users/users.component';
import { DomainListComponent } from './domains/domainList.component';
const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' },
@@ -35,6 +36,11 @@ const routes: Routes = [
{ path: 'empty-registrar', component: EmptyRegistrar },
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
{
path: DomainListComponent.PATH,
component: DomainListComponent,
canActivate: [RegistrarGuard],
},
{
path: SettingsComponent.PATH,
component: SettingsComponent,

View File

@@ -36,16 +36,16 @@ 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 { RegistrarSelectorComponent } from './registrar/registrarSelector.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';
import { ContactWidgetComponent } from './home/widgets/contactWidget.component';
import { PromotionsWidgetComponent } from './home/widgets/promotionsWidget.component';
import { TldsWidgetComponent } from './home/widgets/tldsWidget.component';
import { ResourcesWidgetComponent } from './home/widgets/resourcesWidget.component';
import { EppWidgetComponent } from './home/widgets/eppWidget.component';
import { BillingWidgetComponent } from './home/widgets/billingWidget.component';
import { DomainsWidgetComponent } from './home/widgets/domainsWidget.component';
import { SettingsWidgetComponent } from './home/widgets/settingsWidget.component';
import { UserDataService } from './shared/services/userData.service';
import WhoisComponent from './settings/whois/whois.component';
import { SnackBarModule } from './snackbar.module';
@@ -53,6 +53,7 @@ import {
RegistrarDetailsComponent,
RegistrarDetailsWrapperComponent,
} from './registrar/registrarDetails.component';
import { DomainListComponent } from './domains/domainList.component';
@NgModule({
declarations: [
@@ -60,6 +61,7 @@ import {
BillingWidgetComponent,
ContactDetailsDialogComponent,
ContactWidgetComponent,
DomainListComponent,
DomainsWidgetComponent,
EmptyRegistrar,
EppWidgetComponent,

View File

@@ -0,0 +1,54 @@
<div class="console-domains">
<mat-form-field>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event)" #input />
</mat-form-field>
<div *ngIf="isLoading; else domains_content" class="console-domains__loading">
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
</div>
<ng-template #domains_content>
<table mat-table [dataSource]="dataSource" class="mat-elevation-z8">
<ng-container matColumnDef="domainName">
<th mat-header-cell *matHeaderCellDef>Domain Name</th>
<td mat-cell *matCellDef="let element">{{ element.domainName }}</td>
</ng-container>
<ng-container matColumnDef="creationTime">
<th mat-header-cell *matHeaderCellDef>Creation Time</th>
<td mat-cell *matCellDef="let element">
{{ element.creationTime.creationTime }}
</td>
</ng-container>
<ng-container matColumnDef="registrationExpirationTime">
<th mat-header-cell *matHeaderCellDef>Expiration Time</th>
<td mat-cell *matCellDef="let element">
{{ element.registrationExpirationTime }}
</td>
</ng-container>
<ng-container matColumnDef="statuses">
<th mat-header-cell *matHeaderCellDef>Statuses</th>
<td mat-cell *matCellDef="let element">{{ element.statuses }}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
<!-- Row shown when there is no matching data. -->
<tr class="mat-row" *matNoDataRow>
<td class="mat-cell" colspan="4">No domains found</td>
</tr>
</table>
<mat-paginator
[length]="totalResults"
[pageIndex]="pageNumber"
[pageSize]="resultsPerPage"
[pageSizeOptions]="[10, 25, 50, 100, 500]"
(page)="onPageChange($event)"
aria-label="Select page of domain results"
showFirstLastButtons
></mat-paginator>
</ng-template>
</div>

View File

@@ -0,0 +1,36 @@
// 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 { ComponentFixture, TestBed } from '@angular/core/testing';
import { DomainListComponent } from './domainList.component';
describe('DomainListComponent', () => {
let component: DomainListComponent;
let fixture: ComponentFixture<DomainListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DomainListComponent],
}).compileComponents();
fixture = TestBed.createComponent(DomainListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@@ -0,0 +1,80 @@
// 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, ViewChild } from '@angular/core';
import { MatTableDataSource } from '@angular/material/table';
import { BackendService } from '../shared/services/backend.service';
import { MatPaginator, PageEvent } from '@angular/material/paginator';
import { RegistrarService } from '../registrar/registrar.service';
import { Domain, DomainListService } from './domainList.service';
@Component({
selector: 'app-domain-list',
templateUrl: './domainList.component.html',
styleUrls: ['./domainList.component.scss'],
providers: [DomainListService],
})
export class DomainListComponent {
public static PATH = 'domain-list';
displayedColumns: string[] = [
'domainName',
'creationTime',
'registrationExpirationTime',
'statuses',
];
dataSource: MatTableDataSource<Domain> = new MatTableDataSource();
isLoading = true;
pageNumber?: number;
resultsPerPage = 50;
totalResults?: number;
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
constructor(
private backendService: BackendService,
private domainListService: DomainListService,
private registrarService: RegistrarService
) {}
ngOnInit() {
this.dataSource.paginator = this.paginator;
this.reloadData();
}
reloadData() {
this.isLoading = true;
this.domainListService
.retrieveDomains(this.pageNumber, this.resultsPerPage, this.totalResults)
.subscribe((domainListResult) => {
this.dataSource.data = domainListResult.domains;
this.totalResults = domainListResult.totalResults;
this.isLoading = false;
});
}
/** TODO: the backend will need to accept a filter string. */
applyFilter(event: KeyboardEvent) {
// const filterValue = (event.target as HTMLInputElement).value;
this.reloadData();
}
onPageChange(event: PageEvent) {
this.pageNumber = event.pageIndex;
this.resultsPerPage = event.pageSize;
this.reloadData();
}
}

View File

@@ -0,0 +1,66 @@
// 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 { BackendService } from '../shared/services/backend.service';
import { RegistrarService } from '../registrar/registrar.service';
import { tap } from 'rxjs';
export interface CreateAutoTimestamp {
creationTime: string;
}
export interface Domain {
creationTime: CreateAutoTimestamp;
currentSponsorRegistrarId: string;
domainName: string;
registrationExpirationTime: string;
statuses: string[];
}
export interface DomainListResult {
checkpointTime: string;
domains: Domain[];
totalResults: number;
}
@Injectable()
export class DomainListService {
checkpointTime?: string;
constructor(
private backendService: BackendService,
private registrarService: RegistrarService
) {}
retrieveDomains(
pageNumber?: number,
resultsPerPage?: number,
totalResults?: number
) {
return this.backendService
.getDomains(
this.registrarService.activeRegistrarId,
this.checkpointTime,
pageNumber,
resultsPerPage,
totalResults
)
.pipe(
tap((domainListResult: DomainListResult) => {
this.checkpointTime = domainListResult.checkpointTime;
})
);
}
}

View File

@@ -17,7 +17,7 @@ import { RegistrarService } from 'src/app/registrar/registrar.service';
@Component({
selector: '[app-billing-widget]',
templateUrl: './billing-widget.component.html',
templateUrl: './billingWidget.component.html',
})
export class BillingWidgetComponent {
constructor(public registrarService: RegistrarService) {}

View File

@@ -17,7 +17,7 @@ import { UserDataService } from 'src/app/shared/services/userData.service';
@Component({
selector: '[app-contact-widget]',
templateUrl: './contact-widget.component.html',
templateUrl: './contactWidget.component.html',
})
export class ContactWidgetComponent {
constructor(public userDataService: UserDataService) {}

View File

@@ -13,7 +13,12 @@
Create a Domain
</button>
<p class="secondary-text">Register a new domain name</p>
<button mat-button color="primary" class="console-app__widget-link">
<button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openDomainsPage()"
>
View DUMs
</button>
<p class="secondary-text">

View File

@@ -13,11 +13,17 @@
// limitations under the License.
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { DomainListComponent } from 'src/app/domains/domainList.component';
@Component({
selector: '[app-domains-widget]',
templateUrl: './domains-widget.component.html',
templateUrl: './domainsWidget.component.html',
})
export class DomainsWidgetComponent {
constructor() {}
constructor(private router: Router) {}
openDomainsPage() {
this.router.navigate([DomainListComponent.PATH]);
}
}

View File

@@ -16,7 +16,7 @@ import { Component } from '@angular/core';
@Component({
selector: '[app-epp-widget]',
templateUrl: './epp-widget.component.html',
templateUrl: './eppWidget.component.html',
})
export class EppWidgetComponent {
constructor() {}

View File

@@ -16,7 +16,7 @@ import { Component } from '@angular/core';
@Component({
selector: '[app-promotions-widget]',
templateUrl: './promotions-widget.component.html',
templateUrl: './promotionsWidget.component.html',
})
export class PromotionsWidgetComponent {
constructor() {}

View File

@@ -17,7 +17,7 @@ import { UserDataService } from 'src/app/shared/services/userData.service';
@Component({
selector: '[app-resources-widget]',
templateUrl: './resources-widget.component.html',
templateUrl: './resourcesWidget.component.html',
})
export class ResourcesWidgetComponent {
constructor(public userDataService: UserDataService) {}

View File

@@ -21,7 +21,7 @@ import { SettingsComponent } from 'src/app/settings/settings.component';
@Component({
selector: '[app-settings-widget]',
templateUrl: './settings-widget.component.html',
templateUrl: './settingsWidget.component.html',
})
export class SettingsWidgetComponent {
constructor(private router: Router) {}

View File

@@ -16,7 +16,7 @@ import { Component } from '@angular/core';
@Component({
selector: '[app-tlds-widget]',
templateUrl: './tlds-widget.component.html',
templateUrl: './tldsWidget.component.html',
})
export class TldsWidgetComponent {
constructor() {}

View File

@@ -14,7 +14,7 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RegistrarSelectorComponent } from './registrar-selector.component';
import { RegistrarSelectorComponent } from './registrarSelector.component';
describe('RegistrarSelectorComponent', () => {
let component: RegistrarSelectorComponent;

View File

@@ -21,8 +21,8 @@ const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 599px)';
@Component({
selector: 'app-registrar-selector',
templateUrl: './registrar-selector.component.html',
styleUrls: ['./registrar-selector.component.scss'],
templateUrl: './registrarSelector.component.html',
styleUrls: ['./registrarSelector.component.scss'],
})
export class RegistrarSelectorComponent implements OnInit {
protected isMobile: boolean = false;

View File

@@ -76,7 +76,7 @@ class ContactDetailsEventsResponder {
@Component({
selector: 'app-contact-details-dialog',
templateUrl: 'contact-details.component.html',
templateUrl: 'contactDetails.component.html',
styleUrls: ['./contact.component.scss'],
})
export class ContactDetailsDialogComponent {

View File

@@ -21,6 +21,7 @@ import { Contact } from '../../settings/contact/contact.service';
import { Registrar } from '../../registrar/registrar.service';
import { UserData } from './userData.service';
import { WhoisRegistrarFields } from 'src/app/settings/whois/whois.service';
import { DomainListResult } from 'src/app/domains/domainList.service';
@Injectable()
export class BackendService {
@@ -63,6 +64,31 @@ export class BackendService {
);
}
getDomains(
registrarId: string,
checkpointTime?: string,
pageNumber?: number,
resultsPerPage?: number,
totalResults?: number
): Observable<DomainListResult> {
var url = `/console-api/domain-list?registrarId=${registrarId}`;
if (checkpointTime) {
url += `&checkpointTime=${checkpointTime}`;
}
if (pageNumber) {
url += `&pageNumber=${pageNumber}`;
}
if (resultsPerPage) {
url += `&resultsPerPage=${resultsPerPage}`;
}
if (totalResults) {
url += `&totalResults=${totalResults}`;
}
return this.http
.get<DomainListResult>(url)
.pipe(catchError((err) => this.errorCatcher<DomainListResult>(err)));
}
getRegistrars(): Observable<Registrar[]> {
return this.http
.get<Registrar[]>('/console-api/registrars')

View File

@@ -12,7 +12,7 @@
// 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";
@import "app/registrar/registrarSelector.component.scss";
html,
body {

View File

@@ -16,8 +16,8 @@ package google.registry.bsa;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.collect.Maps.transformValues;
import static google.registry.model.tld.Tld.isEnrolledWithBsa;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableSet;
@@ -50,14 +50,6 @@ public class IdnChecker {
allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet());
}
// TODO(11/30/2023): Remove below when new Tld schema is deployed and the `getBsaEnrollStartTime`
// method is no longer hardcoded.
@VisibleForTesting
IdnChecker(ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> idnToTlds) {
this.idnToTlds = idnToTlds;
allTlds = idnToTlds.values().stream().flatMap(ImmutableSet::stream).collect(toImmutableSet());
}
/** Returns all IDNs in which the {@code label} is valid. */
ImmutableSet<IdnTableEnum> getAllValidIdns(String label) {
return idnToTlds.keySet().stream()
@@ -88,11 +80,6 @@ public class IdnChecker {
return Sets.difference(allTlds, getSupportingTlds(idnTables));
}
private static boolean isEnrolledWithBsa(Tld tld, DateTime now) {
DateTime enrollTime = tld.getBsaEnrollStartTime();
return enrollTime != null && enrollTime.isBefore(now);
}
private static ImmutableMap<IdnTableEnum, ImmutableSet<Tld>> getIdnToTldMap(DateTime now) {
ImmutableMultimap.Builder<IdnTableEnum, Tld> idnToTldMap = new ImmutableMultimap.Builder();
Tlds.getTldEntitiesOfType(TldType.REAL).stream()

View File

@@ -1397,6 +1397,47 @@ public final class RegistryConfig {
return config.bulkPricingPackageMonitoring.bulkPricingPackageDomainLimitUpgradeEmailBody;
}
@Provides
@Config("bsaGcsBucket")
public static String provideBsaGcsBucket(@Config("projectId") String projectId) {
return projectId + "-bsa";
}
@Provides
@Config("bsaChecksumAlgorithm")
public static String provideBsaChecksumAlgorithm(RegistryConfigSettings config) {
return config.bsa.bsaChecksumAlgorithm;
}
@Provides
@Config("bsaLockLeaseExpiry")
public static Duration provideBsaLockLeaseExpiry(RegistryConfigSettings config) {
return Duration.standardMinutes(config.bsa.bsaLockLeaseExpiryMinutes);
}
/** Returns the desired interval between successive BSA downloads. */
@Provides
@Config("bsaDownloadInterval")
public static Duration provideBsaDownloadInterval(RegistryConfigSettings config) {
return Duration.standardMinutes(config.bsa.bsaDownloadIntervalMinutes);
}
/**
* Returns the maximum period when a BSA download can be skipped due to the checksum-based
* equality check with the previous download.
*/
@Provides
@Config("bsaMaxNopInterval")
public static Duration provideBsaMaxNopInterval(RegistryConfigSettings config) {
return Duration.standardHours(config.bsa.bsaMaxNopIntervalHours);
}
@Provides
@Config("bsaLabelTxnBatchSize")
public static int provideBsaLabelTxnBatchSize(RegistryConfigSettings config) {
return config.bsa.bsaLabelTxnBatchSize;
}
@Provides
@Config("bsaAuthUrl")
public static String provideBsaAuthUrl(RegistryConfigSettings config) {
@@ -1415,6 +1456,27 @@ public final class RegistryConfig {
return ImmutableMap.copyOf(config.bsa.dataUrls);
}
/** Provides the BSA Http endpoint for reporting order processing status. */
@Provides
@Config("bsaOrderStatusUrl")
public static String provideBsaOrderStatusUrls(RegistryConfigSettings config) {
return config.bsa.orderStatusUrl;
}
/** Provides the BSA Http endpoint for reporting new unblockable domains. */
@Provides
@Config("bsaAddUnblockableDomainsUrl")
public static String provideBsaAddUnblockableDomainsUrls(RegistryConfigSettings config) {
return String.format("%s?%s", config.bsa.unblockableDomainsUrl, "action=add");
}
/** Provides the BSA Http endpoint for reporting domains that have become blockable. */
@Provides
@Config("bsaRemoveUnblockableDomainsUrl")
public static String provideBsaRemoveUnblockableDomainsUrls(RegistryConfigSettings config) {
return String.format("%s?%s", config.bsa.unblockableDomainsUrl, "action=remove");
}
private static String formatComments(String text) {
return Splitter.on('\n').omitEmptyStrings().trimResults().splitToList(text).stream()
.map(s -> "# " + s)

View File

@@ -267,8 +267,15 @@ public class RegistryConfigSettings {
/** Configurations for integration with Brand Safety Alliance (BSA) API. */
public static class Bsa {
public String bsaChecksumAlgorithm;
public int bsaLockLeaseExpiryMinutes;
public int bsaDownloadIntervalMinutes;
public int bsaMaxNopIntervalHours;
public int bsaLabelTxnBatchSize;
public String authUrl;
public int authTokenExpirySeconds;
public Map<String, String> dataUrls;
public String orderStatusUrl;
public String unblockableDomainsUrl;
}
}

View File

@@ -617,3 +617,7 @@ bsa:
dataUrls:
"BLOCK": "https://"
"BLOCK_PLUS": "https://"
# Http endpoint for reporting order processing status
orderStatusUrl: "https://"
# Http endpoint for reporting changes in the set of unblockable domains.
unblockableDomainsUrl: "https://"

View File

@@ -15,8 +15,8 @@
<!-- Test action -->
<servlet-mapping>
<servlet-name>backend-servlet</servlet-name>
<url-pattern>/_dr/task/bsa</url-pattern>
<servlet-name>bsa-servlet</servlet-name>
<url-pattern>/_dr/task/bsaDownload</url-pattern>
</servlet-mapping>
<!-- Security config -->

View File

@@ -19,6 +19,12 @@
value="production"/>
</system-properties>
<!-- Enable external traffic to go through VPC, required for static ip -->
<vpc-access-connector>
<name>projects/domain-registry/locations/us-central1/connectors/appengine-connector</name>
<egress-setting>all-traffic</egress-setting>
</vpc-access-connector>
<static-files>
<include path="/*.html" expiration="1d"/>
</static-files>

View File

@@ -75,14 +75,6 @@ public class EppRequestHandler {
&& eppOutput.getResponse().getResult().getCode() == SUCCESS_AND_CLOSE) {
response.setHeader(ProxyHttpHeaders.EPP_SESSION, "close");
}
// If a login request returns a success, a logged-in header is added to the response to inform
// the proxy that it is no longer necessary to send the full client certificate to the backend
// for this connection.
if (eppOutput.isResponse()
&& eppOutput.getResponse().isLoginResponse()
&& eppOutput.isSuccess()) {
response.setHeader(ProxyHttpHeaders.LOGGED_IN, "true");
}
} catch (Exception e) {
logger.atWarning().withCause(e).log("handleEppCommand general exception.");
response.setStatus(SC_BAD_REQUEST);

View File

@@ -26,6 +26,7 @@ import com.google.common.net.InetAddresses;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryEnvironment;
import google.registry.flows.EppException.AuthenticationErrorException;
import google.registry.flows.certs.CertificateChecker;
import google.registry.flows.certs.CertificateChecker.InsecureCertificateException;
@@ -66,11 +67,11 @@ public class TlsCredentials implements TransportCredentials {
public TlsCredentials(
@Config("requireSslCertificates") boolean requireSslCertificates,
@Header(ProxyHttpHeaders.CERTIFICATE_HASH) Optional<String> clientCertificateHash,
@Header(ProxyHttpHeaders.IP_ADDRESS) Optional<String> clientAddress,
Optional<InetAddress> clientInetAddr,
CertificateChecker certificateChecker) {
this.requireSslCertificates = requireSslCertificates;
this.clientCertificateHash = clientCertificateHash;
this.clientInetAddr = clientAddress.map(TlsCredentials::parseInetAddress);
this.clientInetAddr = clientInetAddr;
this.certificateChecker = certificateChecker;
}
@@ -104,18 +105,25 @@ public class TlsCredentials implements TransportCredentials {
}
// In the rare unexpected case that the client inet address wasn't passed along at all, then
// by default deny access.
if (clientInetAddr.isPresent()) {
for (CidrAddressBlock cidrAddressBlock : ipAddressAllowList) {
if (cidrAddressBlock.contains(clientInetAddr.get())) {
// IP address is in allow list; return early.
return;
}
if (!clientInetAddr.isPresent()) {
logger.atWarning().log(
"Authentication error: Missing IP address for registrar %s.", registrar.getRegistrarId());
throw new BadRegistrarIpAddressException(clientInetAddr);
}
for (CidrAddressBlock cidrAddressBlock : ipAddressAllowList) {
if (cidrAddressBlock.contains(clientInetAddr.get())) {
// IP address is in allow list; return early.
return;
}
}
logger.atInfo().log(
logger.atWarning().log(
"Authentication error: IP address %s is not allow-listed for registrar %s; allow list is:"
+ " %s",
clientInetAddr, registrar.getRegistrarId(), ipAddressAllowList);
clientInetAddr,
registrar.getRegistrarId(),
RegistryEnvironment.get() == RegistryEnvironment.PRODUCTION
? "redacted in production"
: ipAddressAllowList);
throw new BadRegistrarIpAddressException(clientInetAddr);
}
@@ -232,7 +240,7 @@ public class TlsCredentials implements TransportCredentials {
? String.format(
"Registrar IP address %s is not in stored allow list",
clientInetAddr.get().getHostAddress())
: "Registrar IP address is not in stored allow list");
: "Registrar IP address is missing");
}
}
@@ -249,9 +257,14 @@ public class TlsCredentials implements TransportCredentials {
}
@Provides
@Header(ProxyHttpHeaders.IP_ADDRESS)
static Optional<String> provideIpAddress(HttpServletRequest req) {
return extractOptionalHeader(req, ProxyHttpHeaders.IP_ADDRESS);
static Optional<InetAddress> provideIpAddress(HttpServletRequest req) {
Optional<String> clientAddress = extractOptionalHeader(req, ProxyHttpHeaders.IP_ADDRESS);
Optional<String> fallbackClientAddress =
extractOptionalHeader(req, ProxyHttpHeaders.IP_ADDRESS);
Optional<InetAddress> clientInetAddr = clientAddress.map(TlsCredentials::parseInetAddress);
return clientInetAddr.isPresent()
? clientInetAddr
: fallbackClientAddress.map(TlsCredentials::parseInetAddress);
}
}
}

View File

@@ -18,7 +18,6 @@ import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.flows.domain.DomainFlowUtils.zeroInCurrency;
import static google.registry.flows.domain.token.AllocationTokenFlowUtils.validateTokenForPossiblePremiumName;
import static google.registry.pricing.PricingEngineProxy.getPricesForDomainName;
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import com.google.common.net.InternetDomainName;
@@ -31,11 +30,13 @@ import google.registry.flows.custom.DomainPricingCustomLogic.RenewPriceParameter
import google.registry.flows.custom.DomainPricingCustomLogic.RestorePriceParameters;
import google.registry.flows.custom.DomainPricingCustomLogic.TransferPriceParameters;
import google.registry.flows.custom.DomainPricingCustomLogic.UpdatePriceParameters;
import google.registry.model.billing.BillingBase.RenewalPriceBehavior;
import google.registry.model.billing.BillingRecurrence;
import google.registry.model.domain.fee.BaseFee;
import google.registry.model.domain.fee.BaseFee.FeeType;
import google.registry.model.domain.fee.Fee;
import google.registry.model.domain.token.AllocationToken;
import google.registry.model.domain.token.AllocationToken.RegistrationBehavior;
import google.registry.model.domain.token.AllocationToken.TokenBehavior;
import google.registry.model.pricing.PremiumPricingEngine.DomainPrices;
import google.registry.model.tld.Tld;
@@ -132,12 +133,14 @@ public final class DomainPricingLogic {
// recurrence is null if the domain is still available. Billing events are created
// in the process of domain creation.
if (billingRecurrence == null) {
renewCost = getDomainRenewCostWithDiscount(domainPrices, years, allocationToken);
renewCost =
getDomainRenewCostWithDiscount(tld, domainPrices, dateTime, years, allocationToken);
isRenewCostPremiumPrice = domainPrices.isPremium();
} else {
switch (billingRecurrence.getRenewalPriceBehavior()) {
case DEFAULT:
renewCost = getDomainRenewCostWithDiscount(domainPrices, years, allocationToken);
renewCost =
getDomainRenewCostWithDiscount(tld, domainPrices, dateTime, years, allocationToken);
isRenewCostPremiumPrice = domainPrices.isPremium();
break;
// if the renewal price behavior is specified, then the renewal price should be the same
@@ -156,10 +159,7 @@ public final class DomainPricingLogic {
case NONPREMIUM:
renewCost =
getDomainCostWithDiscount(
false,
years,
allocationToken,
Tld.get(getTldFromDomainName(domainName)).getStandardRenewCost(dateTime));
false, years, allocationToken, tld.getStandardRenewCost(dateTime));
isRenewCostPremiumPrice = false;
break;
default:
@@ -257,8 +257,20 @@ public final class DomainPricingLogic {
/** Returns the domain renew cost with allocation-token-related discounts applied. */
private Money getDomainRenewCostWithDiscount(
DomainPrices domainPrices, int years, Optional<AllocationToken> allocationToken)
Tld tld,
DomainPrices domainPrices,
DateTime dateTime,
int years,
Optional<AllocationToken> allocationToken)
throws AllocationTokenInvalidForPremiumNameException {
// Short-circuit if the user sent an anchor-tenant or otherwise NONPREMIUM-renewal token
if (allocationToken.isPresent()) {
AllocationToken token = allocationToken.get();
if (token.getRegistrationBehavior().equals(RegistrationBehavior.ANCHOR_TENANT)
|| token.getRenewalPriceBehavior().equals(RenewalPriceBehavior.NONPREMIUM)) {
return tld.getStandardRenewCost(dateTime).multipliedBy(years);
}
}
return getDomainCostWithDiscount(
domainPrices.isPremium(), years, allocationToken, domainPrices.getRenewCost());
}

View File

@@ -20,6 +20,7 @@ import static com.google.common.collect.Sets.difference;
import static com.google.common.collect.Sets.union;
import static google.registry.config.RegistryConfig.getEppResourceCachingDuration;
import static google.registry.config.RegistryConfig.getEppResourceMaxCachedEntries;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmpty;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
@@ -357,13 +358,13 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
@Override
public EppResource load(VKey<? extends EppResource> key) {
return tm().reTransact(() -> tm().loadByKey(key));
return replicaTm().reTransact(() -> replicaTm().loadByKey(key));
}
@Override
public Map<VKey<? extends EppResource>, EppResource> loadAll(
Iterable<? extends VKey<? extends EppResource>> keys) {
return tm().reTransact(() -> tm().loadByKeys(keys));
return replicaTm().reTransact(() -> replicaTm().loadByKeys(keys));
}
};

View File

@@ -165,10 +165,11 @@ public final class ForeignKeyUtils {
* foreign keys should not use this cache.
*
* <p>Note that here the key of the {@link LoadingCache} is of type {@code VKey<? extends
* EppResource>}, but they are not legal {VKey}s to {@link EppResource}s, whose keys are the SQL
* primary keys, i.e. the {@code repoId}s. Instead, their keys are the foreign keys used to query
* the database. We use {@link VKey} here because it is a convenient composite class that contains
* both the resource type and the foreign key, which are needed to for the query and caching.
* EppResource>}, but they are not legal {@link VKey}s to {@link EppResource}s, whose keys are the
* SQL primary keys, i.e. the {@code repoId}s. Instead, their keys are the foreign keys used to
* query the database. We use {@link VKey} here because it is a convenient composite class that
* contains both the resource type and the foreign key, which are needed to for the query and
* caching.
*
* <p>Also note that the value type of this cache is {@link Optional} because the foreign keys in
* question are coming from external commands, and thus don't necessarily represent entities in

View File

@@ -256,6 +256,11 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
return VKey.create(Tld.class, tldStr);
}
/** Checks if {@code tld} is enrolled with BSA. */
public static boolean isEnrolledWithBsa(Tld tld, DateTime now) {
return tld.getBsaEnrollStartTime().orElse(END_OF_TIME).isBefore(now);
}
/**
* The name of the pricing engine that this TLD uses.
*
@@ -550,9 +555,15 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
@JsonSerialize(using = SortedEnumSetSerializer.class)
Set<IdnTableEnum> idnTables;
// TODO(11/30/2023): uncomment below two lines
// /** The start time of this TLD's enrollment in the BSA program, if applicable. */
// @JsonIgnore @Nullable DateTime bsaEnrollStartTime;
/**
* The start time of this TLD's enrollment in the BSA program, if applicable.
*
* <p>This property is excluded from source-based configuration and is managed directly in the
* database.
*/
// TODO(b/309175410): implement setup and cleanup procedure for joining or leaving BSA, and see
// if it can be integrated with the ConfigTldCommand.
@JsonIgnore @Nullable DateTime bsaEnrollStartTime;
public String getTldStr() {
return tldStr;
@@ -574,12 +585,9 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
}
/** Returns the time when this TLD was enrolled in the Brand Safety Alliance (BSA) program. */
@JsonIgnore // Annotation can be removed once we add the field and annotate it.
@Nullable
public DateTime getBsaEnrollStartTime() {
// TODO(11/30/2023): uncomment below.
// return this.bsaEnrollStartTime;
return null;
@JsonIgnore
public Optional<DateTime> getBsaEnrollStartTime() {
return Optional.ofNullable(this.bsaEnrollStartTime);
}
/** Retrieve whether invoicing is enabled. */
@@ -1101,10 +1109,9 @@ public class Tld extends ImmutableObject implements Buildable, UnsafeSerializabl
return this;
}
public Builder setBsaEnrollStartTime(DateTime enrollTime) {
public Builder setBsaEnrollStartTime(Optional<DateTime> enrollTime) {
// TODO(b/309175133): forbid if enrolled with BSA
// TODO(11/30/2023): uncomment below line
// getInstance().bsaEnrollStartTime = enrollTime;
getInstance().bsaEnrollStartTime = enrollTime.orElse(null);
return this;
}

View File

@@ -45,7 +45,7 @@ import org.joda.money.Money;
* {@link PremiumList} object in SQL, and caching these entries so that future lookups can be
* quicker.
*/
public class PremiumListDao {
public final class PremiumListDao {
/**
* In-memory cache for premium lists.
@@ -102,7 +102,7 @@ public class PremiumListDao {
/**
* Returns the most recent revision of the PremiumList with the specified name, if it exists.
*
* <p>Note that this does not load <code>PremiumList.labelsToPrices</code>! If you need to check
* <p>Note that this does not load {@code PremiumList.labelsToPrices}! If you need to check
* prices, use {@link #getPremiumPrice}.
*/
public static Optional<PremiumList> getLatestRevision(String premiumListName) {
@@ -169,7 +169,7 @@ public class PremiumListDao {
}
private static Optional<PremiumList> getLatestRevisionUncached(String premiumListName) {
return tm().transact(
return tm().reTransact(
() ->
tm().query(
"FROM PremiumList WHERE name = :name ORDER BY revisionId DESC",
@@ -197,10 +197,10 @@ public class PremiumListDao {
/**
* Loads the price for the given revisionId + label combination. Note that this does a database
* retrieval so it should only be done in a cached context.
* retrieval, so it should only be done in a cached context.
*/
static Optional<BigDecimal> getPriceForLabelUncached(RevisionIdAndLabel revisionIdAndLabel) {
return tm().transact(
return tm().reTransact(
() ->
tm().query(
"SELECT pe.price FROM PremiumEntry pe WHERE pe.revisionId = :revisionId"

View File

@@ -199,7 +199,7 @@ public final class ReservedList
public synchronized ImmutableMap<String, ReservedListEntry> getReservedListEntries() {
if (reservedListMap == null) {
reservedListMap =
tm().transact(
tm().reTransact(
() ->
tm()
.createQueryComposer(ReservedListEntry.class)

View File

@@ -47,7 +47,7 @@ public class ReservedListDao {
* exists.
*/
public static Optional<ReservedList> getLatestRevision(String reservedListName) {
return tm().transact(
return tm().reTransact(
() ->
tm().query(
"FROM ReservedList WHERE revisionId IN "

View File

@@ -65,7 +65,7 @@ public class ClaimsListDao {
* doesn't exist.
*/
private static ClaimsList getUncached() {
return tm().transact(
return tm().reTransact(
() -> {
Long revisionId =
tm().query("SELECT MAX(revisionId) FROM ClaimsList", Long.class)

View File

@@ -267,7 +267,7 @@ public abstract class PersistenceModule {
name -> overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, name));
overrides.put(
Environment.ISOLATION, TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ.name());
return new JpaTransactionManagerImpl(create(overrides), clock);
return new JpaTransactionManagerImpl(create(overrides), clock, true);
}
@Provides
@@ -283,7 +283,7 @@ public abstract class PersistenceModule {
name -> overrides.put(HIKARI_DS_CLOUD_SQL_INSTANCE, name));
overrides.put(
Environment.ISOLATION, TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ.name());
return new JpaTransactionManagerImpl(create(overrides), clock);
return new JpaTransactionManagerImpl(create(overrides), clock, true);
}
/** Constructs the {@link EntityManagerFactory} instance. */

View File

@@ -33,6 +33,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import com.google.common.flogger.FluentLogger;
import com.google.common.flogger.StackSize;
import google.registry.config.RegistryEnvironment;
import google.registry.model.ImmutableObject;
import google.registry.persistence.JpaRetries;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
@@ -85,13 +86,19 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
// EntityManagerFactory is thread safe.
private final EntityManagerFactory emf;
private final Clock clock;
private final boolean readOnly;
private static final ThreadLocal<TransactionInfo> transactionInfo =
ThreadLocal.withInitial(TransactionInfo::new);
public JpaTransactionManagerImpl(EntityManagerFactory emf, Clock clock) {
public JpaTransactionManagerImpl(EntityManagerFactory emf, Clock clock, boolean readOnly) {
this.emf = emf;
this.clock = clock;
this.readOnly = readOnly;
}
public JpaTransactionManagerImpl(EntityManagerFactory emf, Clock clock) {
this(emf, clock, false);
}
@Override
@@ -158,7 +165,10 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
if (!getHibernateAllowNestedTransactions()) {
throw new IllegalStateException(NESTED_TRANSACTION_MESSAGE);
}
logger.atWarning().withStackTrace(StackSize.MEDIUM).log(NESTED_TRANSACTION_MESSAGE);
if (RegistryEnvironment.get() != RegistryEnvironment.PRODUCTION
&& RegistryEnvironment.get() != RegistryEnvironment.UNITTEST) {
logger.atWarning().withStackTrace(StackSize.MEDIUM).log(NESTED_TRANSACTION_MESSAGE);
}
// This prevents inner transaction from retrying, thus avoiding a cascade retry effect.
return transactNoRetry(work, isolationLevel);
}
@@ -200,6 +210,10 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
try {
txn.begin();
txnInfo.start(clock);
if (readOnly) {
getEntityManager().createNativeQuery("SET TRANSACTION READ ONLY").executeUpdate();
logger.atInfo().log("Using read-only SQL replica");
}
if (isolationLevel != null && isolationLevel != getDefaultTransactionIsolationLevel()) {
getEntityManager()
.createNativeQuery(

View File

@@ -28,6 +28,7 @@ import com.google.common.net.MediaType;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URLConnection;
import java.util.Random;
@@ -36,26 +37,37 @@ public final class UrlConnectionUtils {
private UrlConnectionUtils() {}
/** Retrieves the response from the given connection as a byte array. */
public static byte[] getResponseBytes(URLConnection connection) throws IOException {
try (InputStream is = connection.getInputStream()) {
/**
* Retrieves the response from the given connection as a byte array.
*
* <p>Note that in the event the response code is 4XX or 5XX, we use the error stream as any
* payload is included there.
*
* @see HttpURLConnection#getErrorStream()
*/
public static byte[] getResponseBytes(HttpURLConnection connection) throws IOException {
int responseCode = connection.getResponseCode();
try (InputStream is =
responseCode < 400 ? connection.getInputStream() : connection.getErrorStream()) {
return ByteStreams.toByteArray(is);
} catch (NullPointerException e) {
return new byte[] {};
}
}
/** Sets auth on the given connection with the given username/password. */
public static void setBasicAuth(URLConnection connection, String username, String password) {
public static void setBasicAuth(HttpURLConnection connection, String username, String password) {
setBasicAuth(connection, String.format("%s:%s", username, password));
}
/** Sets auth on the given connection with the given string, formatted "username:password". */
public static void setBasicAuth(URLConnection connection, String usernameAndPassword) {
public static void setBasicAuth(HttpURLConnection connection, String usernameAndPassword) {
String token = base64().encode(usernameAndPassword.getBytes(UTF_8));
connection.setRequestProperty(AUTHORIZATION, "Basic " + token);
}
/** Sets the given byte[] payload on the given connection with a particular content type. */
public static void setPayload(URLConnection connection, byte[] bytes, String contentType)
public static void setPayload(HttpURLConnection connection, byte[] bytes, String contentType)
throws IOException {
connection.setRequestProperty(CONTENT_TYPE, contentType);
connection.setDoOutput(true);
@@ -72,7 +84,7 @@ public final class UrlConnectionUtils {
* @see <a href="http://www.ietf.org/rfc/rfc2388.txt">RFC2388 - Returning Values from Forms</a>
*/
public static void setPayloadMultipart(
URLConnection connection,
HttpURLConnection connection,
String name,
String filename,
MediaType contentType,

View File

@@ -122,6 +122,13 @@ public class ConfigureTldCommand extends MutatingCommand {
checkPremiumList(newTld);
checkDnsWriters(newTld);
checkCurrency(newTld);
// bsaEnrollStartTime only exists in DB. Need to carry it over to the updated copy. See Tld.java
// for more information.
Optional<DateTime> bsaEnrollTime =
Optional.ofNullable(oldTld).flatMap(Tld::getBsaEnrollStartTime);
if (bsaEnrollTime.isPresent()) {
newTld = newTld.asBuilder().setBsaEnrollStartTime(bsaEnrollTime).build();
}
// Set the new TLD to breakglass mode if breakglass flag was used
if (breakglass) {
newTld = newTld.asBuilder().setBreakglassMode(true).build();

View File

@@ -463,8 +463,7 @@ abstract class CreateOrUpdateTldCommand extends MutatingCommand {
}
}
private void checkReservedListValidityForTld(String tld, Set<String> reservedListNames)
throws UnsupportedEncodingException {
private void checkReservedListValidityForTld(String tld, Set<String> reservedListNames) {
ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
for (String reservedListName : reservedListNames) {
if (!reservedListName.startsWith("common_") && !reservedListName.startsWith(tld + "_")) {

View File

@@ -67,9 +67,12 @@ abstract class UpdateOrDeleteAllocationTokensCommand extends ConfirmingCommand {
checkArgument(!prefix.isEmpty(), "Provided prefix should not be blank");
return tm().transact(
() ->
tm().loadAllOf(AllocationToken.class).stream()
.filter(token -> token.getToken().startsWith(prefix))
.map(AllocationToken::createVKey)
tm().query(
"SELECT token FROM AllocationToken WHERE token LIKE :prefix",
String.class)
.setParameter("prefix", String.format("%s%%", prefix))
.getResultStream()
.map(token -> VKey.create(AllocationToken.class, token))
.collect(toImmutableList()));
}
}

View File

@@ -14,6 +14,7 @@
package google.registry.tools;
import static google.registry.util.DiffUtils.prettyPrintEntityDeepDiff;
import static google.registry.util.ListNamingUtils.convertFilePathToName;
import static java.nio.charset.StandardCharsets.UTF_8;
@@ -46,17 +47,27 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
.setReservedListMapFromLines(allLines)
.setShouldPublish(shouldPublish);
reservedList = updated.build();
// only call stageEntityChange if there are changes in entries
if (!existingReservedList
.getReservedListEntries()
.equals(reservedList.getReservedListEntries())) {
return String.format(
"Update reserved list for %s?\nOld list: %s\n New list: %s",
name,
outputReservedListEntries(existingReservedList),
outputReservedListEntries(reservedList));
boolean shouldPublishChanged =
existingReservedList.getShouldPublish() != reservedList.getShouldPublish();
boolean reservedListEntriesChanged =
!existingReservedList
.getReservedListEntries()
.equals(reservedList.getReservedListEntries());
if (!shouldPublishChanged && !reservedListEntriesChanged) {
return "No entity changes to apply.";
}
return "No entity changes to apply.";
String result = String.format("Update reserved list for %s?\n", name);
if (shouldPublishChanged) {
result +=
String.format(
"shouldPublish: %s -> %s\n",
existingReservedList.getShouldPublish(), reservedList.getShouldPublish());
}
if (reservedListEntriesChanged) {
result +=
prettyPrintEntityDeepDiff(
existingReservedList.getReservedListEntries(), reservedList.getReservedListEntries());
}
return result;
}
}

View File

@@ -23,6 +23,7 @@ import static google.registry.util.X509Utils.loadCertificate;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import com.google.common.net.InetAddresses;
import google.registry.flows.TlsCredentials;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.registrar.Registrar;
@@ -85,7 +86,7 @@ final class ValidateLoginCredentialsCommand implements Command {
new TlsCredentials(
true,
Optional.ofNullable(clientCertificateHash),
Optional.ofNullable(clientIpAddress),
Optional.ofNullable(InetAddresses.forString(clientIpAddress)),
certificateChecker)
.validate(registrar, password);
checkState(

View File

@@ -19,6 +19,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Ascii;
import com.google.gson.Gson;
import com.google.gson.annotations.Expose;
import google.registry.model.CreateAutoTimestamp;
@@ -33,6 +34,7 @@ import google.registry.ui.server.registrar.JsonGetAction;
import java.util.List;
import java.util.Optional;
import javax.inject.Inject;
import javax.persistence.TypedQuery;
import org.joda.time.DateTime;
/** Returns a (paginated) list of domains for a particular registrar. */
@@ -49,6 +51,8 @@ public class ConsoleDomainListAction implements JsonGetAction {
private static final String DOMAIN_QUERY_TEMPLATE =
"FROM Domain WHERE currentSponsorRegistrarId = :registrarId AND deletionTime >"
+ " :deletedAfterTime AND creationTime <= :createdBeforeTime";
private static final String SEARCH_TERM_QUERY = " AND LOWER(domainName) LIKE :searchTerm";
private static final String ORDER_BY_STATEMENT = " ORDER BY creationTime DESC";
private final AuthResult authResult;
private final Response response;
@@ -58,6 +62,7 @@ public class ConsoleDomainListAction implements JsonGetAction {
private final int pageNumber;
private final int resultsPerPage;
private final Optional<Long> totalResults;
private final Optional<String> searchTerm;
@Inject
public ConsoleDomainListAction(
@@ -68,7 +73,8 @@ public class ConsoleDomainListAction implements JsonGetAction {
@Parameter("checkpointTime") Optional<DateTime> checkpointTime,
@Parameter("pageNumber") Optional<Integer> pageNumber,
@Parameter("resultsPerPage") Optional<Integer> resultsPerPage,
@Parameter("totalResults") Optional<Long> totalResults) {
@Parameter("totalResults") Optional<Long> totalResults,
@Parameter("searchTerm") Optional<String> searchTerm) {
this.authResult = authResult;
this.response = response;
this.gson = gson;
@@ -77,6 +83,7 @@ public class ConsoleDomainListAction implements JsonGetAction {
this.pageNumber = pageNumber.orElse(0);
this.resultsPerPage = resultsPerPage.orElse(DEFAULT_RESULTS_PER_PAGE);
this.totalResults = totalResults;
this.searchTerm = searchTerm;
}
@Override
@@ -110,13 +117,13 @@ public class ConsoleDomainListAction implements JsonGetAction {
long actualTotalResults =
totalResults.orElseGet(
() ->
tm().query("SELECT COUNT(*) " + DOMAIN_QUERY_TEMPLATE, Long.class)
createCountQuery()
.setParameter("registrarId", registrarId)
.setParameter("createdBeforeTime", checkpointTimestamp)
.setParameter("deletedAfterTime", checkpoint)
.getSingleResult());
List<Domain> domains =
tm().query(DOMAIN_QUERY_TEMPLATE + " ORDER BY creationTime DESC", Domain.class)
createDomainQuery()
.setParameter("registrarId", registrarId)
.setParameter("createdBeforeTime", checkpointTimestamp)
.setParameter("deletedAfterTime", checkpoint)
@@ -127,6 +134,26 @@ public class ConsoleDomainListAction implements JsonGetAction {
response.setStatus(HttpStatusCodes.STATUS_CODE_OK);
}
/** Creates the query to get the total number of matching domains, interpolating as necessary. */
private TypedQuery<Long> createCountQuery() {
String queryString = "SELECT COUNT(*) " + DOMAIN_QUERY_TEMPLATE;
if (searchTerm.isPresent() && !searchTerm.get().isEmpty()) {
return tm().query(queryString + SEARCH_TERM_QUERY, Long.class)
.setParameter("searchTerm", String.format("%%%s%%", Ascii.toLowerCase(searchTerm.get())));
}
return tm().query(queryString, Long.class);
}
/** Creates the query to retrieve the matching domains themselves, interpolating as necessary. */
private TypedQuery<Domain> createDomainQuery() {
if (searchTerm.isPresent() && !searchTerm.get().isEmpty()) {
return tm().query(
DOMAIN_QUERY_TEMPLATE + SEARCH_TERM_QUERY + ORDER_BY_STATEMENT, Domain.class)
.setParameter("searchTerm", String.format("%%%s%%", Ascii.toLowerCase(searchTerm.get())));
}
return tm().query(DOMAIN_QUERY_TEMPLATE + ORDER_BY_STATEMENT, Domain.class);
}
private void writeBadRequest(String message) {
response.setPayload(message);
response.setStatus(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);

View File

@@ -226,4 +226,10 @@ public final class RegistrarConsoleModule {
public static Optional<Long> provideTotalResults(HttpServletRequest req) {
return extractOptionalParameter(req, "totalResults").map(Long::valueOf);
}
@Provides
@Parameter("searchTerm")
public static Optional<String> provideSearchTerm(HttpServletRequest req) {
return extractOptionalParameter(req, "searchTerm");
}
}

View File

@@ -15,38 +15,65 @@
package google.registry.bsa;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.tldconfig.idn.IdnTableEnum.EXTENDED_LATIN;
import static google.registry.tldconfig.idn.IdnTableEnum.JA;
import static google.registry.tldconfig.idn.IdnTableEnum.UNCONFUSABLE_LATIN;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.model.tld.Tld;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationWithCoverageExtension;
import google.registry.testing.FakeClock;
import java.util.Optional;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.junit.jupiter.api.extension.RegisterExtension;
@ExtendWith(MockitoExtension.class)
/** Unit tests for {@link IdnChecker}. */
public class IdnCheckerTest {
@Mock Tld jaonly;
@Mock Tld jandelatin;
@Mock Tld strictlatin;
FakeClock fakeClock = new FakeClock();
@RegisterExtension
final JpaIntegrationWithCoverageExtension jpa =
new JpaTestExtensions.Builder().withClock(fakeClock).buildIntegrationWithCoverageExtension();
Tld jaonly;
Tld jandelatin;
Tld strictlatin;
IdnChecker idnChecker;
@BeforeEach
void setup() {
idnChecker =
new IdnChecker(
ImmutableMap.of(
JA,
ImmutableSet.of(jandelatin, jaonly),
EXTENDED_LATIN,
ImmutableSet.of(jandelatin),
UNCONFUSABLE_LATIN,
ImmutableSet.of(strictlatin)));
jaonly = createTld("jaonly");
jandelatin = createTld("jandelatin");
strictlatin = createTld("strictlatin");
jaonly =
persistResource(
jaonly
.asBuilder()
.setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc()))
.setIdnTables(ImmutableSet.of(JA))
.build());
jandelatin =
persistResource(
jandelatin
.asBuilder()
.setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc()))
.setIdnTables(ImmutableSet.of(JA, EXTENDED_LATIN))
.build());
strictlatin =
persistResource(
strictlatin
.asBuilder()
.setBsaEnrollStartTime(Optional.of(fakeClock.nowUtc()))
.setIdnTables(ImmutableSet.of(UNCONFUSABLE_LATIN))
.build());
fakeClock.advanceOneMilli();
idnChecker = new IdnChecker(fakeClock);
}
@Test

View File

@@ -23,6 +23,7 @@ import static google.registry.util.X509Utils.getCertificateHash;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.net.InetAddresses;
import google.registry.flows.certs.CertificateChecker;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
@@ -66,7 +67,7 @@ class EppLoginTlsTest extends EppTestCase {
new TlsCredentials(
true,
Optional.ofNullable(clientCertificateHash),
Optional.of("192.168.1.100:54321"),
Optional.of(InetAddresses.forString("192.168.1.100")),
certificateChecker));
}

View File

@@ -43,7 +43,6 @@ import google.registry.persistence.VKey;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeHttpSession;
import google.registry.testing.FakeResponse;
import google.registry.util.ProxyHttpHeaders;
import java.util.Map;
import java.util.Objects;
import java.util.Optional;
@@ -126,10 +125,6 @@ public class EppTestCase {
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Check that the logged-in header was added to the response
assertThat(response.getHeaders())
.isEqualTo(ImmutableMap.of(ProxyHttpHeaders.LOGGED_IN, "true"));
verifyAndReturnOutput(response.getPayload(), expectedOutput, inputFilename, outputFilename);
}
@@ -146,10 +141,6 @@ public class EppTestCase {
setUpSession();
FakeResponse response = executeXmlCommand(input);
// Checks that the Logged-In header is not in the response. If testing the login command, use
// assertLoginCommandAndResponse instead of this method.
assertThat(response.getHeaders()).doesNotContainEntry(ProxyHttpHeaders.LOGGED_IN, "true");
return verifyAndReturnOutput(
response.getPayload(), expectedOutput, inputFilename, outputFilename);
}

View File

@@ -30,6 +30,7 @@ import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.net.InetAddresses;
import com.google.common.testing.TestLogHandler;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.eppcommon.Trid;
@@ -186,7 +187,10 @@ class FlowRunnerTest {
void testRun_loggingStatement_tlsCredentials() throws Exception {
flowRunner.credentials =
new TlsCredentials(
true, Optional.of("abc123def"), Optional.of("127.0.0.1"), certificateChecker);
true,
Optional.of("abc123def"),
Optional.of(InetAddresses.forString("127.0.0.1")),
certificateChecker);
flowRunner.run(eppMetricBuilder);
assertThat(Splitter.on("\n\t").split(findFirstLogMessageByPrefix(handler, "EPP Command\n\t")))
.contains("TlsCredentials{clientCertificateHash=abc123def," + " clientAddress=/127.0.0.1}");

View File

@@ -27,6 +27,7 @@ import static org.mockito.Mockito.when;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedMap;
import com.google.common.net.InetAddresses;
import google.registry.flows.TlsCredentials.BadRegistrarIpAddressException;
import google.registry.flows.TlsCredentials.MissingRegistrarCertificateException;
import google.registry.flows.TlsCredentials.RegistrarCertificateNotConfiguredException;
@@ -71,7 +72,11 @@ final class TlsCredentialsTest {
@Test
void testClientCertificateAndHash_missing() {
TlsCredentials tls =
new TlsCredentials(true, Optional.empty(), Optional.of("192.168.1.1"), certificateChecker);
new TlsCredentials(
true,
Optional.empty(),
Optional.of(InetAddresses.forString("192.168.1.1")),
certificateChecker);
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
@@ -83,10 +88,13 @@ final class TlsCredentialsTest {
}
@Test
void test_missingIpAddress_doesntAllowAccess() {
void test_wrongIpAddress_doesntAllowAccess() {
TlsCredentials tls =
new TlsCredentials(
false, Optional.of("certHash"), Optional.of("127.0.0.1"), certificateChecker);
false,
Optional.of("certHash"),
Optional.of(InetAddresses.forString("127.0.0.1")),
certificateChecker);
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
@@ -104,11 +112,33 @@ final class TlsCredentialsTest {
.isEqualTo("Registrar IP address 127.0.0.1 is not in stored allow list");
}
@Test
void test_missingIpAddress_doesntAllowAccess() {
TlsCredentials tls =
new TlsCredentials(false, Optional.of("certHash"), Optional.empty(), certificateChecker);
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
.setClientCertificate(SAMPLE_CERT, clock.nowUtc())
.setIpAddressAllowList(ImmutableSet.of(CidrAddressBlock.create("3.5.8.13")))
.build());
BadRegistrarIpAddressException thrown =
assertThrows(
BadRegistrarIpAddressException.class,
() -> tls.validate(Registrar.loadByRegistrarId("TheRegistrar").get(), "password"));
assertThat(thrown).hasMessageThat().isEqualTo("Registrar IP address is missing");
}
@Test
void testClientCertificate_notConfigured() {
TlsCredentials tls =
new TlsCredentials(
true, Optional.of("hash"), Optional.of("192.168.1.1"), certificateChecker);
true,
Optional.of("hash"),
Optional.of(InetAddresses.forString("192.168.1.1")),
certificateChecker);
persistResource(loadRegistrar("TheRegistrar").asBuilder().build());
assertThrows(
RegistrarCertificateNotConfiguredException.class,
@@ -119,7 +149,10 @@ final class TlsCredentialsTest {
void test_validateCertificateHash_canBeConfiguredToBypassCerts() throws Exception {
TlsCredentials tls =
new TlsCredentials(
false, Optional.of("certHash"), Optional.of("192.168.1.1"), certificateChecker);
false,
Optional.of("certHash"),
Optional.of(InetAddresses.forString("192.168.1.1")),
certificateChecker);
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()
@@ -134,7 +167,10 @@ final class TlsCredentialsTest {
void test_validateCertificateHash_passWithFailOverCerticate() throws Exception {
TlsCredentials tls =
new TlsCredentials(
false, Optional.of(SAMPLE_CERT_HASH), Optional.of("192.168.1.1"), certificateChecker);
false,
Optional.of(SAMPLE_CERT_HASH),
Optional.of(InetAddresses.forString("192.168.1.1")),
certificateChecker);
persistResource(
loadRegistrar("TheRegistrar")
.asBuilder()

View File

@@ -340,6 +340,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
new AllocationToken.Builder()
.setToken("abc123")
.setTokenType(UNLIMITED_USE)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setDiscountFraction(0.5)
.setDiscountYears(2)
.setTokenStatusTransitions(
@@ -364,6 +365,7 @@ class DomainCheckFlowTest extends ResourceCheckFlowTestCase<DomainCheckFlow, Dom
.setTokenType(UNLIMITED_USE)
.setDiscountFraction(0.5)
.setDiscountYears(2)
.setAllowedEppActions(ImmutableSet.of(CommandName.CREATE))
.setTokenStatusTransitions(
ImmutableSortedMap.<DateTime, TokenStatus>naturalOrder()
.put(START_OF_TIME, TokenStatus.NOT_STARTED)

View File

@@ -30,6 +30,7 @@ import google.registry.flows.certs.CertificateChecker;
import google.registry.model.registrar.Registrar;
import google.registry.testing.CertificateSamples;
import google.registry.util.CidrAddressBlock;
import java.net.InetAddress;
import java.util.Optional;
import org.joda.time.DateTime;
import org.junit.jupiter.api.Test;
@@ -42,10 +43,14 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
Optional.of(CertificateSamples.SAMPLE_CERT3_HASH);
private static final Optional<String> BAD_CERT_HASH =
Optional.of(CertificateSamples.SAMPLE_CERT2_HASH);
private static final Optional<String> GOOD_IP = Optional.of("192.168.1.1");
private static final Optional<String> BAD_IP = Optional.of("1.1.1.1");
private static final Optional<String> GOOD_IPV6 = Optional.of("2001:db8::1");
private static final Optional<String> BAD_IPV6 = Optional.of("2001:db8::2");
private static final Optional<InetAddress> GOOD_IP =
Optional.of(InetAddresses.forString("192.168.1.1"));
private static final Optional<InetAddress> BAD_IP =
Optional.of(InetAddresses.forString("1.1.1.1"));
private static final Optional<InetAddress> GOOD_IPV6 =
Optional.of(InetAddresses.forString("2001:db8::1"));
private static final Optional<InetAddress> BAD_IPV6 =
Optional.of(InetAddresses.forString("2001:db8::2"));
private final CertificateChecker certificateChecker =
new CertificateChecker(
ImmutableSortedMap.of(START_OF_TIME, 825, DateTime.parse("2020-09-01T00:00:00Z"), 398),
@@ -59,8 +64,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
protected Registrar.Builder getRegistrarBuilder() {
return super.getRegistrarBuilder()
.setClientCertificate(GOOD_CERT.get(), DateTime.now(UTC))
.setIpAddressAllowList(
ImmutableList.of(CidrAddressBlock.create(InetAddresses.forString(GOOD_IP.get()), 32)));
.setIpAddressAllowList(ImmutableList.of(CidrAddressBlock.create(GOOD_IP.get(), 32)));
}
@Test
@@ -129,7 +133,7 @@ public class LoginFlowViaTlsTest extends LoginFlowTestCase {
CidrAddressBlock.create(InetAddresses.forString("192.168.1.1"), 32),
CidrAddressBlock.create(InetAddresses.forString("2001:db8::1"), 128)))
.build());
credentials = new TlsCredentials(true, GOOD_CERT_HASH, GOOD_CERT, certificateChecker);
credentials = new TlsCredentials(true, GOOD_CERT_HASH, Optional.empty(), certificateChecker);
doFailingTest("login_valid.xml", BadRegistrarIpAddressException.class);
}

View File

@@ -219,10 +219,10 @@ public abstract class JpaTransactionManagerExtension
recreateSchema();
}
JpaTransactionManagerImpl txnManager = new JpaTransactionManagerImpl(emf, clock);
JpaTransactionManagerImpl readOnlyTxnManager = new JpaTransactionManagerImpl(emf, clock, true);
cachedTm = TransactionManagerFactory.tm();
TransactionManagerFactory.setJpaTm(Suppliers.ofInstance(txnManager));
TransactionManagerFactory.setReplicaJpaTm(
Suppliers.ofInstance(new ReplicaSimulatingJpaTransactionManager(txnManager)));
TransactionManagerFactory.setReplicaJpaTm(Suppliers.ofInstance(readOnlyTxnManager));
// Reset SQL Sequence based id allocation so that ids are deterministic in tests.
TransactionManagerFactory.tm()
.transact(

View File

@@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_READ_COMMITTED;
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_READ_UNCOMMITTED;
import static google.registry.persistence.PersistenceModule.TransactionIsolationLevel.TRANSACTION_REPEATABLE_READ;
import static google.registry.persistence.transaction.TransactionManagerFactory.replicaTm;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.assertDetachedFromEntityManager;
import static google.registry.testing.DatabaseHelper.existsInDb;
@@ -107,6 +108,44 @@ class JpaTransactionManagerImplTest {
assertCompanyExist("Bar");
}
@Test
void transact_replica_failureOnWrite() {
assertPersonEmpty();
assertCompanyEmpty();
DatabaseException thrown =
assertThrows(
DatabaseException.class,
() ->
replicaTm()
.transact(
() -> {
insertPerson(10);
}));
assertThat(thrown)
.hasMessageThat()
.contains("cannot execute INSERT in a read-only transaction");
}
@Test
void transact_replica_successOnRead() {
assertPersonEmpty();
assertCompanyEmpty();
tm().transact(
() -> {
insertPerson(10);
});
replicaTm()
.transact(
() -> {
EntityManager em = replicaTm().getEntityManager();
Integer maybeAge =
(Integer)
em.createNativeQuery("SELECT age FROM Person WHERE age = 10")
.getSingleResult();
assertThat(maybeAge).isEqualTo(10);
});
}
@Test
void transact_setIsolationLevel() {
// If not specified, run at the default isolation level.

View File

@@ -1,289 +0,0 @@
// 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.
package google.registry.persistence.transaction;
import static com.google.common.base.Throwables.throwIfUnchecked;
import static google.registry.persistence.transaction.DatabaseException.throwIfSqlException;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import google.registry.model.ImmutableObject;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
import google.registry.persistence.VKey;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.stream.Stream;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import javax.persistence.criteria.CriteriaQuery;
import org.joda.time.DateTime;
/**
* A {@link JpaTransactionManager} that simulates a read-only replica SQL instance.
*
* <p>We accomplish this by delegating all calls to the standard transaction manager except for
* calls that start transactions. For these, we create a transaction like normal but set it to READ
* ONLY mode before doing any work. This is similar to how the read-only Postgres replica works; it
* treats all transactions as read-only transactions.
*/
public class ReplicaSimulatingJpaTransactionManager implements JpaTransactionManager {
private final JpaTransactionManager delegate;
public ReplicaSimulatingJpaTransactionManager(JpaTransactionManager delegate) {
this.delegate = delegate;
}
@Override
public void teardown() {
delegate.teardown();
}
@Override
public TransactionIsolationLevel getDefaultTransactionIsolationLevel() {
return delegate.getDefaultTransactionIsolationLevel();
}
@Override
public TransactionIsolationLevel getCurrentTransactionIsolationLevel() {
return delegate.getCurrentTransactionIsolationLevel();
}
@Override
public EntityManager getStandaloneEntityManager() {
return delegate.getStandaloneEntityManager();
}
@Override
public EntityManager getEntityManager() {
return delegate.getEntityManager();
}
@Override
public <T> TypedQuery<T> query(String sqlString, Class<T> resultClass) {
return delegate.query(sqlString, resultClass);
}
@Override
public <T> TypedQuery<T> criteriaQuery(CriteriaQuery<T> criteriaQuery) {
return delegate.criteriaQuery(criteriaQuery);
}
@Override
public Query query(String sqlString) {
return delegate.query(sqlString);
}
@Override
public boolean inTransaction() {
return delegate.inTransaction();
}
@Override
public void assertInTransaction() {
delegate.assertInTransaction();
}
@Override
public <T> T transact(Callable<T> work, TransactionIsolationLevel isolationLevel) {
if (inTransaction()) {
try {
return work.call();
} catch (Exception e) {
throwIfSqlException(e);
throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
return delegate.transact(
() -> {
delegate
.getEntityManager()
.createNativeQuery("SET TRANSACTION READ ONLY")
.executeUpdate();
return work.call();
},
isolationLevel);
}
@Override
public <T> T reTransact(Callable<T> work) {
return transact(work);
}
@Override
public <T> T transact(Callable<T> work) {
return transact(work, null);
}
@Override
public void transact(ThrowingRunnable work, TransactionIsolationLevel isolationLevel) {
transact(
() -> {
work.run();
return null;
},
isolationLevel);
}
@Override
public void reTransact(ThrowingRunnable work) {
transact(work);
}
@Override
public void transact(ThrowingRunnable work) {
transact(work, null);
}
@Override
public DateTime getTransactionTime() {
return delegate.getTransactionTime();
}
@Override
public void insert(Object entity) {
delegate.insert(entity);
}
@Override
public void insertAll(ImmutableCollection<?> entities) {
delegate.insertAll(entities);
}
@Override
public void insertAll(ImmutableObject... entities) {
delegate.insertAll(entities);
}
@Override
public void put(Object entity) {
delegate.put(entity);
}
@Override
public void putAll(ImmutableObject... entities) {
delegate.putAll(entities);
}
@Override
public void putAll(ImmutableCollection<?> entities) {
delegate.putAll(entities);
}
@Override
public void update(Object entity) {
delegate.update(entity);
}
@Override
public void updateAll(ImmutableCollection<?> entities) {
delegate.updateAll(entities);
}
@Override
public void updateAll(ImmutableObject... entities) {
delegate.updateAll(entities);
}
@Override
public <T> boolean exists(VKey<T> key) {
return delegate.exists(key);
}
@Override
public boolean exists(Object entity) {
return delegate.exists(entity);
}
@Override
public <T> Optional<T> loadByKeyIfPresent(VKey<T> key) {
return delegate.loadByKeyIfPresent(key);
}
@Override
public <T> ImmutableMap<VKey<? extends T>, T> loadByKeysIfPresent(
Iterable<? extends VKey<? extends T>> vKeys) {
return delegate.loadByKeysIfPresent(vKeys);
}
@Override
public <T> ImmutableList<T> loadByEntitiesIfPresent(Iterable<T> entities) {
return delegate.loadByEntitiesIfPresent(entities);
}
@Override
public <T> T loadByKey(VKey<T> key) {
return delegate.loadByKey(key);
}
@Override
public <T> ImmutableMap<VKey<? extends T>, T> loadByKeys(
Iterable<? extends VKey<? extends T>> vKeys) {
return delegate.loadByKeys(vKeys);
}
@Override
public <T> T loadByEntity(T entity) {
return delegate.loadByEntity(entity);
}
@Override
public <T> ImmutableList<T> loadByEntities(Iterable<T> entities) {
return delegate.loadByEntities(entities);
}
@Override
public <T> ImmutableList<T> loadAllOf(Class<T> clazz) {
return delegate.loadAllOf(clazz);
}
@Override
public <T> Stream<T> loadAllOfStream(Class<T> clazz) {
return delegate.loadAllOfStream(clazz);
}
@Override
public <T> Optional<T> loadSingleton(Class<T> clazz) {
return delegate.loadSingleton(clazz);
}
@Override
public void delete(VKey<?> key) {
delegate.delete(key);
}
@Override
public void delete(Iterable<? extends VKey<?>> vKeys) {
delegate.delete(vKeys);
}
@Override
public <T> T delete(T entity) {
return delegate.delete(entity);
}
@Override
public <T> QueryComposer<T> createQueryComposer(Class<T> entity) {
return delegate.createQueryComposer(entity);
}
@Override
public <T> void assertDelete(VKey<T> key) {
delegate.assertDelete(key);
}
}

View File

@@ -263,7 +263,7 @@ public class RdeReportActionTest {
@Test
void testRunWithLock_badRequest_throws500WithErrorInfo() throws Exception {
when(httpUrlConnection.getResponseCode()).thenReturn(STATUS_CODE_BAD_REQUEST);
when(httpUrlConnection.getInputStream()).thenReturn(IIRDEA_BAD_XML.openBufferedStream());
when(httpUrlConnection.getErrorStream()).thenReturn(IIRDEA_BAD_XML.openBufferedStream());
InternalServerErrorException thrown =
assertThrows(
InternalServerErrorException.class,

View File

@@ -99,10 +99,10 @@ class IcannHttpReporterTest {
@Test
void testFail_BadIirdeaResponse() throws Exception {
when(connection.getInputStream()).thenReturn(IIRDEA_BAD_XML.openBufferedStream());
when(connection.getResponseCode()).thenReturn(STATUS_CODE_BAD_REQUEST);
when(connection.getErrorStream()).thenReturn(IIRDEA_BAD_XML.openBufferedStream());
assertThat(reporter.send(FAKE_PAYLOAD, "test-transactions-201706.csv")).isFalse();
verify(connection).getInputStream();
verify(connection).getErrorStream();
}
@Test

View File

@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.Arrays;
import java.util.List;
@@ -104,4 +105,21 @@ public class UrlConnectionUtilsTest {
"Multipart data contains autogenerated boundary: "
+ "------------------------------AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
}
@Test
void testErrorStream() throws Exception {
HttpsURLConnection connection = mock(HttpsURLConnection.class);
when(connection.getResponseCode()).thenReturn(400);
when(connection.getErrorStream())
.thenReturn(new ByteArrayInputStream("Failure".getBytes(UTF_8)));
assertThat(UrlConnectionUtils.getResponseBytes(connection))
.isEqualTo("Failure".getBytes(UTF_8));
}
@Test
void testErrorStream_null() throws Exception {
HttpsURLConnection connection = mock(HttpsURLConnection.class);
when(connection.getResponseCode()).thenReturn(400);
assertThat(UrlConnectionUtils.getResponseBytes(connection)).isEmpty();
}
}

View File

@@ -108,6 +108,8 @@ class NordnUploadActionTest {
void beforeEach() throws Exception {
when(httpUrlConnection.getInputStream())
.thenReturn(new ByteArrayInputStream("Success".getBytes(UTF_8)));
when(httpUrlConnection.getErrorStream())
.thenReturn(new ByteArrayInputStream("Failure".getBytes(UTF_8)));
when(httpUrlConnection.getResponseCode()).thenReturn(SC_ACCEPTED);
when(httpUrlConnection.getHeaderField(LOCATION)).thenReturn("http://trololol");
when(httpUrlConnection.getOutputStream()).thenReturn(connectionOutputStream);

View File

@@ -14,9 +14,9 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth8.assertThat;
import static google.registry.model.EntityYamlUtils.createObjectMapper;
import static google.registry.model.domain.token.AllocationToken.TokenType.DEFAULT_PROMO;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistPremiumList;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -46,6 +46,7 @@ import google.registry.model.tld.Tld.TldNotFoundException;
import google.registry.model.tld.label.PremiumList;
import google.registry.model.tld.label.PremiumListDao;
import java.io.File;
import java.util.Optional;
import java.util.logging.Logger;
import org.joda.money.Money;
import org.joda.time.DateTime;
@@ -101,20 +102,19 @@ public class ConfigureTldCommandTest extends CommandTestCase<ConfigureTldCommand
assertThat(updatedTld.getCreateBillingCost()).isEqualTo(Money.of(USD, 25));
testTldConfiguredSuccessfully(updatedTld, "tld.yaml");
assertThat(updatedTld.getBreakglassMode()).isFalse();
assertThat(tld.getBsaEnrollStartTime()).isNull();
assertThat(tld.getBsaEnrollStartTime()).isEmpty();
}
@Test
void testSuccess_updateTld_bsaTimeUnaffected() throws Exception {
void testSuccess_updateTld_existingBsaTimeCarriedOver() throws Exception {
Tld tld = createTld("tld");
DateTime bsaStartTime = DateTime.now(DateTimeZone.UTC);
tm().transact(() -> tm().put(tld.asBuilder().setBsaEnrollStartTime(bsaStartTime).build()));
persistResource(tld.asBuilder().setBsaEnrollStartTime(Optional.of(bsaStartTime)).build());
File tldFile = tmpDir.resolve("tld.yaml").toFile();
Files.asCharSink(tldFile, UTF_8).write(loadFile(getClass(), "tld.yaml"));
runCommandForced("--input=" + tldFile);
// TODO(11/30/2023): uncomment below two lines
// Tld updatedTld = Tld.get("tld");
// assertThat(tld.getBsaEnrollStartTime()).isEqualTo(bsaStartTime);
Tld updatedTld = Tld.get("tld");
assertThat(updatedTld.getBsaEnrollStartTime()).hasValue(bsaStartTime);
}
@Test

View File

@@ -53,6 +53,7 @@ abstract class CreateOrUpdateReservedListCommandTestCase<
.write("sdfgagmsdgs,sdfgsd\nasdf234tafgs,asdfaw\n\n");
reservedTermsPath = reservedTermsFile.getPath();
invalidReservedTermsPath = invalidReservedTermsFile.getPath();
command.printStream = System.out;
}
@Test

View File

@@ -66,6 +66,8 @@ class UpdateReservedListCommandTest
assertThat(ReservedList.get("xn--q9jyb4c_common-reserved")).isPresent();
ReservedList reservedList = ReservedList.get("xn--q9jyb4c_common-reserved").get();
assertThat(reservedList.getShouldPublish()).isFalse();
assertInStdout("Update reserved list for xn--q9jyb4c_common-reserved?");
assertInStdout("shouldPublish: true -> false");
}
@Test
@@ -85,6 +87,10 @@ class UpdateReservedListCommandTest
assertThat(reservedList.getReservationInList("baddies")).hasValue(FULLY_BLOCKED);
assertThat(reservedList.getReservationInList("ford")).hasValue(FULLY_BLOCKED);
assertThat(reservedList.getReservationInList("helicopter")).isEmpty();
assertInStdout("Update reserved list for xn--q9jyb4c_common-reserved?");
assertInStdout("helicopter: helicopter,FULLY_BLOCKED -> null");
assertInStdout("baddies: null -> baddies,FULLY_BLOCKED");
assertInStdout("ford: null -> ford,FULLY_BLOCKED # random comment");
}
@Test
@@ -127,11 +133,13 @@ class UpdateReservedListCommandTest
// CreateOrUpdateReservedListCommandTestCases.java
UpdateReservedListCommand command = new UpdateReservedListCommand();
command.input = Paths.get(reservedTermsPath);
command.shouldPublish = false;
command.init();
assertThat(command.prompt()).contains("Update reserved list for xn--q9jyb4c_common-reserved?");
assertThat(command.prompt()).contains("Old list: [(helicopter,FULLY_BLOCKED)]");
assertThat(command.prompt())
.contains("New list: [(baddies,FULLY_BLOCKED), (ford,FULLY_BLOCKED # random comment)]");
assertThat(command.prompt()).contains("shouldPublish: true -> false");
assertThat(command.prompt()).contains("helicopter: helicopter,FULLY_BLOCKED -> null");
assertThat(command.prompt()).contains("baddies: null -> baddies,FULLY_BLOCKED");
assertThat(command.prompt()).contains("ford: null -> ford,FULLY_BLOCKED # random comment");
}
}

View File

@@ -21,6 +21,7 @@ import static google.registry.testing.DatabaseHelper.persistActiveDomain;
import static google.registry.testing.DatabaseHelper.persistDomainAsDeleted;
import com.google.api.client.http.HttpStatusCodes;
import com.google.common.collect.Iterables;
import com.google.gson.Gson;
import google.registry.model.EppResourceUtils;
import google.registry.model.console.GlobalRole;
@@ -90,7 +91,7 @@ public class ConsoleDomainListActionTest {
@Test
void testSuccess_pages() {
// Two pages of results should go in reverse chronological order
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, null);
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
@@ -98,7 +99,7 @@ public class ConsoleDomainListActionTest {
assertThat(result.totalResults).isEqualTo(10);
// Now do the second page
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, 10L);
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, 10L, null);
action.run();
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
@@ -107,7 +108,7 @@ public class ConsoleDomainListActionTest {
@Test
void testSuccess_partialPage() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 1, 8, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 1, 8, null, null);
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
@@ -116,7 +117,7 @@ public class ConsoleDomainListActionTest {
@Test
void testSuccess_checkpointTime_createdBefore() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 10, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 10, null, null);
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
@@ -127,7 +128,7 @@ public class ConsoleDomainListActionTest {
persistActiveDomain("newdomain.tld", clock.nowUtc());
// Even though we persisted a new domain, the old checkpoint should return no more results
action = createAction("TheRegistrar", result.checkpointTime, 1, 10, null);
action = createAction("TheRegistrar", result.checkpointTime, 1, 10, null, null);
action.run();
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
@@ -136,7 +137,7 @@ public class ConsoleDomainListActionTest {
@Test
void testSuccess_checkpointTime_deletion() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, null);
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
@@ -146,16 +147,50 @@ public class ConsoleDomainListActionTest {
persistDomainAsDeleted(toDelete, clock.nowUtc());
// Second page should include the domain that is now deleted due to the checkpoint time
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, null);
action = createAction("TheRegistrar", result.checkpointTime, 1, 5, null, null);
action.run();
result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains.stream().map(Domain::getDomainName).collect(toImmutableList()))
.containsExactly("4exists.tld", "3exists.tld", "2exists.tld", "1exists.tld", "0exists.tld");
}
@Test
void testSuccess_searchTerm_oneMatch() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "0");
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(Iterables.getOnlyElement(result.domains).getDomainName()).isEqualTo("0exists.tld");
}
@Test
void testSuccess_searchTerm_returnsNone() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "deleted");
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
}
@Test
void testSuccess_searchTerm_caseInsensitive() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "eXiStS");
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(5);
assertThat(result.totalResults).isEqualTo(10);
}
@Test
void testSuccess_searchTerm_tld() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 5, null, "tld");
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).hasSize(5);
assertThat(result.totalResults).isEqualTo(10);
}
@Test
void testPartialSuccess_pastEnd() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 5, 5, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 5, 5, null, null);
action.run();
DomainListResult result = GSON.fromJson(response.getPayload(), DomainListResult.class);
assertThat(result.domains).isEmpty();
@@ -163,13 +198,13 @@ public class ConsoleDomainListActionTest {
@Test
void testFailure_invalidResultsPerPage() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 0, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, 0, 0, null, null);
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
assertThat(response.getPayload())
.isEqualTo("Results per page must be between 1 and 500 inclusive");
action = createAction("TheRegistrar", null, 0, 501, null);
action = createAction("TheRegistrar", null, 0, 501, null, null);
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
assertThat(response.getPayload())
@@ -178,14 +213,14 @@ public class ConsoleDomainListActionTest {
@Test
void testFailure_invalidPageNumber() {
ConsoleDomainListAction action = createAction("TheRegistrar", null, -1, 10, null);
ConsoleDomainListAction action = createAction("TheRegistrar", null, -1, 10, null, null);
action.run();
assertThat(response.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_BAD_REQUEST);
assertThat(response.getPayload()).isEqualTo("Page number must be non-negative");
}
private ConsoleDomainListAction createAction(String registrarId) {
return createAction(registrarId, null, null, null, null);
return createAction(registrarId, null, null, null, null, null);
}
private ConsoleDomainListAction createAction(
@@ -193,7 +228,8 @@ public class ConsoleDomainListActionTest {
@Nullable DateTime checkpointTime,
@Nullable Integer pageNumber,
@Nullable Integer resultsPerPage,
@Nullable Long totalResults) {
@Nullable Long totalResults,
@Nullable String searchTerm) {
response = new FakeResponse();
AuthResult authResult =
AuthResult.createUser(
@@ -210,6 +246,7 @@ public class ConsoleDomainListActionTest {
Optional.ofNullable(checkpointTime),
Optional.ofNullable(pageNumber),
Optional.ofNullable(resultsPerPage),
Optional.ofNullable(totalResults));
Optional.ofNullable(totalResults),
Optional.ofNullable(searchTerm));
}
}

View File

@@ -34,6 +34,24 @@
<fee:command>create</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
<fee:domain>
<fee:name>example1.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
<fee:domain>
<fee:name>example2.example</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
<fee:domain>
<fee:name>reserved.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
</fee:domain>
</fee:check>
</extension>
<clTRID>ABC-12345</clTRID>

View File

@@ -42,6 +42,28 @@
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
<fee:cd>
<fee:name>example1.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:fee description="renew">11.00</fee:fee>
<fee:class>premium</fee:class>
</fee:cd>
<fee:cd>
<fee:name>example2.example</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
<fee:cd>
<fee:name>reserved.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
</fee:chkData>
</extension>
<trID>

View File

@@ -41,6 +41,27 @@
<fee:period unit="y">1</fee:period>
<fee:class>reserved</fee:class>
</fee:cd>
<fee:cd>
<fee:name>example1.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
<fee:cd>
<fee:name>example2.example</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
<fee:cd>
<fee:name>reserved.tld</fee:name>
<fee:currency>USD</fee:currency>
<fee:command>renew</fee:command>
<fee:period unit="y">1</fee:period>
<fee:class>token-not-supported</fee:class>
</fee:cd>
</fee:chkData>
</extension>
<trID>

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -148,3 +148,5 @@ V147__drop_gaia_id_from_user.sql
V148__add_bsa_download_and_label_tables.sql
V149__add_bsa_domain_in_use_table.sql
V150__add_tld_bsa_enroll_date.sql
V151__add_bsa_unblockable_domain_table.sql
V152__add_bsa_domain_refresh_table.sql

View File

@@ -0,0 +1,27 @@
-- 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.
CREATE TABLE "BsaUnblockableDomain" (
label text not null,
tld text not null,
creation_time timestamptz not null,
reason text not null,
primary key (label, tld)
);
ALTER TABLE IF EXISTS "BsaUnblockableDomain"
ADD CONSTRAINT FKbsaunblockabledomainlabel
FOREIGN KEY (label)
REFERENCES "BsaLabel" (label)
ON DELETE CASCADE;

View File

@@ -0,0 +1,21 @@
-- 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.
CREATE TABLE "BsaDomainRefresh" (
job_id bigserial not null,
creation_time timestamptz not null,
stage text not null,
update_timestamp timestamptz,
primary key (job_id)
);

View File

@@ -728,6 +728,7 @@
auto_renew_grace_period_length interval not null,
automatic_transfer_length interval not null,
breakglass_mode boolean not null,
bsa_enroll_start_time timestamptz,
claims_period_end timestamptz not null,
create_billing_cost_amount numeric(19, 2),
create_billing_cost_currency text,

View File

@@ -135,6 +135,37 @@ CREATE TABLE public."BsaDomainInUse" (
);
--
-- Name: BsaDomainRefresh; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."BsaDomainRefresh" (
job_id bigint NOT NULL,
creation_time timestamp with time zone NOT NULL,
stage text NOT NULL,
update_timestamp timestamp with time zone
);
--
-- Name: BsaDomainRefresh_job_id_seq; Type: SEQUENCE; Schema: public; Owner: -
--
CREATE SEQUENCE public."BsaDomainRefresh_job_id_seq"
START WITH 1
INCREMENT BY 1
NO MINVALUE
NO MAXVALUE
CACHE 1;
--
-- Name: BsaDomainRefresh_job_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: -
--
ALTER SEQUENCE public."BsaDomainRefresh_job_id_seq" OWNED BY public."BsaDomainRefresh".job_id;
--
-- Name: BsaDownload; Type: TABLE; Schema: public; Owner: -
--
@@ -177,6 +208,18 @@ CREATE TABLE public."BsaLabel" (
);
--
-- Name: BsaUnblockableDomain; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."BsaUnblockableDomain" (
label text NOT NULL,
tld text NOT NULL,
creation_time timestamp with time zone NOT NULL,
reason text NOT NULL
);
--
-- Name: ClaimsEntry; Type: TABLE; Schema: public; Owner: -
--
@@ -1210,6 +1253,13 @@ CREATE SEQUENCE public.project_wide_unique_id_seq
CACHE 10;
--
-- Name: BsaDomainRefresh job_id; Type: DEFAULT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BsaDomainRefresh" ALTER COLUMN job_id SET DEFAULT nextval('public."BsaDomainRefresh_job_id_seq"'::regclass);
--
-- Name: BsaDownload job_id; Type: DEFAULT; Schema: public; Owner: -
--
@@ -1327,6 +1377,14 @@ ALTER TABLE ONLY public."BsaDomainInUse"
ADD CONSTRAINT "BsaDomainInUse_pkey" PRIMARY KEY (label, tld);
--
-- Name: BsaDomainRefresh BsaDomainRefresh_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BsaDomainRefresh"
ADD CONSTRAINT "BsaDomainRefresh_pkey" PRIMARY KEY (job_id);
--
-- Name: BsaDownload BsaDownload_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -1343,6 +1401,14 @@ ALTER TABLE ONLY public."BsaLabel"
ADD CONSTRAINT "BsaLabel_pkey" PRIMARY KEY (label);
--
-- Name: BsaUnblockableDomain BsaUnblockableDomain_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BsaUnblockableDomain"
ADD CONSTRAINT "BsaUnblockableDomain_pkey" PRIMARY KEY (label, tld);
--
-- Name: ClaimsEntry ClaimsEntry_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2723,6 +2789,14 @@ ALTER TABLE ONLY public."BsaDomainInUse"
ADD CONSTRAINT fkbsadomaininuse2label FOREIGN KEY (label) REFERENCES public."BsaLabel"(label) ON DELETE CASCADE;
--
-- Name: BsaUnblockableDomain fkbsaunblockabledomainlabel; Type: FK CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."BsaUnblockableDomain"
ADD CONSTRAINT fkbsaunblockabledomainlabel FOREIGN KEY (label) REFERENCES public."BsaLabel"(label) ON DELETE CASCADE;
--
-- Name: DomainTransactionRecord fkcjqe54u72kha71vkibvxhjye7; Type: FK CONSTRAINT; Schema: public; Owner: -
--

View File

@@ -124,6 +124,7 @@ public class EppServiceHandler extends HttpsRelayServiceHandler {
.headers()
.set(ProxyHttpHeaders.CERTIFICATE_HASH, sslClientCertificateHash)
.set(ProxyHttpHeaders.IP_ADDRESS, clientAddress)
.set(ProxyHttpHeaders.FALLBACK_IP_ADDRESS, clientAddress)
.set(HttpHeaderNames.CONTENT_TYPE, EPP_CONTENT_TYPE)
.set(HttpHeaderNames.ACCEPT, EPP_CONTENT_TYPE);
return request;

View File

@@ -100,7 +100,8 @@ public final class TestUtils {
.set(HttpHeaderNames.CONTENT_TYPE, "application/epp+xml")
.set("accept", "application/epp+xml")
.set(ProxyHttpHeaders.CERTIFICATE_HASH, sslClientCertificateHash)
.set(ProxyHttpHeaders.IP_ADDRESS, clientAddress);
.set(ProxyHttpHeaders.IP_ADDRESS, clientAddress)
.set(ProxyHttpHeaders.FALLBACK_IP_ADDRESS, clientAddress);
if (cookies.length != 0) {
request.headers().set("cookie", ClientCookieEncoder.STRICT.encode(cookies));
}

View File

@@ -78,8 +78,8 @@ steps:
grep -e "^backend\|^default\|^bsa\|^pubapi\|^tools" |\
while read line; do echo "${TAG_NAME},$line"; done | tee "$local_map"
num_versions=$(cat "$local_map" | wc -l)
if [ "$num_versions" -ne 4 ]; then
echo "Expecting exactly four active services. Found $num_versions"
if [ "$num_versions" -ne 5 ]; then
echo "Expecting exactly five active services. Found $num_versions"
exit 1
fi
gsutil cp "$local_map" gs://$PROJECT_ID-deployed-tags/nomulus.${_ENV}.tmp

View File

@@ -0,0 +1,322 @@
# This is a Gradle generated file for dependency locking.
# Manual edits can break the build and are not advised.
# This file is expected to be part of source control.
antlr:antlr:2.7.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
aopalliance:aopalliance:1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
args4j:args4j:2.0.23=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.101tec:zkclient:0.10=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.beust:jcommander:1.60=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-annotations:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-core:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.core:jackson-databind:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-toml:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-joda:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml.jackson:jackson-bom:2.15.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.fasterxml:classmate:1.5.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.ben-manes.caffeine:caffeine:2.9.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-api:3.3.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport-zerodep:3.3.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.docker-java:docker-java-transport:3.3.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jffi:1.3.11=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-a64asm:1.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-constants:0.10.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-enxio:0.32.15=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-ffi:2.2.14=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-posix:3.1.17=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-unixsocket:0.38.20=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.android:annotations:4.1.1.4=runtimeClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-appengine:1.35.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-jackson2:2.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-java6:1.35.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client-servlet:1.35.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api-client:google-api-client:1.35.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:gapic-google-cloud-storage-v2:2.22.6-alpha=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1:2.41.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.165.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta2:0.165.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-bigtable-v2:2.26.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsub-v1:1.106.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-pubsublite-v1:1.12.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-database-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-admin-instance-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-spanner-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:grpc-google-common-protos:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1:2.41.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta1:0.165.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigquerystorage-v1beta2:0.165.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-admin-v2:2.26.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-bigtable-v2:2.26.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-datastore-v1:0.107.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-firestore-v1:3.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:1.64.0=compileClasspath,testCompileClasspath
com.google.api.grpc:proto-google-cloud-monitoring-v3:3.24.0=runtimeClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsub-v1:1.106.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-pubsublite-v1:1.12.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-secretmanager-v1beta1:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-database-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-admin-instance-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-spanner-v1:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-storage-v2:2.23.0-alpha=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta2:0.113.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-cloud-tasks-v2beta3:0.113.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-common-protos:2.24.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api.grpc:proto-google-iam-v1:1.18.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:api-common:2.16.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-grpc:2.32.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax-httpjson:2.32.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.api:gax:2.33.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-admin-directory:directory_v1-rev118-1.25.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-appengine:v1-rev20230831-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-bigquery:v2-rev20230520-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20230129-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-dataflow:v1b3-rev20220920-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-dns:v2beta1-rev99-1.25.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-drive:v2-rev393-1.25.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-gmail:v1-rev20220404-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-groupssettings:v1-rev20210624-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-healthcare:v1-rev20230510-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-iamcredentials:v1-rev20211203-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-monitoring:v3-rev20230806-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sheets:v4-rev20230815-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-sqladmin:v1beta4-rev20230831-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.apis:google-api-services-storage:v1-rev20230617-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-api-1.0-sdk:1.9.86=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.appengine:appengine-testing:1.9.86=runtimeClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-credentials:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auth:google-auth-library-oauth2-http:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.service:auto-service-annotations:1.1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value-annotations:1.10.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.auto.value:auto-value:1.10.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigdataoss:gcsio:2.2.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigdataoss:util:2.2.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.datastore:datastore-v1-proto-client:2.16.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:jdbc-socket-factory-core:1.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud.sql:postgres-socket-factory:1.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigquerystorage:2.41.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable-stats:2.26.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-bigtable:2.26.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-grpc:2.22.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core-http:2.21.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-core:2.22.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-firestore:3.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-monitoring:1.82.0=compileClasspath,testCompileClasspath
com.google.cloud:google-cloud-monitoring:3.24.0=runtimeClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsub:1.124.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-pubsublite:1.12.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-secretmanager:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-spanner:6.45.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-storage:2.22.6=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:google-cloud-tasks:2.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:grpc-gcp:1.4.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.cloud:proto-google-cloud-firestore-bundle-v1:3.14.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.findbugs:jsr305:3.0.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.code.gson:gson:2.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.common.html.types:types:1.0.6=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.dagger:dagger:2.48=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.errorprone:error_prone_annotations:2.21.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.escapevelocity:escapevelocity:0.9.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.flatbuffers:flatbuffers-java:1.12.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.flogger:flogger-system-backend:0.7.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.flogger:flogger:0.7.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.flogger:google-extensions:0.7.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.guava:failureaccess:1.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava-parent:32.1.2-jre=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.guava:guava:32.1.2-jre=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.gwt:gwt-user:2.10.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-apache-v2:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-appengine:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-gson:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-jackson2:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client-protobuf:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.http-client:google-http-client:1.43.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.inject.extensions:guice-multibindings:4.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.inject:guice:4.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.j2objc:j2objc-annotations:2.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.jsinterop:jsinterop-annotations:2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.monitoring-client:metrics:1.0.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.monitoring-client:stackdriver:1.0.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client-appengine:1.34.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client-java6:1.34.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client-jetty:1.34.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client-servlet:1.34.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.oauth-client:google-oauth-client:1.34.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java-util:3.23.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.protobuf:protobuf-java:3.23.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.re2j:re2j:1.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.template:soy:2021-02-01=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.google.truth:truth:1.1.5=runtimeClasspath,testRuntimeClasspath
com.googlecode.json-simple:json-simple:1.1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.ibm.icu:icu4j:57.1=compileClasspath,testCompileClasspath
com.ibm.icu:icu4j:73.2=runtimeClasspath,testRuntimeClasspath
com.jcraft:jsch:0.1.55=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.lmax:disruptor:3.4.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.sun.istack:istack-commons-runtime:3.0.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.sun.xml.fastinfoset:FastInfoset:1.2.15=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.thoughtworks.paranamer:paranamer:2.7=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
com.zaxxer:HikariCP:3.4.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-codec:commons-codec:1.15=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
commons-logging:commons-logging:1.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
dnsjava:dnsjava:3.5.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.confluent:common-config:5.3.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.confluent:common-utils:5.3.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.confluent:kafka-avro-serializer:5.3.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.confluent:kafka-schema-registry-client:5.3.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.github.classgraph:classgraph:4.8.104=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.github.java-diff-utils:java-diff-utils:4.12=runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-alts:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-api:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-auth:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-census:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-context:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-core:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-googleapis:1.56.1=runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-grpclb:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty-shaded:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-netty:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf-lite:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-protobuf:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-rls:1.56.1=runtimeClasspath,testRuntimeClasspath
io.grpc:grpc-services:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-stub:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.grpc:grpc-xds:1.56.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-buffer:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http2:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-http:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-codec-socks:4.1.87.Final=runtimeClasspath,testRuntimeClasspath
io.netty:netty-codec:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-common:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-handler-proxy:4.1.87.Final=runtimeClasspath,testRuntimeClasspath
io.netty:netty-handler:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-resolver:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-tcnative-boringssl-static:2.0.52.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-tcnative-classes:2.0.52.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-transport-native-unix-common:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.netty:netty-transport:4.1.87.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-api:0.31.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-exemplar-util:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.0=compileClasspath,testCompileClasspath
io.opencensus:opencensus-contrib-grpc-metrics:0.31.1=runtimeClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-grpc-util:0.31.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-http-util:0.31.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-contrib-resource-util:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-exporter-metrics-util:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-exporter-stats-stackdriver:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-impl-core:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-impl:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.opencensus:opencensus-proto:0.2.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
io.perfmark:perfmark-api:0.26.0=runtimeClasspath,testRuntimeClasspath
javax.activation:activation:1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.activation:javax.activation-api:1.2.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.annotation:javax.annotation-api:1.3.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.annotation:jsr250-api:1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.inject:javax.inject:1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.jdo:jdo2-api:2.3-20090302111651=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.mail:mail:1.5.0-b01=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.persistence:javax.persistence-api:2.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.servlet:servlet-api:2.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.validation:validation-api:1.0.0.GA=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
javax.xml.bind:jaxb-api:2.3.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
jline:jline:1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
joda-time:joda-time:2.10.14=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.bytebuddy:byte-buddy:1.12.18=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
net.java.dev.jna:jna:5.12.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.arrow:arrow-format:5.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.arrow:arrow-memory-core:5.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.arrow:arrow-vector:5.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.avro:avro:1.8.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-fn-execution:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-job-management:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-model-pipeline:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-construction-java:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-core-java:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-google-cloud-dataflow-java:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-runners-java-fn-execution:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-core:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-expansion-service:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-arrow:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-avro:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-google-cloud-platform-core:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-extensions-protobuf:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-fn-execution:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-harness:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-google-cloud-platform:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-sdks-java-io-kafka:2.50.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-grpc-1_54_0:0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.beam:beam-vendor-guava-32_1_2-jre:0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-compress:1.23.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-csv:1.10.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.commons:commons-lang3:3.13.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpclient:4.5.14=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.apache.httpcomponents:httpcore:4.4.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.bouncycastle:bcpg-jdk15on:1.67=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.bouncycastle:bcpkix-jdk15on:1.67=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.bouncycastle:bcprov-jdk15on:1.67=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.checkerframework:checker-compat-qual:2.5.3=compileClasspath,testCompileClasspath
org.checkerframework:checker-compat-qual:2.5.5=runtimeClasspath,testRuntimeClasspath
org.checkerframework:checker-qual:3.33.0=compileClasspath,testCompileClasspath
org.checkerframework:checker-qual:3.35.0=runtimeClasspath,testRuntimeClasspath
org.codehaus.jackson:jackson-core-asl:1.9.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.codehaus.jackson:jackson-mapper-asl:1.9.13=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.codehaus.mojo:animal-sniffer-annotations:1.23=runtimeClasspath,testRuntimeClasspath
org.conscrypt:conscrypt-openjdk-uber:2.5.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-http:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-io:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-security:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-server:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-servlet:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util-ajax:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.eclipse.jetty:jetty-util:9.4.49.v20220914=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.flywaydb:flyway-core:9.22.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:jaxb-runtime:2.3.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.glassfish.jaxb:txw2:2.3.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.gwtproject:gwt-user:2.10.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hamcrest:hamcrest:2.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hibernate.common:hibernate-commons-annotations:5.1.2.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hibernate:hibernate-core:5.6.15.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.hibernate:hibernate-hikaricp:5.6.15.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jboss.logging:jboss-logging:3.4.3.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jboss.spec.javax.transaction:jboss-transaction-api_1.2_spec:1.1.1.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jboss:jandex:2.4.2.Final=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jetbrains:annotations:17.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.joda:joda-money:1.0.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.json:json:20230618=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jsoup:jsoup:1.16.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.jvnet.staxex:stax-ex:1.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-analysis:9.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-commons:9.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-tree:9.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm-util:9.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.ow2.asm:asm:9.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.postgresql:postgresql:42.6.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.rnorth.duct-tape:duct-tape:1.0.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-api:2.0.9=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.slf4j:slf4j-jdk14:2.0.9=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-core:5.3.27=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-expression:5.3.27=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.springframework:spring-jcl:5.3.27=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:database-commons:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:jdbc:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:postgresql:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.testcontainers:testcontainers:1.19.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.threeten:threetenbp:1.6.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.tukaani:xz:1.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.w3c.css:sac:1.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.xerial.snappy:snappy-java:1.1.10.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
org.yaml:snakeyaml:2.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-api:16.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-diagram:16.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-tools:16.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler-utility:16.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
us.fatehi:schemacrawler:16.10.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
xerces:xmlParserAPIs:2.6.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
xpp3:xpp3:1.1.4c=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
empty=annotationProcessor,providedCompile,providedRuntime,testAnnotationProcessor

View File

@@ -19,30 +19,25 @@ import com.google.common.net.HttpHeaders;
/** Utility class of HTTP header names used for HTTP calls between Nomulus and the proxy. */
public final class ProxyHttpHeaders {
/**
* HTTP header name used to pass a full SSL certificate from the proxy to Nomulus.
*
* <p>This header contains the SSL certificate encoded to a string. It is used to pass the client
* certificate used for login to Nomulus for validation.
*/
public static final String FULL_CERTIFICATE = "X-SSL-Full-Certificate";
/** HTTP header name used to pass the certificate hash from the proxy to Nomulus. */
public static final String CERTIFICATE_HASH = "X-SSL-Certificate";
/**
* HTTP header name passed from Nomulus to proxy to indicate that a client has successfully logged
* in.
*/
public static final String LOGGED_IN = "Logged-In";
/**
* HTTP header name passed from Nomulus to proxy to indicate that an EPP session should be closed.
*/
public static final String EPP_SESSION = "Epp-Session";
/** HTTP header name used to pass the client IP address from the proxy to Nomulus. */
public static final String IP_ADDRESS = HttpHeaders.X_FORWARDED_FOR;
public static final String IP_ADDRESS = "Nomulus-Client-Address";
/**
* Fallback HTTP header name used to pass the client IP address from the proxy to Nomulus.
*
* <p>Note that Java 17's servlet implementation (at least on App Engine) injects some seemingly
* unrelated addresses into this header. We only use this as a fallback so the proxy can
* transition to use the above header that should not be interfered with.
*/
public static final String FALLBACK_IP_ADDRESS = HttpHeaders.X_FORWARDED_FOR;
private ProxyHttpHeaders() {}
}