Compare commits
19 Commits
nomulus-20
...
proxy-2025
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8987fd37c2 | ||
|
|
653e092ad4 | ||
|
|
5e97a8b412 | ||
|
|
229fcf3946 | ||
|
|
b775e4a178 | ||
|
|
e3c386a8a7 | ||
|
|
799f0449ad | ||
|
|
bf025445d5 | ||
|
|
9f22f2e8ae | ||
|
|
45c8b81823 | ||
|
|
4cfcc60655 | ||
|
|
e4ee63b8f3 | ||
|
|
f8407c74bc | ||
|
|
693467a165 | ||
|
|
cea3da01a0 | ||
|
|
c2030e5859 | ||
|
|
1cbbc660d2 | ||
|
|
e0bbff827e | ||
|
|
10925f2447 |
@@ -7,6 +7,11 @@
|
||||
></mat-progress-bar>
|
||||
</div>
|
||||
<mat-sidenav-container class="console-app__container">
|
||||
<mat-sidenav-content class="console-app__content-wrapper">
|
||||
<div class="console-app__content" role="main">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
<mat-sidenav
|
||||
[mode]="breakpointObserver.isMobileView() ? 'over' : 'side'"
|
||||
[opened]="!breakpointObserver.isMobileView()"
|
||||
@@ -15,10 +20,5 @@
|
||||
>
|
||||
<app-navigation />
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content class="console-app__content-wrapper">
|
||||
<div class="console-app__content">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
</mat-sidenav-container>
|
||||
</div>
|
||||
|
||||
@@ -20,12 +20,18 @@ import { AppComponent } from './app.component';
|
||||
import { MaterialModule } from './material.module';
|
||||
import { BackendService } from './shared/services/backend.service';
|
||||
import { AppRoutingModule } from './app-routing.module';
|
||||
import { AppModule } from './app.module';
|
||||
|
||||
describe('AppComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [AppComponent],
|
||||
imports: [MaterialModule, BrowserAnimationsModule, AppRoutingModule],
|
||||
imports: [
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
provideHttpClient(),
|
||||
@@ -36,6 +42,7 @@ describe('AppComponent', () => {
|
||||
|
||||
it('should create the app', () => {
|
||||
const fixture = TestBed.createComponent(AppComponent);
|
||||
fixture.detectChanges();
|
||||
const app = fixture.componentInstance;
|
||||
expect(app).toBeTruthy();
|
||||
});
|
||||
|
||||
@@ -26,7 +26,11 @@ import { BackendService } from './shared/services/backend.service';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { BillingInfoComponent } from './billingInfo/billingInfo.component';
|
||||
import { DomainListComponent } from './domains/domainList.component';
|
||||
import {
|
||||
DomainListComponent,
|
||||
ReasonDialogComponent,
|
||||
ResponseDialogComponent,
|
||||
} from './domains/domainList.component';
|
||||
import { RegistryLockComponent } from './domains/registryLock.component';
|
||||
import { HeaderComponent } from './header/header.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
@@ -92,6 +96,8 @@ export class SelectedRegistrarModule {}
|
||||
TldsComponent,
|
||||
WhoisComponent,
|
||||
WhoisEditComponent,
|
||||
ReasonDialogComponent,
|
||||
ResponseDialogComponent,
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
imports: [
|
||||
|
||||
@@ -65,16 +65,66 @@
|
||||
/>
|
||||
</mat-form-field>
|
||||
|
||||
<div
|
||||
class="console-app__domains-selection"
|
||||
[elementId]="getElementIdForBulkDelete()"
|
||||
[ngClass]="{ active: selection.hasValue() }"
|
||||
>
|
||||
<div class="console-app__domains-selection-text">
|
||||
{{ selection.selected.length }} Selected
|
||||
</div>
|
||||
<div class="console-app__domains-selection-actions">
|
||||
<button
|
||||
mat-flat-button
|
||||
aria-label="Delete Selected Domains"
|
||||
(click)="deleteSelectedDomains()"
|
||||
>
|
||||
Delete Selected Domains
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z0"
|
||||
class="console-app__domains-table"
|
||||
>
|
||||
<!-- Checkbox Column -->
|
||||
<ng-container matColumnDef="select">
|
||||
<mat-header-cell *matHeaderCellDef>
|
||||
<mat-checkbox
|
||||
(change)="$event ? toggleAllRows() : null"
|
||||
[checked]="selection.hasValue() && isAllSelected"
|
||||
[indeterminate]="selection.hasValue() && !isAllSelected"
|
||||
[aria-label]="checkboxLabel()"
|
||||
[elementId]="getElementIdForBulkDelete()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</mat-header-cell>
|
||||
<mat-cell *matCellDef="let row">
|
||||
<mat-checkbox
|
||||
(click)="$event.stopPropagation()"
|
||||
(change)="$event ? selection.toggle(row) : null"
|
||||
[checked]="selection.isSelected(row)"
|
||||
[aria-label]="checkboxLabel(row)"
|
||||
[elementId]="getElementIdForBulkDelete()"
|
||||
>
|
||||
</mat-checkbox>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="domainName">
|
||||
<mat-header-cell *matHeaderCellDef>Domain Name</mat-header-cell>
|
||||
<mat-cell *matCellDef="let element">{{
|
||||
element.domainName
|
||||
}}</mat-cell>
|
||||
<mat-cell *matCellDef="let element">
|
||||
<mat-icon
|
||||
*ngIf="getOperationMessage(element.domainName)"
|
||||
[matTooltip]="getOperationMessage(element.domainName)"
|
||||
matTooltipPosition="above"
|
||||
class="primary-text"
|
||||
>info</mat-icon
|
||||
>
|
||||
<span>{{ element.domainName }}</span>
|
||||
</mat-cell>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="creationTime">
|
||||
|
||||
@@ -12,6 +12,22 @@
|
||||
}
|
||||
}
|
||||
|
||||
&__domains-selection {
|
||||
height: 60px;
|
||||
max-height: 0;
|
||||
transition: max-height 0.2s linear;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
overflow: hidden;
|
||||
gap: 20px;
|
||||
&-text {
|
||||
font-weight: bold;
|
||||
}
|
||||
&.active {
|
||||
max-height: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
&-domains__download {
|
||||
position: absolute;
|
||||
top: -55px;
|
||||
@@ -41,6 +57,22 @@
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
}
|
||||
.mat-column-select {
|
||||
max-width: 60px;
|
||||
padding-left: 15px;
|
||||
}
|
||||
.mat-column-domainName {
|
||||
position: relative;
|
||||
padding-left: 25px;
|
||||
mat-icon {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
}
|
||||
}
|
||||
mat-cell:has([style*="display: none"]),
|
||||
mat-header-cell:has([style*="display: none"]) {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
&__domains-spinner {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { MaterialModule } from '../material.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { DomainListComponent } from './domainList.component';
|
||||
import { FormsModule } from '@angular/forms';
|
||||
import { AppModule } from '../app.module';
|
||||
|
||||
describe('DomainListComponent', () => {
|
||||
let component: DomainListComponent;
|
||||
@@ -29,7 +30,12 @@ describe('DomainListComponent', () => {
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [DomainListComponent],
|
||||
imports: [MaterialModule, BrowserAnimationsModule, FormsModule],
|
||||
imports: [
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
FormsModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
provideHttpClient(),
|
||||
|
||||
@@ -12,16 +12,91 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { SelectionModel } from '@angular/cdk/collections';
|
||||
import { HttpErrorResponse, HttpStatusCode } from '@angular/common/http';
|
||||
import { Component, ViewChild, effect } from '@angular/core';
|
||||
import { Component, ViewChild, effect, Inject } from '@angular/core';
|
||||
import { MatPaginator, PageEvent } from '@angular/material/paginator';
|
||||
import { MatSnackBar } from '@angular/material/snack-bar';
|
||||
import { MatTableDataSource } from '@angular/material/table';
|
||||
import { Subject, debounceTime } from 'rxjs';
|
||||
import { Subject, debounceTime, take, filter } from 'rxjs';
|
||||
import { RegistrarService } from '../registrar/registrar.service';
|
||||
import { Domain, DomainListService } from './domainList.service';
|
||||
import { RegistryLockComponent } from './registryLock.component';
|
||||
import { RegistryLockService } from './registryLock.service';
|
||||
import {
|
||||
MAT_DIALOG_DATA,
|
||||
MatDialog,
|
||||
MatDialogRef,
|
||||
} from '@angular/material/dialog';
|
||||
import { RESTRICTED_ELEMENTS } from '../shared/directives/userLevelVisiblity.directive';
|
||||
|
||||
interface DomainResponse {
|
||||
message: string;
|
||||
responseCode: string;
|
||||
}
|
||||
|
||||
interface DomainData {
|
||||
[domain: string]: DomainResponse;
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-response-dialog',
|
||||
template: `
|
||||
<h2 mat-dialog-title>{{ data.title }}</h2>
|
||||
<mat-dialog-content [innerHTML]="data.content" />
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="onClose()">Close</button>
|
||||
</mat-dialog-actions>
|
||||
`,
|
||||
})
|
||||
export class ResponseDialogComponent {
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ReasonDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { title: string; content: string }
|
||||
) {}
|
||||
|
||||
onClose(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-reason-dialog',
|
||||
template: `
|
||||
<h2 mat-dialog-title>
|
||||
Please provide a reason for {{ data.operation }} the domain(s):
|
||||
</h2>
|
||||
<mat-dialog-content>
|
||||
<mat-form-field appearance="outline" style="width:100%">
|
||||
<textarea matInput [(ngModel)]="reason" rows="4"></textarea>
|
||||
</mat-form-field>
|
||||
</mat-dialog-content>
|
||||
<mat-dialog-actions>
|
||||
<button mat-button (click)="onCancel()">Cancel</button>
|
||||
<button mat-button color="warn" (click)="onDelete()" [disabled]="!reason">
|
||||
Delete
|
||||
</button>
|
||||
</mat-dialog-actions>
|
||||
`,
|
||||
})
|
||||
export class ReasonDialogComponent {
|
||||
reason: string = '';
|
||||
|
||||
constructor(
|
||||
public dialogRef: MatDialogRef<ReasonDialogComponent>,
|
||||
@Inject(MAT_DIALOG_DATA)
|
||||
public data: { operation: 'deleting' | 'suspending' }
|
||||
) {}
|
||||
|
||||
onDelete(): void {
|
||||
this.dialogRef.close(this.reason);
|
||||
}
|
||||
|
||||
onCancel(): void {
|
||||
this.dialogRef.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'app-domain-list',
|
||||
@@ -31,8 +106,10 @@ import { RegistryLockService } from './registryLock.service';
|
||||
export class DomainListComponent {
|
||||
public static PATH = 'domain-list';
|
||||
private readonly DEBOUNCE_MS = 500;
|
||||
isAllSelected = false;
|
||||
|
||||
displayedColumns: string[] = [
|
||||
'select',
|
||||
'domainName',
|
||||
'creationTime',
|
||||
'registrationExpirationTime',
|
||||
@@ -42,6 +119,7 @@ export class DomainListComponent {
|
||||
];
|
||||
|
||||
dataSource: MatTableDataSource<Domain> = new MatTableDataSource();
|
||||
selection = new SelectionModel<Domain>(true, [], undefined, this.isChecked());
|
||||
isLoading = true;
|
||||
|
||||
searchTermSubject = new Subject<string>();
|
||||
@@ -51,13 +129,18 @@ export class DomainListComponent {
|
||||
resultsPerPage = 50;
|
||||
totalResults?: number = 0;
|
||||
|
||||
reason: string = '';
|
||||
|
||||
operationResult: DomainData | undefined;
|
||||
|
||||
@ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator;
|
||||
|
||||
constructor(
|
||||
protected domainListService: DomainListService,
|
||||
protected registrarService: RegistrarService,
|
||||
protected registryLockService: RegistryLockService,
|
||||
private _snackBar: MatSnackBar
|
||||
private _snackBar: MatSnackBar,
|
||||
private dialog: MatDialog
|
||||
) {
|
||||
effect(() => {
|
||||
this.pageNumber = 0;
|
||||
@@ -134,6 +217,98 @@ export class DomainListComponent {
|
||||
onPageChange(event: PageEvent) {
|
||||
this.pageNumber = event.pageIndex;
|
||||
this.resultsPerPage = event.pageSize;
|
||||
this.selection.clear();
|
||||
this.reloadData();
|
||||
}
|
||||
|
||||
toggleAllRows() {
|
||||
if (this.isAllSelected) {
|
||||
this.selection.clear();
|
||||
this.isAllSelected = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.selection.select(...this.dataSource.data);
|
||||
this.isAllSelected = true;
|
||||
}
|
||||
|
||||
checkboxLabel(row?: Domain): string {
|
||||
if (!row) {
|
||||
return `${this.isAllSelected ? 'deselect' : 'select'} all`;
|
||||
}
|
||||
return `${this.selection.isSelected(row) ? 'deselect' : 'select'} row ${
|
||||
row.domainName
|
||||
}`;
|
||||
}
|
||||
|
||||
private isChecked(): ((o1: Domain, o2: Domain) => boolean) | undefined {
|
||||
return (o1: Domain, o2: Domain) => {
|
||||
if (!o1.domainName || !o2.domainName) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return this.isAllSelected || o1.domainName === o2.domainName;
|
||||
};
|
||||
}
|
||||
|
||||
getElementIdForBulkDelete() {
|
||||
return RESTRICTED_ELEMENTS.BULK_DELETE;
|
||||
}
|
||||
|
||||
getOperationMessage(domain: string) {
|
||||
if (this.operationResult && this.operationResult[domain])
|
||||
return this.operationResult[domain].message;
|
||||
return '';
|
||||
}
|
||||
|
||||
sendDeleteRequest(reason: string) {
|
||||
this.isLoading = true;
|
||||
this.domainListService
|
||||
.deleteDomains(
|
||||
this.selection.selected,
|
||||
reason,
|
||||
this.registrarService.registrarId()
|
||||
)
|
||||
.pipe(take(1))
|
||||
.subscribe({
|
||||
next: (result: DomainData) => {
|
||||
this.isLoading = false;
|
||||
const successCount = Object.keys(result).filter((domainName) =>
|
||||
result[domainName].responseCode.toString().startsWith('1')
|
||||
).length;
|
||||
const failureCount = Object.keys(result).length - successCount;
|
||||
this.dialog.open(ResponseDialogComponent, {
|
||||
data: {
|
||||
title: 'Domain Deletion Results',
|
||||
content: `Successfully deleted - ${successCount} domain(s)<br/>Failed to delete - ${failureCount} domain(s)<br/>${
|
||||
failureCount
|
||||
? 'Some domains could not be deleted due to ongoing processes or server errors. '
|
||||
: ''
|
||||
}Please check the table for more information.`,
|
||||
},
|
||||
});
|
||||
this.selection.clear();
|
||||
this.operationResult = result;
|
||||
this.reloadData();
|
||||
},
|
||||
error: (err: HttpErrorResponse) =>
|
||||
this._snackBar.open(err.error || err.message),
|
||||
});
|
||||
}
|
||||
|
||||
deleteSelectedDomains() {
|
||||
const dialogRef = this.dialog.open(ReasonDialogComponent, {
|
||||
data: {
|
||||
operation: 'deleting',
|
||||
},
|
||||
});
|
||||
|
||||
dialogRef
|
||||
.afterClosed()
|
||||
.pipe(
|
||||
take(1),
|
||||
filter((reason) => !!reason)
|
||||
)
|
||||
.subscribe(this.sendDeleteRequest.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,6 @@ export class DomainListService {
|
||||
private backendService: BackendService,
|
||||
private registrarService: RegistrarService
|
||||
) {}
|
||||
|
||||
retrieveDomains(
|
||||
pageNumber?: number,
|
||||
resultsPerPage?: number,
|
||||
@@ -71,4 +70,13 @@ export class DomainListService {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
deleteDomains(domains: Domain[], reason: string, registrarId: string) {
|
||||
return this.backendService.bulkDomainAction(
|
||||
domains.map((d) => d.domainName),
|
||||
reason,
|
||||
'DELETE',
|
||||
registrarId
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
<a
|
||||
[routerLink]="'/home'"
|
||||
routerLinkActive="active"
|
||||
aria-label="Google Registry logo"
|
||||
class="console-app__logo"
|
||||
>
|
||||
<svg
|
||||
|
||||
@@ -17,6 +17,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { HeaderComponent } from './header.component';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AppModule, SelectedRegistrarModule } from '../app.module';
|
||||
import { AppRoutingModule } from '../app-routing.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||
|
||||
describe('HeaderComponent', () => {
|
||||
let component: HeaderComponent;
|
||||
@@ -24,7 +30,19 @@ describe('HeaderComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
imports: [
|
||||
SelectedRegistrarModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: ActivatedRoute, useValue: {} as ActivatedRoute },
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
declarations: [HeaderComponent],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { HomeComponent } from './home.component';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { AppModule } from '../app.module';
|
||||
|
||||
describe('HomeComponent', () => {
|
||||
let component: HomeComponent;
|
||||
@@ -23,7 +24,7 @@ describe('HomeComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule],
|
||||
imports: [MaterialModule, AppModule],
|
||||
declarations: [HomeComponent],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -6,7 +6,9 @@
|
||||
<mat-tree-node
|
||||
*matTreeNodeDef="let node"
|
||||
matTreeNodeToggle
|
||||
tabindex="0"
|
||||
(click)="onClick(node)"
|
||||
(keyup.enter)="onClick(node)"
|
||||
[class.active]="router.url.includes(node.path)"
|
||||
[elementId]="getElementId(node)"
|
||||
>
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="console-app__registrar-view">
|
||||
<div
|
||||
class="console-app__registrar-view"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
<h1 class="mat-headline-4">Registrars</h1>
|
||||
<mat-divider></mat-divider>
|
||||
<div class="console-app__registrar-view-content">
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
[ngModelOptions]="{ standalone: true }"
|
||||
(focus)="onFocus()"
|
||||
[matAutocomplete]="auto"
|
||||
spellcheck="false"
|
||||
/>
|
||||
<mat-autocomplete
|
||||
autoActiveFirstOption
|
||||
|
||||
@@ -59,6 +59,8 @@
|
||||
<mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
(click)="openDetails(row.registrarId)"
|
||||
tabindex="0"
|
||||
(keyup.enter)="openDetails(row.registrarId)"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
|
||||
|
||||
@@ -32,7 +32,9 @@
|
||||
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
|
||||
<mat-row
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
tabindex="0"
|
||||
(click)="openDetails(row)"
|
||||
(keyup.enter)="openDetails(row)"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
}
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<div class="console-app__contact" *ngIf="contactService.contactInEdit">
|
||||
<div
|
||||
class="console-app__contact"
|
||||
*ngIf="contactService.contactInEdit"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
<div class="console-app__contact-controls">
|
||||
<button
|
||||
mat-icon-button
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="settings-security__edit-password">
|
||||
<div
|
||||
class="settings-security__edit-password"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
<p>
|
||||
<button
|
||||
mat-icon-button
|
||||
|
||||
@@ -42,7 +42,7 @@ describe('SecurityComponent', () => {
|
||||
fetchSecurityDetailsSpy =
|
||||
securityServiceSpy.fetchSecurityDetails.and.returnValue(of());
|
||||
|
||||
saveSpy = securityServiceSpy.saveChanges;
|
||||
saveSpy = securityServiceSpy.saveChanges.and.returnValue(of());
|
||||
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [SecurityEditComponent, SecurityComponent],
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="settings-security__edit">
|
||||
<div
|
||||
class="settings-security__edit"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
<h1>IP Allowlist</h1>
|
||||
<p>
|
||||
Restrict access to EPP production servers to the following IP/IPv6
|
||||
|
||||
@@ -10,22 +10,28 @@
|
||||
<a
|
||||
mat-tab-link
|
||||
routerLink="contact"
|
||||
routerLinkActive="active-link"
|
||||
routerLinkActive
|
||||
queryParamsHandling="merge"
|
||||
#rla="routerLinkActive"
|
||||
[active]="rla.isActive"
|
||||
>Contacts</a
|
||||
>
|
||||
<a
|
||||
mat-tab-link
|
||||
routerLink="whois"
|
||||
routerLinkActive="active-link"
|
||||
routerLinkActive
|
||||
queryParamsHandling="merge"
|
||||
#rla2="routerLinkActive"
|
||||
[active]="rla2.isActive"
|
||||
>WHOIS Info</a
|
||||
>
|
||||
<a
|
||||
mat-tab-link
|
||||
routerLink="security"
|
||||
routerLinkActive="active-link"
|
||||
routerLinkActive
|
||||
queryParamsHandling="merge"
|
||||
#rla3="routerLinkActive"
|
||||
[active]="rla3.isActive"
|
||||
>Security</a
|
||||
>
|
||||
</nav>
|
||||
|
||||
@@ -13,14 +13,6 @@
|
||||
// limitations under the License.
|
||||
|
||||
.console-settings {
|
||||
.mdc-tab {
|
||||
&.active-link {
|
||||
border-bottom: 2px solid var(--primary);
|
||||
.mdc-tab__text-label {
|
||||
color: var(--primary);
|
||||
}
|
||||
}
|
||||
}
|
||||
nav {
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
|
||||
@@ -17,6 +17,12 @@ import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
import { SettingsComponent } from './settings.component';
|
||||
import { MaterialModule } from '../material.module';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { AppModule, SelectedRegistrarModule } from '../app.module';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { provideHttpClient } from '@angular/common/http';
|
||||
import { provideHttpClientTesting } from '@angular/common/http/testing';
|
||||
import { AppRoutingModule } from '../app-routing.module';
|
||||
|
||||
describe('SettingsComponent', () => {
|
||||
let component: SettingsComponent;
|
||||
@@ -24,7 +30,19 @@ describe('SettingsComponent', () => {
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
imports: [MaterialModule, BrowserAnimationsModule],
|
||||
imports: [
|
||||
SelectedRegistrarModule,
|
||||
MaterialModule,
|
||||
BrowserAnimationsModule,
|
||||
AppRoutingModule,
|
||||
AppModule,
|
||||
],
|
||||
providers: [
|
||||
BackendService,
|
||||
{ provide: ActivatedRoute, useValue: {} as ActivatedRoute },
|
||||
provideHttpClient(),
|
||||
provideHttpClientTesting(),
|
||||
],
|
||||
declarations: [SettingsComponent],
|
||||
}).compileComponents();
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
<div class="console-app__whois-edit" *ngIf="registrarInEdit">
|
||||
<div
|
||||
class="console-app__whois-edit"
|
||||
*ngIf="registrarInEdit"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
<button
|
||||
mat-icon-button
|
||||
class="console-app__whois-edit-back"
|
||||
|
||||
@@ -19,6 +19,7 @@ export enum RESTRICTED_ELEMENTS {
|
||||
REGISTRAR_ELEMENT,
|
||||
OTE,
|
||||
USERS,
|
||||
BULK_DELETE,
|
||||
}
|
||||
|
||||
export const DISABLED_ELEMENTS_PER_ROLE = {
|
||||
@@ -26,6 +27,7 @@ export const DISABLED_ELEMENTS_PER_ROLE = {
|
||||
RESTRICTED_ELEMENTS.REGISTRAR_ELEMENT,
|
||||
RESTRICTED_ELEMENTS.OTE,
|
||||
RESTRICTED_ELEMENTS.USERS,
|
||||
RESTRICTED_ELEMENTS.BULK_DELETE,
|
||||
],
|
||||
SUPPORT_LEAD: [RESTRICTED_ELEMENTS.USERS],
|
||||
SUPPORT_AGENT: [RESTRICTED_ELEMENTS.USERS],
|
||||
|
||||
@@ -180,6 +180,23 @@ export class BackendService {
|
||||
.pipe(catchError((err) => this.errorCatcher<any>(err)));
|
||||
}
|
||||
|
||||
bulkDomainAction(
|
||||
domainNames: string[],
|
||||
reason: string,
|
||||
bulkDomainAction: string,
|
||||
registrarId: string
|
||||
) {
|
||||
return this.http
|
||||
.post<any>(
|
||||
`/console-api/bulk-domain?registrarId=${registrarId}&bulkDomainAction=${bulkDomainAction}`,
|
||||
{
|
||||
domainList: domainNames,
|
||||
reason,
|
||||
}
|
||||
)
|
||||
.pipe(catchError((err) => this.errorCatcher<any>(err)));
|
||||
}
|
||||
|
||||
updateUser(registrarId: string, updatedUser: User): Observable<any> {
|
||||
return this.http
|
||||
.put<User>(`/console-api/users?registrarId=${registrarId}`, updatedUser)
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
<div class="console-app__user-details">
|
||||
<div
|
||||
class="console-app__user-details"
|
||||
cdkTrapFocus
|
||||
[cdkTrapFocusAutoCapture]="true"
|
||||
>
|
||||
@if(isEditing) {
|
||||
<h1 class="mat-headline-4">Editing {{ userDetails().emailAddress }}</h1>
|
||||
<mat-divider></mat-divider>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<app-selected-registrar-wrapper>
|
||||
<app-selected-registrar-wrapper cdkTrapFocus [cdkTrapFocusAutoCapture]="true">
|
||||
@if(isLoading) {
|
||||
<div class="console-app__users-spinner">
|
||||
<mat-spinner />
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
*matRowDef="let row; columns: displayedColumns"
|
||||
[class.rowSelected]="isRowSelected(row)"
|
||||
(click)="onClick(row)"
|
||||
(keyup.enter)="onClick(row)"
|
||||
tabindex="0"
|
||||
></mat-row>
|
||||
</mat-table>
|
||||
</div>
|
||||
|
||||
@@ -82,11 +82,6 @@ $typographyConfig: mat.m2-define-typography-config(
|
||||
),
|
||||
);
|
||||
|
||||
// Access and define a class with secondary color exposed
|
||||
.secondary-text {
|
||||
color: $secondary-color;
|
||||
}
|
||||
|
||||
.text-xl {
|
||||
font-size: 18px;
|
||||
}
|
||||
@@ -115,6 +110,15 @@ mat-row:hover {
|
||||
--mat-sidenav-container-width: 280px;
|
||||
}
|
||||
|
||||
// Access and define a class with secondary color exposed
|
||||
.secondary-text {
|
||||
color: #575757;
|
||||
}
|
||||
|
||||
.primary-text {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
$theme: mat.define-theme(
|
||||
(
|
||||
color: (
|
||||
|
||||
@@ -21,10 +21,10 @@ com.github.docker-java:docker-java-transport:3.4.0=compileClasspath,deploy_jar,n
|
||||
com.github.jnr:jffi:1.3.13=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-a64asm:1.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-constants:0.10.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.17=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.16=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.19=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.22=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.18=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.17=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.20=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.23=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-x86asm:1.0.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
com.google.android:annotations:4.1.1.4=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -111,16 +111,16 @@ com.google.apis:google-api-services-bigquery:v2-rev20240815-2.0.0=compileClasspa
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20240310-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20241209-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20240719-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241027-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241206-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20240520-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20240530-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20241114-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iamcredentials:v1-rev20211203-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241017-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sheets:v4-rev20241203-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20240925-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20241108-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20240706-2.0.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20241206-2.0.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -140,8 +140,8 @@ com.google.cloud.opentelemetry:detector-resources-support:0.31.0=compileClasspat
|
||||
com.google.cloud.opentelemetry:detector-resources-support:0.33.0=testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:exporter-metrics:0.33.0=testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:shared-resourcemapping:0.33.0=testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.2=testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigtable:2.43.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath
|
||||
@@ -280,7 +280,6 @@ com.zaxxer:HikariCP:6.2.1=compileClasspath,deploy_jar,nonprodCompileClasspath,no
|
||||
commons-beanutils:commons-beanutils:1.9.4=checkstyle
|
||||
commons-codec:commons-codec:1.17.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
commons-dbutils:commons-dbutils:1.8.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-io:commons-io:2.17.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-logging:commons-logging:1.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
dev.failsafe:failsafe:3.3.2=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -408,10 +407,10 @@ javax.validation:validation-api:1.0.0.GA=compileClasspath,deploy_jar,nonprodComp
|
||||
joda-time:joda-time:2.12.7=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=nonprodCompileClasspath,nonprodRuntimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
net.arnx:nashorn-promise:0.1.1=testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.4=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.14.12=compileClasspath,nonprodCompileClasspath
|
||||
net.bytebuddy:byte-buddy:1.14.15=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.10=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.java.dev.jna:jna:5.13.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
net.ltgt.gradle.incap:incap:0.2=annotationProcessor,testAnnotationProcessor
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
@@ -479,18 +478,18 @@ org.eclipse.angus:angus-activation:2.0.2=deploy_jar,jaxb,nonprodRuntimeClasspath
|
||||
org.eclipse.angus:jakarta.mail:2.0.3=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections-api:11.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections:11.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty.ee10:jetty-ee10-servlet:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty.ee10:jetty-ee10-webapp:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-ee:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-http:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-io:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-security:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-server:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-session:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:12.1.0.alpha0=testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.0=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty.ee10:jetty-ee10-servlet:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty.ee10:jetty-ee10-webapp:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-ee:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-http:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-io:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-security:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-server:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-session:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-util:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.jetty:jetty-xml:12.1.0.alpha1=testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:codemodel:4.0.5=jaxb
|
||||
org.glassfish.jaxb:jaxb-core:4.0.2=deploy_jar,nonprodRuntimeClasspath,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.5=jaxb
|
||||
@@ -553,19 +552,24 @@ org.junit.platform:junit-platform-runner:1.11.4=testCompileClasspath,testRuntime
|
||||
org.junit.platform:junit-platform-suite-api:1.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-commons:1.11.4=testRuntimeClasspath
|
||||
org.junit:junit-bom:5.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.14.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-junit-jupiter:5.14.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.15.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-junit-jupiter:5.15.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.ogce:xpp3:1.1.6=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.5=soy
|
||||
org.ow2.asm:asm-analysis:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=soy
|
||||
org.ow2.asm:asm-commons:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.5=soy
|
||||
org.ow2.asm:asm-tree:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-util:9.5=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,soy,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.5=compileClasspath,nonprodCompileClasspath,soy
|
||||
org.ow2.asm:asm:9.7=deploy_jar,jacocoAnt,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-util:9.5=soy
|
||||
org.ow2.asm:asm-util:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.5=soy
|
||||
org.ow2.asm:asm:9.7=jacocoAnt
|
||||
org.ow2.asm:asm:9.7.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,errorprone,nonprodAnnotationProcessor,testAnnotationProcessor
|
||||
org.postgresql:postgresql:42.7.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
@@ -604,13 +608,13 @@ org.w3c.css:sac:1.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodR
|
||||
org.webjars.npm:viz.js-graphviz-java:2.1.3=testRuntimeClasspath
|
||||
org.xerial.snappy:snappy-java:1.1.10.4=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.yaml:snakeyaml:2.3=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.24.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.25.1=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
xerces:xmlParserAPIs:2.6.2=compileClasspath,deploy_jar,nonprodCompileClasspath,nonprodRuntimeClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
empty=devtool,nomulus_test
|
||||
|
||||
@@ -17,6 +17,7 @@ package google.registry.batch;
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
import static com.google.common.collect.ImmutableList.toImmutableList;
|
||||
import static google.registry.config.RegistryConfig.CANARY_HEADER;
|
||||
import static java.util.concurrent.TimeUnit.SECONDS;
|
||||
|
||||
import com.google.api.gax.rpc.ApiException;
|
||||
@@ -190,6 +191,9 @@ public class CloudTasksUtils implements Serializable {
|
||||
requestBuilder.setOidcToken(oidcTokenBuilder.build());
|
||||
String totalPath = String.format("%s%s", service.getServiceUrl(), path);
|
||||
requestBuilder.setUrl(totalPath);
|
||||
if (RegistryEnvironment.isCanary()) {
|
||||
requestBuilder.putHeaders(CANARY_HEADER, "true");
|
||||
}
|
||||
return Task.newBuilder().setHttpRequest(requestBuilder.build()).build();
|
||||
}
|
||||
|
||||
@@ -200,7 +204,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
* default service account as the principal. That account must have permission to submit tasks to
|
||||
* Cloud Tasks.
|
||||
*
|
||||
* <p>Prefer this overload over the one where the path and service are explicit defined, as this
|
||||
* <p>Prefer this overload over the one where the path and service are explicitly defined, as this
|
||||
* class will automatically determine the service to use based on the action and the runtime.
|
||||
*
|
||||
* @param actionClazz the action class to run, must be annotated with {@link Action}.
|
||||
@@ -269,7 +273,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
/**
|
||||
* Create a {@link Task} to be enqueued with a random delay up to {@code jitterSeconds}.
|
||||
*
|
||||
* <p>Prefer this overload over the one where the path and service are explicit defined, as this
|
||||
* <p>Prefer this overload over the one where the path and service are explicitly defined, as this
|
||||
* class will automatically determine the service to use based on the action and the runtime.
|
||||
*
|
||||
* @param actionClazz the action class to run, must be annotated with {@link Action}.
|
||||
@@ -306,7 +310,7 @@ public class CloudTasksUtils implements Serializable {
|
||||
* @param service the GAE/GKE service to route the request to.
|
||||
* @param params a multimap of URL query parameters. Duplicate keys are saved as is, and it is up
|
||||
* to the server to process the duplicate keys.
|
||||
* @param delay the amount of time that a task needs to delayed for.
|
||||
* @param delay the amount of time that a task needs to be delayed for.
|
||||
* @return the enqueued task.
|
||||
* @see <a
|
||||
* href=ttps://cloud.google.com/appengine/docs/standard/java/taskqueue/push/creating-tasks#target>Specifyinig
|
||||
@@ -330,14 +334,14 @@ public class CloudTasksUtils implements Serializable {
|
||||
/**
|
||||
* Create a {@link Task} to be enqueued with delay of {@code duration}.
|
||||
*
|
||||
* <p>Prefer this overload over the one where the path and service are explicit defined, as this
|
||||
* <p>Prefer this overload over the one where the path and service are explicitly defined, as this
|
||||
* class will automatically determine the service to use based on the action and the runtime.
|
||||
*
|
||||
* @param actionClazz the action class to run, must be annotated with {@link Action}.
|
||||
* @param method the HTTP method to be used for the request.
|
||||
* @param params a multimap of URL query parameters. Duplicate keys are saved as is, and it is up
|
||||
* to the server to process the duplicate keys.
|
||||
* @param delay the amount of time that a task needs to delayed for.
|
||||
* @param delay the amount of time that a task needs to be delayed for.
|
||||
* @return the enqueued task.
|
||||
* @see <a
|
||||
* href=ttps://cloud.google.com/appengine/docs/standard/java/taskqueue/push/creating-tasks#target>Specifyinig
|
||||
|
||||
@@ -20,6 +20,7 @@ import dagger.Lazy;
|
||||
import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.persistence.PersistenceModule.BeamJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.BeamReadOnlyReplicaJpaTm;
|
||||
@@ -36,6 +37,7 @@ import javax.inject.Singleton;
|
||||
modules = {
|
||||
ConfigModule.class,
|
||||
CredentialModule.class,
|
||||
KeyringModule.class,
|
||||
PersistenceModule.class,
|
||||
SecretManagerModule.class,
|
||||
UtilsModule.class
|
||||
|
||||
@@ -71,6 +71,7 @@ import org.joda.time.Duration;
|
||||
*/
|
||||
public final class RegistryConfig {
|
||||
|
||||
public static final String CANARY_HEADER = "canary";
|
||||
private static final String ENVIRONMENT_CONFIG_FORMAT = "files/nomulus-config-%s.yaml";
|
||||
private static final String YAML_CONFIG_PROD =
|
||||
readResourceUtf8(RegistryConfig.class, "files/default-config.yaml");
|
||||
@@ -1098,12 +1099,6 @@ public final class RegistryConfig {
|
||||
return config.registryPolicy.greetingServerId;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("activeKeyring")
|
||||
public static String provideKeyring(RegistryConfigSettings config) {
|
||||
return config.keyring.activeKeyring;
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Config("customLogicFactoryClass")
|
||||
public static String provideCustomLogicFactoryClass(RegistryConfigSettings config) {
|
||||
|
||||
@@ -37,7 +37,6 @@ public class RegistryConfigSettings {
|
||||
public Monitoring monitoring;
|
||||
public Misc misc;
|
||||
public Beam beam;
|
||||
public Keyring keyring;
|
||||
public RegistryTool registryTool;
|
||||
public SslCertificateValidation sslCertificateValidation;
|
||||
public ContactHistory contactHistory;
|
||||
@@ -214,11 +213,6 @@ public class RegistryConfigSettings {
|
||||
public int transientFailureRetries;
|
||||
}
|
||||
|
||||
/** Configuration for keyrings (used to store secrets outside of source). */
|
||||
public static class Keyring {
|
||||
public String activeKeyring;
|
||||
}
|
||||
|
||||
/** Configuration options for the registry tool. */
|
||||
public static class RegistryTool {
|
||||
public String clientId;
|
||||
|
||||
@@ -488,11 +488,6 @@ beam:
|
||||
initialWorkerCount: 24
|
||||
stagingBucketUrl: gcs-bucket-with-staged-templates
|
||||
|
||||
keyring:
|
||||
# The name of the active keyring, either "Dummy" or "CSM". The latter stands
|
||||
# for Cloud SecretManager.
|
||||
activeKeyring: Dummy
|
||||
|
||||
# Configuration options relevant to the "nomulus" registry tool.
|
||||
registryTool:
|
||||
# OAuth client ID used by the tool.
|
||||
|
||||
@@ -54,7 +54,8 @@ public class ExportPremiumTermsAction implements Runnable {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
static final MediaType EXPORT_MIME_TYPE = MediaType.PLAIN_TEXT_UTF_8;
|
||||
static final String PREMIUM_TERMS_FILENAME = "CONFIDENTIAL_premium_terms.txt";
|
||||
static final String TLD_IDENTIFIER_FORMAT = "# TLD: %s";
|
||||
static final String PREMIUM_TERMS_FILENAME_FORMAT = "CONFIDENTIAL_premium_terms_%s.txt";
|
||||
|
||||
@Inject DriveConnection driveConnection;
|
||||
|
||||
@@ -127,7 +128,7 @@ public class ExportPremiumTermsAction implements Runnable {
|
||||
try {
|
||||
String fileId =
|
||||
driveConnection.createOrUpdateFile(
|
||||
PREMIUM_TERMS_FILENAME,
|
||||
String.format(PREMIUM_TERMS_FILENAME_FORMAT, tldStr),
|
||||
EXPORT_MIME_TYPE,
|
||||
tld.getDriveFolderId(),
|
||||
getFormattedPremiumTerms(tld).getBytes(UTF_8));
|
||||
@@ -150,11 +151,9 @@ public class ExportPremiumTermsAction implements Runnable {
|
||||
.map(PremiumEntry::toString)
|
||||
.collect(ImmutableSortedSet.toImmutableSortedSet(String::compareTo));
|
||||
|
||||
return Joiner.on("\n")
|
||||
.appendTo(
|
||||
new StringBuilder(),
|
||||
Iterables.concat(ImmutableList.of(exportDisclaimer.trim()), premiumTerms))
|
||||
.append("\n")
|
||||
.toString();
|
||||
String tldIdentifier = String.format(TLD_IDENTIFIER_FORMAT, tldStr);
|
||||
Iterable<String> commentsAndTerms =
|
||||
Iterables.concat(ImmutableList.of(exportDisclaimer.trim(), tldIdentifier), premiumTerms);
|
||||
return Joiner.on("\n").join(commentsAndTerms) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static google.registry.dns.DnsUtils.requestDomainDnsRefresh;
|
||||
import static google.registry.flows.FlowUtils.persistEntityChanges;
|
||||
@@ -120,9 +119,7 @@ import google.registry.model.tmch.ClaimsList;
|
||||
import google.registry.model.tmch.ClaimsListDao;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.inject.Inject;
|
||||
import org.joda.money.Money;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
@@ -363,9 +360,7 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
// Create a new autorenew billing event and poll message starting at the expiration time.
|
||||
BillingRecurrence autorenewBillingEvent =
|
||||
createAutorenewBillingEvent(
|
||||
domainHistoryId,
|
||||
registrationExpirationTime,
|
||||
getRenewalPriceInfo(isAnchorTenant, allocationToken));
|
||||
domainHistoryId, registrationExpirationTime, isAnchorTenant, allocationToken);
|
||||
PollMessage.Autorenew autorenewPollMessage =
|
||||
createAutorenewPollMessage(domainHistoryId, registrationExpirationTime);
|
||||
ImmutableSet.Builder<ImmutableObject> entitiesToSave = new ImmutableSet.Builder<>();
|
||||
@@ -625,7 +620,17 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
private BillingRecurrence createAutorenewBillingEvent(
|
||||
HistoryEntryId domainHistoryId,
|
||||
DateTime registrationExpirationTime,
|
||||
RenewalPriceInfo renewalpriceInfo) {
|
||||
boolean isAnchorTenant,
|
||||
Optional<AllocationToken> allocationToken) {
|
||||
// Non-standard renewal behaviors can occur for anchor tenants (always NONPREMIUM pricing) or if
|
||||
// explicitly configured in the token (either NONPREMIUM or directly SPECIFIED). Use DEFAULT if
|
||||
// none is configured.
|
||||
RenewalPriceBehavior renewalPriceBehavior =
|
||||
isAnchorTenant
|
||||
? RenewalPriceBehavior.NONPREMIUM
|
||||
: allocationToken
|
||||
.map(AllocationToken::getRenewalPriceBehavior)
|
||||
.orElse(RenewalPriceBehavior.DEFAULT);
|
||||
return new BillingRecurrence.Builder()
|
||||
.setReason(Reason.RENEW)
|
||||
.setFlags(ImmutableSet.of(Flag.AUTO_RENEW))
|
||||
@@ -634,8 +639,8 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
.setEventTime(registrationExpirationTime)
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setDomainHistoryId(domainHistoryId)
|
||||
.setRenewalPriceBehavior(renewalpriceInfo.renewalPriceBehavior())
|
||||
.setRenewalPrice(renewalpriceInfo.renewalPrice())
|
||||
.setRenewalPriceBehavior(renewalPriceBehavior)
|
||||
.setRenewalPrice(allocationToken.flatMap(AllocationToken::getRenewalPrice).orElse(null))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -679,41 +684,6 @@ public final class DomainCreateFlow implements MutatingFlow {
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the {@link RenewalPriceBehavior} and the renewal price that needs be stored in the
|
||||
* {@link BillingRecurrence} billing events.
|
||||
*
|
||||
* <p>By default, the renewal price is calculated during the process of renewal. Renewal price
|
||||
* should be the createCost if and only if the renewal price behavior in the {@link
|
||||
* AllocationToken} is 'SPECIFIED'.
|
||||
*/
|
||||
static RenewalPriceInfo getRenewalPriceInfo(
|
||||
boolean isAnchorTenant, Optional<AllocationToken> allocationToken) {
|
||||
if (isAnchorTenant) {
|
||||
allocationToken.ifPresent(
|
||||
token ->
|
||||
checkArgument(
|
||||
token.getRenewalPriceBehavior() != RenewalPriceBehavior.SPECIFIED,
|
||||
"Renewal price behavior cannot be SPECIFIED for anchor tenant"));
|
||||
return RenewalPriceInfo.create(RenewalPriceBehavior.NONPREMIUM, null);
|
||||
} else if (allocationToken.isPresent()
|
||||
&& allocationToken.get().getRenewalPriceBehavior() == RenewalPriceBehavior.SPECIFIED) {
|
||||
return RenewalPriceInfo.create(
|
||||
RenewalPriceBehavior.SPECIFIED, allocationToken.get().getRenewalPrice().get());
|
||||
} else {
|
||||
return RenewalPriceInfo.create(RenewalPriceBehavior.DEFAULT, null);
|
||||
}
|
||||
}
|
||||
|
||||
/** A record to store renewal info used in {@link BillingRecurrence} billing events. */
|
||||
public record RenewalPriceInfo(
|
||||
RenewalPriceBehavior renewalPriceBehavior, @Nullable Money renewalPrice) {
|
||||
static RenewalPriceInfo create(
|
||||
RenewalPriceBehavior renewalPriceBehavior, @Nullable Money renewalPrice) {
|
||||
return new RenewalPriceInfo(renewalPriceBehavior, renewalPrice);
|
||||
}
|
||||
}
|
||||
|
||||
private static ImmutableList<FeeTransformResponseExtension> createResponseExtensions(
|
||||
Optional<FeeCreateCommandExtension> feeCreate, FeesAndCredits feesAndCredits) {
|
||||
return feeCreate
|
||||
|
||||
@@ -85,14 +85,10 @@ public final class DomainPricingLogic {
|
||||
createFee = Fee.create(zeroInCurrency(currency), FeeType.CREATE, false);
|
||||
} else {
|
||||
DomainPrices domainPrices = getPricesForDomainName(domainName, dateTime);
|
||||
if (allocationToken.isPresent()
|
||||
&& allocationToken
|
||||
.get()
|
||||
.getRegistrationBehavior()
|
||||
.equals(RegistrationBehavior.NONPREMIUM_CREATE)) {
|
||||
if (allocationToken.isPresent()) {
|
||||
// Handle any special NONPREMIUM / SPECIFIED cases configured in the token
|
||||
domainPrices =
|
||||
DomainPrices.create(
|
||||
false, tld.getCreateBillingCost(dateTime), domainPrices.getRenewCost());
|
||||
applyTokenToDomainPrices(domainPrices, tld, dateTime, years, allocationToken.get());
|
||||
}
|
||||
Money domainCreateCost =
|
||||
getDomainCreateCostWithDiscount(domainPrices, years, allocationToken, tld);
|
||||
@@ -357,6 +353,27 @@ public final class DomainPricingLogic {
|
||||
return totalDomainFlowCost;
|
||||
}
|
||||
|
||||
private DomainPrices applyTokenToDomainPrices(
|
||||
DomainPrices domainPrices, Tld tld, DateTime dateTime, int years, AllocationToken token) {
|
||||
// Convert to nonpremium iff no premium charges are included (either in create or any renewal)
|
||||
boolean convertToNonPremium =
|
||||
token.getRegistrationBehavior().equals(RegistrationBehavior.NONPREMIUM_CREATE)
|
||||
&& (years == 1
|
||||
|| !token.getRenewalPriceBehavior().equals(RenewalPriceBehavior.DEFAULT));
|
||||
boolean isPremium = domainPrices.isPremium() && !convertToNonPremium;
|
||||
Money createCost =
|
||||
token.getRegistrationBehavior().equals(RegistrationBehavior.NONPREMIUM_CREATE)
|
||||
? tld.getCreateBillingCost(dateTime)
|
||||
: domainPrices.getCreateCost();
|
||||
Money renewCost =
|
||||
token.getRenewalPriceBehavior().equals(RenewalPriceBehavior.NONPREMIUM)
|
||||
? tld.getStandardRenewCost(dateTime)
|
||||
: token.getRenewalPriceBehavior().equals(RenewalPriceBehavior.SPECIFIED)
|
||||
? token.getRenewalPrice().get()
|
||||
: domainPrices.getRenewCost();
|
||||
return DomainPrices.create(isPremium, createCost, renewCost);
|
||||
}
|
||||
|
||||
/** An allocation token was provided that is invalid for premium domains. */
|
||||
public static class AllocationTokenInvalidForPremiumNameException
|
||||
extends CommandUseErrorException {
|
||||
|
||||
@@ -14,31 +14,22 @@
|
||||
|
||||
package google.registry.keyring;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkState;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
import java.util.Map;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyring;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Singleton;
|
||||
|
||||
/** Dagger module for {@link Keyring} */
|
||||
@Module
|
||||
public final class KeyringModule {
|
||||
public abstract class KeyringModule {
|
||||
|
||||
@Provides
|
||||
@Binds
|
||||
@Singleton
|
||||
public static Keyring provideKeyring(
|
||||
Map<String, Keyring> keyrings, @Config("activeKeyring") String activeKeyring) {
|
||||
checkState(
|
||||
keyrings.containsKey(activeKeyring),
|
||||
"Invalid Keyring %s is configured; valid choices are %s",
|
||||
activeKeyring,
|
||||
keyrings.keySet());
|
||||
return keyrings.get(activeKeyring);
|
||||
}
|
||||
public abstract Keyring provideKeyring(SecretManagerKeyring keyring);
|
||||
|
||||
@Provides
|
||||
@Config("cloudSqlInstanceConnectionName")
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.keyring.api;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.MoreObjects;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.util.ComparingInvocationHandler;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
import javax.annotation.Nullable;
|
||||
import org.bouncycastle.bcpg.BCPGKey;
|
||||
import org.bouncycastle.bcpg.PublicKeyPacket;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
|
||||
/**
|
||||
* Checks that a second keyring returns the same result as the current one.
|
||||
*
|
||||
* <p>Will behave exactly like the "actualKeyring" - as in will throw / return the exact same values
|
||||
* - no matter what the "secondKeyring" does. But will log a warning if "secondKeyring" acts
|
||||
* differently than "actualKeyring".
|
||||
*
|
||||
* <p>If both keyrings threw exceptions, there is no check whether the exeptions are the same. The
|
||||
* assumption is that an error happened in both, but they might report that error differently.
|
||||
*/
|
||||
public final class ComparatorKeyring extends ComparingInvocationHandler<Keyring> {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private ComparatorKeyring(Keyring original, Keyring second) {
|
||||
super(Keyring.class, original, second);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance of Keyring that is an exact proxy of "original".
|
||||
*
|
||||
* <p>This proxy will log any differences in return value or thrown exceptions with "second".
|
||||
*/
|
||||
public static Keyring create(Keyring original, Keyring second) {
|
||||
return new ComparatorKeyring(original, second).makeProxy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void log(Method method, String message) {
|
||||
logger.atSevere().log("ComparatorKeyring.%s: %s", method.getName(), message);
|
||||
}
|
||||
|
||||
/** Implements equals for the PGP classes. */
|
||||
@Override
|
||||
protected boolean compareResults(Method method, @Nullable Object a, @Nullable Object b) {
|
||||
Class<?> clazz = method.getReturnType();
|
||||
if (PGPPublicKey.class.equals(clazz)) {
|
||||
return compare((PGPPublicKey) a, (PGPPublicKey) b);
|
||||
}
|
||||
if (PGPPrivateKey.class.equals(clazz)) {
|
||||
return compare((PGPPrivateKey) a, (PGPPrivateKey) b);
|
||||
}
|
||||
if (PGPKeyPair.class.equals(clazz)) {
|
||||
return compare((PGPKeyPair) a, (PGPKeyPair) b);
|
||||
}
|
||||
return super.compareResults(method, a, b);
|
||||
}
|
||||
|
||||
/** Implements toString for the PGP classes. */
|
||||
@Override
|
||||
protected String stringifyResult(Method method, @Nullable Object a) {
|
||||
Class<?> clazz = method.getReturnType();
|
||||
if (PGPPublicKey.class.equals(clazz)) {
|
||||
return stringify((PGPPublicKey) a);
|
||||
}
|
||||
if (PGPPrivateKey.class.equals(clazz)) {
|
||||
return stringify((PGPPrivateKey) a);
|
||||
}
|
||||
if (PGPKeyPair.class.equals(clazz)) {
|
||||
return stringify((PGPKeyPair) a);
|
||||
}
|
||||
return super.stringifyResult(method, a);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String stringifyThrown(Method method, Throwable throwable) {
|
||||
StringWriter stringWriter = new StringWriter();
|
||||
PrintWriter printWriter = new PrintWriter(stringWriter);
|
||||
throwable.printStackTrace(printWriter);
|
||||
return String.format("%s\nStack trace:\n%s", throwable.toString(), stringWriter.toString());
|
||||
}
|
||||
|
||||
// .equals implementation for PGP types.
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean compare(@Nullable PGPKeyPair a, @Nullable PGPKeyPair b) {
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
return compare(a.getPublicKey(), b.getPublicKey())
|
||||
&& compare(a.getPrivateKey(), b.getPrivateKey());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean compare(@Nullable PGPPublicKey a, @Nullable PGPPublicKey b) {
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
try {
|
||||
return Arrays.equals(a.getFingerprint(), b.getFingerprint())
|
||||
&& Arrays.equals(a.getEncoded(), b.getEncoded());
|
||||
} catch (IOException e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"ComparatorKeyring error: PGPPublicKey.getEncoded failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean compare(@Nullable PGPPrivateKey a, @Nullable PGPPrivateKey b) {
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
return a.getKeyID() == b.getKeyID()
|
||||
&& compare(a.getPrivateKeyDataPacket(), b.getPrivateKeyDataPacket())
|
||||
&& compare(a.getPublicKeyPacket(), b.getPublicKeyPacket());
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean compare(PublicKeyPacket a, PublicKeyPacket b) {
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
try {
|
||||
return Arrays.equals(a.getEncoded(), b.getEncoded());
|
||||
} catch (IOException e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"ComparatorKeyring error: PublicKeyPacket.getEncoded failed.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static boolean compare(BCPGKey a, BCPGKey b) {
|
||||
if (a == null || b == null) {
|
||||
return a == null && b == null;
|
||||
}
|
||||
return Objects.equals(a.getFormat(), b.getFormat())
|
||||
&& Arrays.equals(a.getEncoded(), b.getEncoded());
|
||||
}
|
||||
|
||||
// toString implementations
|
||||
|
||||
@VisibleForTesting
|
||||
static String stringify(PGPKeyPair a) {
|
||||
if (a == null) {
|
||||
return "null";
|
||||
}
|
||||
return MoreObjects.toStringHelper(PGPKeyPair.class)
|
||||
.addValue(stringify(a.getPublicKey()))
|
||||
.addValue(stringify(a.getPrivateKey()))
|
||||
.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String stringify(PGPPublicKey a) {
|
||||
if (a == null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
for (byte b : a.getFingerprint()) {
|
||||
builder.append(String.format("%02x:", b));
|
||||
}
|
||||
return MoreObjects.toStringHelper(PGPPublicKey.class)
|
||||
.add("fingerprint", builder.toString())
|
||||
.toString();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static String stringify(PGPPrivateKey a) {
|
||||
if (a == null) {
|
||||
return "null";
|
||||
}
|
||||
|
||||
// We need to be careful what information we output here. The private key should be private, and
|
||||
// I'm not sure what is safe to put in the logs.
|
||||
return MoreObjects.toStringHelper(PGPPrivateKey.class)
|
||||
.add("keyId", a.getKeyID())
|
||||
.toString();
|
||||
}
|
||||
}
|
||||
@@ -1,133 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.keyring.api;
|
||||
|
||||
import static com.google.common.io.Resources.getResource;
|
||||
import static google.registry.keyring.api.PgpHelper.KeyRequirement.ENCRYPT_SIGN;
|
||||
import static google.registry.keyring.api.PgpHelper.lookupKeyPair;
|
||||
|
||||
import com.google.common.base.VerifyException;
|
||||
import com.google.common.io.ByteSource;
|
||||
import com.google.common.io.Resources;
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import dagger.multibindings.StringKey;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import javax.inject.Named;
|
||||
import org.bouncycastle.openpgp.PGPException;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.PGPUtil;
|
||||
import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRingCollection;
|
||||
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection;
|
||||
|
||||
/**
|
||||
* Dagger keyring module that provides an {@link InMemoryKeyring} instance populated with dummy
|
||||
* values.
|
||||
*
|
||||
* <p>This dummy module allows the domain registry code to compile and run in an unmodified state,
|
||||
* with all attempted outgoing connections failing because the supplied dummy credentials aren't
|
||||
* valid. For a real system that needs to connect with external services, you should replace this
|
||||
* module with one that loads real credentials from secure sources.
|
||||
*
|
||||
* <p>The dummy PGP keyrings are created using gnupg1/pgp1 roughly like the following (using
|
||||
* gnupg2/pgp2 is an exercise left for the developer):
|
||||
*
|
||||
* <pre>{@code
|
||||
* # mkdir gpg
|
||||
* # chmod 700 gpg
|
||||
* # gpg1 --homedir gpg --gen-key <<<EOF
|
||||
* 1
|
||||
* 1024
|
||||
* 0
|
||||
* Y
|
||||
* Test Registry
|
||||
* test-registry@example.com
|
||||
*
|
||||
* O
|
||||
* EOF
|
||||
* [press enter twice at keyring password prompts]
|
||||
* # gpg1 --homedir gpg -a -o pgp-public-keyring.asc --export test-registry@example.com
|
||||
* # gpg1 --homedir gpg -a -o pgp-private-keyring.asc --export-secret-keys test-registry@example.com
|
||||
* # mv pgp*keyring.asc java/google/registry/keyring/api
|
||||
* # rm -rf gpg
|
||||
* }</pre>
|
||||
*/
|
||||
@Module
|
||||
@Immutable
|
||||
public abstract class DummyKeyringModule {
|
||||
|
||||
public static final String NAME = "Dummy";
|
||||
|
||||
/** The contents of a dummy PGP public key stored in a file. */
|
||||
private static final ByteSource PGP_PUBLIC_KEYRING =
|
||||
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-public-keyring.asc"));
|
||||
|
||||
/** The contents of a dummy PGP private key stored in a file. */
|
||||
private static final ByteSource PGP_PRIVATE_KEYRING =
|
||||
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-private-keyring.asc"));
|
||||
|
||||
/** The email address of the aforementioned PGP key. */
|
||||
private static final String EMAIL_ADDRESS = "test-registry@example.com";
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@StringKey(NAME)
|
||||
abstract Keyring provideKeyring(@Named("DummyKeyring") InMemoryKeyring keyring);
|
||||
|
||||
/** Always returns a {@link InMemoryKeyring} instance. */
|
||||
@Provides
|
||||
@Named("DummyKeyring")
|
||||
static InMemoryKeyring provideDummyKeyring() {
|
||||
PGPKeyPair dummyKey;
|
||||
try (InputStream publicInput = PGP_PUBLIC_KEYRING.openStream();
|
||||
InputStream privateInput = PGP_PRIVATE_KEYRING.openStream()) {
|
||||
PGPPublicKeyRingCollection publicKeys =
|
||||
new BcPGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicInput));
|
||||
PGPSecretKeyRingCollection privateKeys =
|
||||
new BcPGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateInput));
|
||||
dummyKey = lookupKeyPair(publicKeys, privateKeys, EMAIL_ADDRESS, ENCRYPT_SIGN);
|
||||
} catch (PGPException | IOException e) {
|
||||
throw new VerifyException("Failed to load PGP keys from jar", e);
|
||||
}
|
||||
// Use the same dummy PGP keypair for all required PGP keys -- a real production system would
|
||||
// have different values for these keys. Pass dummy values for all Strings.
|
||||
return new InMemoryKeyring(
|
||||
dummyKey,
|
||||
dummyKey,
|
||||
dummyKey.getPublicKey(),
|
||||
dummyKey,
|
||||
dummyKey.getPublicKey(),
|
||||
"not a real key",
|
||||
"not a real key",
|
||||
"not a real password",
|
||||
"not a real API key",
|
||||
"not a real login",
|
||||
"not a real password",
|
||||
"not a real login",
|
||||
"not a real credential",
|
||||
"not a real password",
|
||||
"not a real password",
|
||||
"not the real primary connection",
|
||||
"not the real replica connection");
|
||||
}
|
||||
|
||||
private DummyKeyringModule() {}
|
||||
}
|
||||
@@ -1,175 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.keyring.api;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Preconditions.checkNotNull;
|
||||
|
||||
import javax.annotation.concurrent.Immutable;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
|
||||
/** A {@link Keyring} that uses in-memory values for all credentials. */
|
||||
@Immutable
|
||||
public final class InMemoryKeyring implements Keyring {
|
||||
|
||||
private final PGPKeyPair rdeStagingKey;
|
||||
private final PGPKeyPair rdeSigningKey;
|
||||
private final PGPPublicKey rdeReceiverKey;
|
||||
private final PGPKeyPair brdaSigningKey;
|
||||
private final PGPPublicKey brdaEncryptionKey;
|
||||
private final String rdeSshClientPublicKey;
|
||||
private final String rdeSshClientPrivateKey;
|
||||
private final String icannReportingPassword;
|
||||
private final String safeBrowsingAPIKey;
|
||||
private final String marksdbDnlLoginAndPassword;
|
||||
private final String marksdbLordnPassword;
|
||||
private final String marksdbSmdrlLoginAndPassword;
|
||||
private final String bsaApiKey;
|
||||
private final String sqlPrimaryConnectionName;
|
||||
private final String sqlReplicaConnectionName;
|
||||
|
||||
public InMemoryKeyring(
|
||||
PGPKeyPair rdeStagingKey,
|
||||
PGPKeyPair rdeSigningKey,
|
||||
PGPPublicKey rdeReceiverKey,
|
||||
PGPKeyPair brdaSigningKey,
|
||||
PGPPublicKey brdaEncryptionKey,
|
||||
String rdeSshClientPublicKey,
|
||||
String rdeSshClientPrivateKey,
|
||||
String icannReportingPassword,
|
||||
String safeBrowsingAPIKey,
|
||||
String marksdbDnlLoginAndPassword,
|
||||
String marksdbLordnPassword,
|
||||
String marksdbSmdrlLoginAndPassword,
|
||||
String cloudSqlPassword,
|
||||
String toolsCloudSqlPassword,
|
||||
String bsaApiKey,
|
||||
String sqlPrimaryConnectionName,
|
||||
String sqlReplicaConnectionName) {
|
||||
checkArgument(PgpHelper.isSigningKey(rdeSigningKey.getPublicKey()),
|
||||
"RDE signing key must support signing: %s", rdeSigningKey.getKeyID());
|
||||
checkArgument(rdeStagingKey.getPublicKey().isEncryptionKey(),
|
||||
"staging key must support encryption: %s", rdeStagingKey.getKeyID());
|
||||
checkArgument(rdeReceiverKey.isEncryptionKey(),
|
||||
"receiver key must support encryption: %s", rdeReceiverKey.getKeyID());
|
||||
checkArgument(PgpHelper.isSigningKey(brdaSigningKey.getPublicKey()),
|
||||
"BRDA signing key must support signing: %s", brdaSigningKey.getKeyID());
|
||||
checkArgument(brdaEncryptionKey.isEncryptionKey(),
|
||||
"encryption key must support encryption: %s", brdaEncryptionKey.getKeyID());
|
||||
this.rdeStagingKey = rdeStagingKey;
|
||||
this.rdeSigningKey = rdeSigningKey;
|
||||
this.rdeReceiverKey = rdeReceiverKey;
|
||||
this.brdaSigningKey = brdaSigningKey;
|
||||
this.brdaEncryptionKey = brdaEncryptionKey;
|
||||
this.rdeSshClientPublicKey = checkNotNull(rdeSshClientPublicKey, "rdeSshClientPublicKey");
|
||||
this.rdeSshClientPrivateKey = checkNotNull(rdeSshClientPrivateKey, "rdeSshClientPrivateKey");
|
||||
this.icannReportingPassword = checkNotNull(icannReportingPassword, "icannReportingPassword");
|
||||
this.safeBrowsingAPIKey = checkNotNull(safeBrowsingAPIKey, "safeBrowsingAPIKey");
|
||||
this.marksdbDnlLoginAndPassword =
|
||||
checkNotNull(marksdbDnlLoginAndPassword, "marksdbDnlLoginAndPassword");
|
||||
this.marksdbLordnPassword = checkNotNull(marksdbLordnPassword, "marksdbLordnPassword");
|
||||
this.marksdbSmdrlLoginAndPassword =
|
||||
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
|
||||
this.bsaApiKey = checkNotNull(bsaApiKey, "bsaApiKey");
|
||||
this.sqlPrimaryConnectionName = sqlPrimaryConnectionName;
|
||||
this.sqlReplicaConnectionName = sqlReplicaConnectionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPKeyPair getRdeSigningKey() {
|
||||
return rdeSigningKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPublicKey getRdeStagingEncryptionKey() {
|
||||
return rdeStagingKey.getPublicKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPrivateKey getRdeStagingDecryptionKey() {
|
||||
return rdeStagingKey.getPrivateKey();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPublicKey getRdeReceiverKey() {
|
||||
return rdeReceiverKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPKeyPair getBrdaSigningKey() {
|
||||
return brdaSigningKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PGPPublicKey getBrdaReceiverKey() {
|
||||
return brdaEncryptionKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRdeSshClientPublicKey() {
|
||||
return rdeSshClientPublicKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRdeSshClientPrivateKey() {
|
||||
return rdeSshClientPrivateKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIcannReportingPassword() {
|
||||
return icannReportingPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSafeBrowsingAPIKey() {
|
||||
return safeBrowsingAPIKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMarksdbDnlLoginAndPassword() {
|
||||
return marksdbDnlLoginAndPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMarksdbLordnPassword() {
|
||||
return marksdbLordnPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMarksdbSmdrlLoginAndPassword() {
|
||||
return marksdbSmdrlLoginAndPassword;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBsaApiKey() {
|
||||
return bsaApiKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlPrimaryConnectionName() {
|
||||
return sqlPrimaryConnectionName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSqlReplicaConnectionName() {
|
||||
return sqlReplicaConnectionName;
|
||||
}
|
||||
|
||||
/** Does nothing. */
|
||||
@Override
|
||||
public void close() {}
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.keyring.secretmanager;
|
||||
|
||||
import dagger.Binds;
|
||||
import dagger.Module;
|
||||
import dagger.multibindings.IntoMap;
|
||||
import dagger.multibindings.StringKey;
|
||||
import google.registry.keyring.api.Keyring;
|
||||
|
||||
/** Dagger module for {@link Keyring} backed by the Cloud SecretManager. */
|
||||
@Module
|
||||
public abstract class SecretManagerKeyringModule {
|
||||
|
||||
public static final String NAME = "CSM";
|
||||
// TODO(b/257276342): Remove after configs in nomulus-internal are updated.
|
||||
public static final String DEPRECATED_NAME = "KMS";
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@StringKey(DEPRECATED_NAME)
|
||||
abstract Keyring provideDeprecatedKeyring(SecretManagerKeyring keyring);
|
||||
|
||||
@Binds
|
||||
@IntoMap
|
||||
@StringKey(NAME)
|
||||
abstract Keyring provideKeyring(SecretManagerKeyring keyring);
|
||||
}
|
||||
@@ -35,9 +35,7 @@ import google.registry.groups.GmailModule;
|
||||
import google.registry.groups.GroupsModule;
|
||||
import google.registry.groups.GroupssettingsModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.RegistryComponent.RegistryModule;
|
||||
import google.registry.module.RequestComponent.RequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
@@ -69,7 +67,6 @@ import javax.inject.Singleton;
|
||||
CustomLogicFactoryModule.class,
|
||||
DirectoryModule.class,
|
||||
DriveModule.class,
|
||||
DummyKeyringModule.class,
|
||||
GmailModule.class,
|
||||
GroupsModule.class,
|
||||
GroupssettingsModule.class,
|
||||
@@ -81,7 +78,6 @@ import javax.inject.Singleton;
|
||||
PersistenceModule.class,
|
||||
RegistryModule.class,
|
||||
RequestComponentModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
SheetsServiceModule.class,
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
|
||||
package google.registry.module;
|
||||
|
||||
import static google.registry.util.GcpJsonFormatter.setCurrentRequest;
|
||||
import static google.registry.util.GcpJsonFormatter.setCurrentTraceId;
|
||||
import static google.registry.util.GcpJsonFormatter.unsetCurrentRequest;
|
||||
import static google.registry.util.RandomStringGenerator.insecureRandomStringGenerator;
|
||||
import static google.registry.util.StringGenerator.Alphabets.HEX_DIGITS_ONLY;
|
||||
|
||||
@@ -67,10 +69,16 @@ public class RegistryServlet extends ServletBase {
|
||||
@Override
|
||||
public void service(HttpServletRequest req, HttpServletResponse rsp) throws IOException {
|
||||
setCurrentTraceId(traceId());
|
||||
String requestMethod = req.getMethod();
|
||||
String requestUrl = req.getRequestURI();
|
||||
String userAgent = String.valueOf(req.getHeader("User-Agent"));
|
||||
String protocol = req.getProtocol();
|
||||
setCurrentRequest(requestMethod, requestUrl, userAgent, protocol);
|
||||
try {
|
||||
super.service(req, rsp);
|
||||
} finally {
|
||||
setCurrentTraceId(null);
|
||||
unsetCurrentRequest();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -121,6 +121,7 @@ import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
|
||||
import google.registry.ui.server.console.ConsoleUserDataAction;
|
||||
import google.registry.ui.server.console.ConsoleUsersAction;
|
||||
import google.registry.ui.server.console.RegistrarsAction;
|
||||
import google.registry.ui.server.console.domains.ConsoleBulkDomainAction;
|
||||
import google.registry.ui.server.console.settings.ContactAction;
|
||||
import google.registry.ui.server.console.settings.SecurityAction;
|
||||
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
|
||||
@@ -174,6 +175,8 @@ interface RequestComponent {
|
||||
|
||||
CheckApiAction checkApiAction();
|
||||
|
||||
ConsoleBulkDomainAction consoleBulkDomainAction();
|
||||
|
||||
ConsoleDomainGetAction consoleDomainGetAction();
|
||||
|
||||
ConsoleDomainListAction consoleDomainListAction();
|
||||
|
||||
@@ -32,9 +32,7 @@ import google.registry.groups.GmailModule;
|
||||
import google.registry.groups.GroupsModule;
|
||||
import google.registry.groups.GroupssettingsModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.backend.BackendRequestComponent.BackendRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
|
||||
CredentialModule.class,
|
||||
CustomLogicFactoryModule.class,
|
||||
DirectoryModule.class,
|
||||
DummyKeyringModule.class,
|
||||
DriveModule.class,
|
||||
GmailModule.class,
|
||||
GroupsModule.class,
|
||||
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
|
||||
KeyringModule.class,
|
||||
NetHttpTransportModule.class,
|
||||
PersistenceModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
SheetsServiceModule.class,
|
||||
|
||||
@@ -21,7 +21,6 @@ import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.groups.GmailModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.bsa.BsaRequestComponent.BsaRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
@@ -43,7 +42,6 @@ import javax.inject.Singleton;
|
||||
GsonModule.class,
|
||||
PersistenceModule.class,
|
||||
KeyringModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
StackdriverModule.class,
|
||||
UrlConnectionServiceModule.class,
|
||||
|
||||
@@ -27,9 +27,7 @@ import google.registry.groups.GmailModule;
|
||||
import google.registry.groups.GroupsModule;
|
||||
import google.registry.groups.GroupssettingsModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||
@@ -52,7 +50,6 @@ import javax.inject.Singleton;
|
||||
CustomLogicFactoryModule.class,
|
||||
CloudTasksUtilsModule.class,
|
||||
DirectoryModule.class,
|
||||
DummyKeyringModule.class,
|
||||
FrontendRequestComponentModule.class,
|
||||
GmailModule.class,
|
||||
GroupsModule.class,
|
||||
@@ -61,7 +58,6 @@ import javax.inject.Singleton;
|
||||
KeyModule.class,
|
||||
KeyringModule.class,
|
||||
NetHttpTransportModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
StackdriverModule.class,
|
||||
|
||||
@@ -37,6 +37,7 @@ import google.registry.ui.server.console.ConsoleUpdateRegistrarAction;
|
||||
import google.registry.ui.server.console.ConsoleUserDataAction;
|
||||
import google.registry.ui.server.console.ConsoleUsersAction;
|
||||
import google.registry.ui.server.console.RegistrarsAction;
|
||||
import google.registry.ui.server.console.domains.ConsoleBulkDomainAction;
|
||||
import google.registry.ui.server.console.settings.ContactAction;
|
||||
import google.registry.ui.server.console.settings.SecurityAction;
|
||||
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
|
||||
@@ -53,6 +54,8 @@ import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
|
||||
WhiteboxModule.class,
|
||||
})
|
||||
public interface FrontendRequestComponent {
|
||||
ConsoleBulkDomainAction consoleBulkDomainAction();
|
||||
|
||||
ConsoleDomainGetAction consoleDomainGetAction();
|
||||
|
||||
ConsoleDomainListAction consoleDomainListAction();
|
||||
|
||||
@@ -25,9 +25,7 @@ import google.registry.groups.DirectoryModule;
|
||||
import google.registry.groups.GroupsModule;
|
||||
import google.registry.groups.GroupssettingsModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.pubapi.PubApiRequestComponent.PubApiRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
@@ -47,7 +45,6 @@ import javax.inject.Singleton;
|
||||
CredentialModule.class,
|
||||
CustomLogicFactoryModule.class,
|
||||
DirectoryModule.class,
|
||||
DummyKeyringModule.class,
|
||||
GroupsModule.class,
|
||||
GroupssettingsModule.class,
|
||||
GsonModule.class,
|
||||
@@ -56,7 +53,6 @@ import javax.inject.Singleton;
|
||||
NetHttpTransportModule.class,
|
||||
PersistenceModule.class,
|
||||
PubApiRequestComponentModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
StackdriverModule.class,
|
||||
|
||||
@@ -27,9 +27,7 @@ import google.registry.groups.DirectoryModule;
|
||||
import google.registry.groups.GroupsModule;
|
||||
import google.registry.groups.GroupssettingsModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.module.tools.ToolsRequestComponent.ToolsRequestComponentModule;
|
||||
import google.registry.monitoring.whitebox.StackdriverModule;
|
||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||
@@ -49,7 +47,6 @@ import javax.inject.Singleton;
|
||||
CustomLogicFactoryModule.class,
|
||||
CloudTasksUtilsModule.class,
|
||||
DirectoryModule.class,
|
||||
DummyKeyringModule.class,
|
||||
DriveModule.class,
|
||||
GroupsModule.class,
|
||||
GroupssettingsModule.class,
|
||||
@@ -57,7 +54,6 @@ import javax.inject.Singleton;
|
||||
KeyModule.class,
|
||||
KeyringModule.class,
|
||||
NetHttpTransportModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
ServerTridProviderModule.class,
|
||||
StackdriverModule.class,
|
||||
|
||||
@@ -17,7 +17,7 @@ package google.registry.persistence;
|
||||
import dagger.Component;
|
||||
import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.persistence.PersistenceModule.DefaultJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.ReadOnlyReplicaJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
@@ -32,8 +32,8 @@ import javax.inject.Singleton;
|
||||
modules = {
|
||||
ConfigModule.class,
|
||||
CredentialModule.class,
|
||||
KeyringModule.class,
|
||||
PersistenceModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
UtilsModule.class
|
||||
})
|
||||
|
||||
@@ -34,13 +34,10 @@ import dagger.BindsOptionalOf;
|
||||
import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
||||
import google.registry.persistence.transaction.TransactionManager;
|
||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||
import google.registry.privileges.secretmanager.SqlCredential;
|
||||
import google.registry.privileges.secretmanager.SqlCredentialStore;
|
||||
import google.registry.privileges.secretmanager.SqlUser;
|
||||
@@ -66,7 +63,7 @@ import javax.inject.Singleton;
|
||||
import org.hibernate.cfg.Environment;
|
||||
|
||||
/** Dagger module class for the persistence layer. */
|
||||
@Module(includes = {KeyringModule.class, SecretManagerModule.class, DummyKeyringModule.class})
|
||||
@Module
|
||||
public abstract class PersistenceModule {
|
||||
|
||||
// This name must be the same as the one defined in persistence.xml.
|
||||
|
||||
@@ -71,6 +71,7 @@ import java.util.NoSuchElementException;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
@@ -177,9 +178,9 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||
if (!getHibernateAllowNestedTransactions()) {
|
||||
throw new IllegalStateException(NESTED_TRANSACTION_MESSAGE);
|
||||
}
|
||||
if (RegistryEnvironment.get() != RegistryEnvironment.PRODUCTION
|
||||
&& RegistryEnvironment.get() != RegistryEnvironment.UNITTEST) {
|
||||
logger.atWarning().withStackTrace(StackSize.MEDIUM).log(NESTED_TRANSACTION_MESSAGE);
|
||||
if (RegistryEnvironment.get() != RegistryEnvironment.UNITTEST) {
|
||||
logger.atWarning().withStackTrace(StackSize.MEDIUM).atMostEvery(1, TimeUnit.MINUTES).log(
|
||||
NESTED_TRANSACTION_MESSAGE);
|
||||
}
|
||||
// This prevents inner transaction from retrying, thus avoiding a cascade retry effect.
|
||||
return transactNoRetry(isolationLevel, work);
|
||||
|
||||
@@ -52,7 +52,7 @@ final class DeleteAllocationTokensCommand extends UpdateOrDeleteAllocationTokens
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
tokensToDelete = getTokenKeys(tokens, prefix);
|
||||
tokensToDelete = tm().transact(() -> getTokenKeys(tokens, prefix));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -136,7 +136,7 @@ abstract class EppToolCommand extends ConfirmingCommand implements CommandWithCo
|
||||
params.put("dryRun", dryRun);
|
||||
params.put("clientId", command.clientId);
|
||||
params.put("superuser", superuser);
|
||||
params.put("xml", URLEncoder.encode(command.xml, UTF_8.toString()));
|
||||
params.put("xml", URLEncoder.encode(command.xml, UTF_8));
|
||||
String requestBody =
|
||||
Joiner.on('&').withKeyValueSeparator("=").join(filterValues(params, Objects::nonNull));
|
||||
responses.add(
|
||||
|
||||
@@ -43,7 +43,8 @@ import org.postgresql.util.PSQLException;
|
||||
final class RegistryCli implements CommandRunner {
|
||||
|
||||
private static final ImmutableSet<RegistryToolEnvironment> DEFAULT_GKE_ENVIRONMENTS =
|
||||
ImmutableSet.of(RegistryToolEnvironment.ALPHA, RegistryToolEnvironment.QA);
|
||||
ImmutableSet.of(
|
||||
RegistryToolEnvironment.ALPHA, RegistryToolEnvironment.CRASH, RegistryToolEnvironment.QA);
|
||||
|
||||
// The environment parameter is parsed twice: once here, and once with {@link
|
||||
// RegistryToolEnvironment#parseFromArgs} in the {@link RegistryTool#main} function.
|
||||
|
||||
@@ -27,9 +27,7 @@ import google.registry.dns.writer.VoidDnsWriterModule;
|
||||
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
|
||||
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
|
||||
import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.model.ModelModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
|
||||
ConfigModule.class,
|
||||
CloudDnsWriterModule.class,
|
||||
CloudTasksUtilsModule.class,
|
||||
DummyKeyringModule.class,
|
||||
DnsUpdateWriterModule.class,
|
||||
GsonModule.class,
|
||||
KeyModule.class,
|
||||
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
|
||||
RdeModule.class,
|
||||
RegistryToolDataflowModule.class,
|
||||
RequestFactoryModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
UrlConnectionServiceModule.class,
|
||||
UtilsModule.class,
|
||||
|
||||
@@ -20,6 +20,7 @@ import static com.google.common.base.Verify.verify;
|
||||
import static com.google.common.net.HttpHeaders.X_REQUESTED_WITH;
|
||||
import static com.google.common.net.MediaType.JSON_UTF_8;
|
||||
import static google.registry.config.ConfigUtils.makeUrl;
|
||||
import static google.registry.config.RegistryConfig.CANARY_HEADER;
|
||||
import static google.registry.security.JsonHttp.JSON_SAFETY_PREFIX;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
@@ -58,8 +59,6 @@ public class ServiceConnection {
|
||||
/** Pattern to heuristically extract title tag contents in HTML responses. */
|
||||
protected static final Pattern HTML_TITLE_TAG_PATTERN = Pattern.compile("<title>(.*?)</title>");
|
||||
|
||||
private static final String CANARY_HEADER = "canary";
|
||||
|
||||
private final Service service;
|
||||
private final boolean useCanary;
|
||||
private final HttpRequestFactory requestFactory;
|
||||
|
||||
@@ -59,21 +59,16 @@ abstract class UpdateOrDeleteAllocationTokensCommand extends ConfirmingCommand {
|
||||
.map(token -> VKey.create(AllocationToken.class, token))
|
||||
.collect(toImmutableList());
|
||||
ImmutableList<VKey<AllocationToken>> nonexistentKeys =
|
||||
tm().transact(
|
||||
() -> keys.stream().filter(key -> !tm().exists(key)).collect(toImmutableList()));
|
||||
keys.stream().filter(key -> !tm().exists(key)).collect(toImmutableList());
|
||||
checkState(nonexistentKeys.isEmpty(), "Tokens with keys %s did not exist", nonexistentKeys);
|
||||
return keys;
|
||||
} else {
|
||||
checkArgument(!prefix.isEmpty(), "Provided prefix should not be blank");
|
||||
return tm().transact(
|
||||
() ->
|
||||
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()));
|
||||
return 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,228 +0,0 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.escape.Escaper;
|
||||
import com.google.common.xml.XmlEscapers;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.flows.StatelessRequestSessionMetadata;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.Result;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.OptionalJsonPayload;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Console endpoint to perform the same action to a list of domains.
|
||||
*
|
||||
* <p>All requests must include the {@link BulkAction} to perform as well as a {@link
|
||||
* BulkDomainList} of domains on which to apply the action. The remaining contents of the request
|
||||
* body depend on the type of action -- some requests may require more data than others.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.GaeService.DEFAULT,
|
||||
gkeService = Action.GkeService.CONSOLE,
|
||||
path = ConsoleBulkDomainAction.PATH,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
|
||||
public static final String PATH = "/console-api/bulk-domain";
|
||||
|
||||
private static Escaper XML_ESCAPER = XmlEscapers.xmlContentEscaper();
|
||||
|
||||
public enum BulkAction {
|
||||
DELETE,
|
||||
SUSPEND
|
||||
}
|
||||
|
||||
/** All requests must include at least a list of domain names on which to perform the action. */
|
||||
public record BulkDomainList(@Expose List<String> domainList) {}
|
||||
|
||||
public record BulkDomainDeleteRequest(@Expose String reason) {}
|
||||
|
||||
public record BulkDomainSuspendRequest(@Expose String reason) {}
|
||||
|
||||
private static final String DOMAIN_DELETE_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<extension>
|
||||
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>%REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>true</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryConsole</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private static final String DOMAIN_SUSPEND_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp
|
||||
xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
<domain:add>
|
||||
<domain:status s="serverDeleteProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverHold" lang="en"></domain:status>
|
||||
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverTransferProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverUpdateProhibited" lang="en"></domain:status>
|
||||
</domain:add>
|
||||
<domain:rem></domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
<extension>
|
||||
<metadata:metadata
|
||||
xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>Console suspension: %REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryTool</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private final EppController eppController;
|
||||
private final String registrarId;
|
||||
private final String bulkDomainAction;
|
||||
private final Optional<JsonElement> optionalJsonPayload;
|
||||
|
||||
@Inject
|
||||
public ConsoleBulkDomainAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
EppController eppController,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("bulkDomainAction") String bulkDomainAction,
|
||||
@OptionalJsonPayload Optional<JsonElement> optionalJsonPayload) {
|
||||
super(consoleApiParams);
|
||||
this.eppController = eppController;
|
||||
this.registrarId = registrarId;
|
||||
this.bulkDomainAction = bulkDomainAction;
|
||||
this.optionalJsonPayload = optionalJsonPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postHandler(User user) {
|
||||
BulkAction bulkAction = BulkAction.valueOf(bulkDomainAction);
|
||||
JsonElement jsonPayload =
|
||||
optionalJsonPayload.orElseThrow(
|
||||
() -> new IllegalArgumentException("Bulk action payload must be present"));
|
||||
BulkDomainList domainList = consoleApiParams.gson().fromJson(jsonPayload, BulkDomainList.class);
|
||||
checkPermission(user, registrarId, ConsolePermission.EXECUTE_EPP_COMMANDS);
|
||||
ImmutableMap<String, ConsoleEppOutput> result =
|
||||
switch (bulkAction) {
|
||||
case DELETE -> handleBulkDelete(jsonPayload, domainList, user);
|
||||
case SUSPEND -> handleBulkSuspend(jsonPayload, domainList, user);
|
||||
};
|
||||
// Front end should parse situations where only some commands worked
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(result));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ConsoleEppOutput> handleBulkDelete(
|
||||
JsonElement jsonPayload, BulkDomainList domainList, User user) {
|
||||
String reason =
|
||||
consoleApiParams.gson().fromJson(jsonPayload, BulkDomainDeleteRequest.class).reason;
|
||||
return runCommandOverDomains(
|
||||
domainList,
|
||||
DOMAIN_DELETE_XML,
|
||||
new ImmutableMap.Builder<String, String>().put("REASON", reason),
|
||||
user);
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ConsoleEppOutput> handleBulkSuspend(
|
||||
JsonElement jsonPayload, BulkDomainList domainList, User user) {
|
||||
String reason =
|
||||
consoleApiParams.gson().fromJson(jsonPayload, BulkDomainSuspendRequest.class).reason;
|
||||
return runCommandOverDomains(
|
||||
domainList,
|
||||
DOMAIN_SUSPEND_XML,
|
||||
new ImmutableMap.Builder<String, String>().put("REASON", reason),
|
||||
user);
|
||||
}
|
||||
|
||||
/** Runs the provided XML template and substitutions over a provided list of domains. */
|
||||
private ImmutableMap<String, ConsoleEppOutput> runCommandOverDomains(
|
||||
BulkDomainList domainList,
|
||||
String xmlTemplate,
|
||||
ImmutableMap.Builder<String, String> replacements,
|
||||
User user) {
|
||||
return domainList.domainList.stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
d -> d,
|
||||
d ->
|
||||
executeEpp(
|
||||
fillSubstitutions(xmlTemplate, replacements.put("DOMAIN_NAME", d)), user)));
|
||||
}
|
||||
|
||||
private ConsoleEppOutput executeEpp(String xml, User user) {
|
||||
return ConsoleEppOutput.fromEppOutput(
|
||||
eppController.handleEppCommand(
|
||||
new StatelessRequestSessionMetadata(
|
||||
registrarId, ProtocolDefinition.getVisibleServiceExtensionUris()),
|
||||
new PasswordOnlyTransportCredentials(),
|
||||
EppRequestSource.CONSOLE,
|
||||
false,
|
||||
user.getUserRoles().isAdmin(),
|
||||
xml.getBytes(UTF_8)));
|
||||
}
|
||||
|
||||
/** Fills the provided XML template with the replacement values, including escaping the values. */
|
||||
private String fillSubstitutions(
|
||||
String xmlTemplate, ImmutableMap.Builder<String, String> replacements) {
|
||||
String xml = xmlTemplate;
|
||||
for (Map.Entry<String, String> entry : replacements.buildKeepingLast().entrySet()) {
|
||||
xml = xml.replaceAll("%" + entry.getKey() + "%", XML_ESCAPER.escape(entry.getValue()));
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
public record ConsoleEppOutput(@Expose String message, @Expose int responseCode) {
|
||||
static ConsoleEppOutput fromEppOutput(EppOutput eppOutput) {
|
||||
Result result = eppOutput.getResponse().getResult();
|
||||
return new ConsoleEppOutput(result.getMsg(), result.getCode().code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
||||
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.annotations.Expose;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppRequestSource;
|
||||
import google.registry.flows.PasswordOnlyTransportCredentials;
|
||||
import google.registry.flows.StatelessRequestSessionMetadata;
|
||||
import google.registry.model.console.User;
|
||||
import google.registry.model.eppcommon.ProtocolDefinition;
|
||||
import google.registry.model.eppoutput.EppOutput;
|
||||
import google.registry.model.eppoutput.Result;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.OptionalJsonPayload;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.ui.server.console.ConsoleApiAction;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Console endpoint to perform the same action to a list of domains.
|
||||
*
|
||||
* <p>All requests must include the {@link ConsoleDomainActionType.BulkAction} to perform as well as
|
||||
* a {@link BulkDomainList} of domains on which to apply the action. The remaining contents of the
|
||||
* request body depend on the type of action -- some requests may require more data than others.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.GaeService.DEFAULT,
|
||||
gkeService = Action.GkeService.CONSOLE,
|
||||
path = ConsoleBulkDomainAction.PATH,
|
||||
method = Action.Method.POST,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public class ConsoleBulkDomainAction extends ConsoleApiAction {
|
||||
|
||||
public static final String PATH = "/console-api/bulk-domain";
|
||||
|
||||
/** All requests must include at least a list of domain names on which to perform the action. */
|
||||
public record BulkDomainList(@Expose List<String> domainList) {}
|
||||
|
||||
private final EppController eppController;
|
||||
private final String registrarId;
|
||||
private final String bulkDomainAction;
|
||||
private final Optional<JsonElement> optionalJsonPayload;
|
||||
|
||||
@Inject
|
||||
public ConsoleBulkDomainAction(
|
||||
ConsoleApiParams consoleApiParams,
|
||||
EppController eppController,
|
||||
@Parameter("registrarId") String registrarId,
|
||||
@Parameter("bulkDomainAction") String bulkDomainAction,
|
||||
@OptionalJsonPayload Optional<JsonElement> optionalJsonPayload) {
|
||||
super(consoleApiParams);
|
||||
this.eppController = eppController;
|
||||
this.registrarId = registrarId;
|
||||
this.bulkDomainAction = bulkDomainAction;
|
||||
this.optionalJsonPayload = optionalJsonPayload;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postHandler(User user) {
|
||||
// Temporary flag while testing
|
||||
if (!user.getUserRoles().isAdmin()) {
|
||||
consoleApiParams.response().setStatus(SC_FORBIDDEN);
|
||||
return;
|
||||
}
|
||||
JsonElement jsonPayload =
|
||||
optionalJsonPayload.orElseThrow(
|
||||
() -> new IllegalArgumentException("Bulk action payload must be present"));
|
||||
BulkDomainList domainList = consoleApiParams.gson().fromJson(jsonPayload, BulkDomainList.class);
|
||||
ConsoleDomainActionType actionType =
|
||||
ConsoleDomainActionType.parseActionType(bulkDomainAction, jsonPayload);
|
||||
|
||||
checkPermission(user, registrarId, actionType.getNecessaryPermission());
|
||||
|
||||
ImmutableMap<String, ConsoleEppOutput> result =
|
||||
domainList.domainList.stream()
|
||||
.collect(
|
||||
toImmutableMap(d -> d, d -> executeEpp(actionType.getXmlContentsToRun(d), user)));
|
||||
// Front end should parse situations where only some commands worked
|
||||
consoleApiParams.response().setPayload(consoleApiParams.gson().toJson(result));
|
||||
consoleApiParams.response().setStatus(SC_OK);
|
||||
}
|
||||
|
||||
private ConsoleEppOutput executeEpp(String xml, User user) {
|
||||
return ConsoleEppOutput.fromEppOutput(
|
||||
eppController.handleEppCommand(
|
||||
new StatelessRequestSessionMetadata(
|
||||
registrarId, ProtocolDefinition.getVisibleServiceExtensionUris()),
|
||||
new PasswordOnlyTransportCredentials(),
|
||||
EppRequestSource.CONSOLE,
|
||||
false,
|
||||
user.getUserRoles().isAdmin(),
|
||||
xml.getBytes(UTF_8)));
|
||||
}
|
||||
|
||||
public record ConsoleEppOutput(@Expose String message, @Expose int responseCode) {
|
||||
static ConsoleEppOutput fromEppOutput(EppOutput eppOutput) {
|
||||
Result result = eppOutput.getResponse().getResult();
|
||||
return new ConsoleEppOutput(result.getMsg(), result.getCode().code);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
|
||||
/** An action that will run a delete EPP command on the given domain. */
|
||||
public class ConsoleBulkDomainDeleteActionType implements ConsoleDomainActionType {
|
||||
|
||||
private static final String DOMAIN_DELETE_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<delete>
|
||||
<domain:delete
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
</domain:delete>
|
||||
</delete>
|
||||
<extension>
|
||||
<metadata:metadata xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>%REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>true</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryConsole</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private final String reason;
|
||||
|
||||
public ConsoleBulkDomainDeleteActionType(JsonElement jsonElement) {
|
||||
this.reason = jsonElement.getAsJsonObject().get("reason").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getXmlContentsToRun(String domainName) {
|
||||
return ConsoleDomainActionType.fillSubstitutions(
|
||||
DOMAIN_DELETE_XML, ImmutableMap.of("DOMAIN_NAME", domainName, "REASON", reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsolePermission getNecessaryPermission() {
|
||||
return ConsolePermission.EXECUTE_EPP_COMMANDS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.gson.JsonElement;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
|
||||
/** An action that will suspend the given domain, assigning all 5 server*Prohibited statuses. */
|
||||
public class ConsoleBulkDomainSuspendActionType implements ConsoleDomainActionType {
|
||||
|
||||
private static final String DOMAIN_SUSPEND_XML =
|
||||
"""
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<epp
|
||||
xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>%DOMAIN_NAME%</domain:name>
|
||||
<domain:add>
|
||||
<domain:status s="serverDeleteProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverHold" lang="en"></domain:status>
|
||||
<domain:status s="serverRenewProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverTransferProhibited" lang="en"></domain:status>
|
||||
<domain:status s="serverUpdateProhibited" lang="en"></domain:status>
|
||||
</domain:add>
|
||||
<domain:rem></domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
<extension>
|
||||
<metadata:metadata
|
||||
xmlns:metadata="urn:google:params:xml:ns:metadata-1.0">
|
||||
<metadata:reason>Console suspension: %REASON%</metadata:reason>
|
||||
<metadata:requestedByRegistrar>false</metadata:requestedByRegistrar>
|
||||
</metadata:metadata>
|
||||
</extension>
|
||||
<clTRID>RegistryConsole</clTRID>
|
||||
</command>
|
||||
</epp>""";
|
||||
|
||||
private final String reason;
|
||||
|
||||
public ConsoleBulkDomainSuspendActionType(JsonElement jsonElement) {
|
||||
this.reason = jsonElement.getAsJsonObject().get("reason").getAsString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getXmlContentsToRun(String domainName) {
|
||||
return ConsoleDomainActionType.fillSubstitutions(
|
||||
DOMAIN_SUSPEND_XML, ImmutableMap.of("DOMAIN_NAME", domainName, "REASON", reason));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ConsolePermission getNecessaryPermission() {
|
||||
return ConsolePermission.SUSPEND_DOMAIN;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.escape.Escaper;
|
||||
import com.google.common.xml.XmlEscapers;
|
||||
import com.google.gson.JsonElement;
|
||||
import google.registry.model.console.ConsolePermission;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* A type of EPP action to perform on domain(s), run by the {@link ConsoleBulkDomainAction}.
|
||||
*
|
||||
* <p>Each {@link BulkAction} defines the class that implements that action, including the EPP XML
|
||||
* that will be run and the permission required.
|
||||
*/
|
||||
public interface ConsoleDomainActionType {
|
||||
|
||||
enum BulkAction {
|
||||
DELETE(ConsoleBulkDomainDeleteActionType.class),
|
||||
SUSPEND(ConsoleBulkDomainSuspendActionType.class);
|
||||
|
||||
private final Class<? extends ConsoleDomainActionType> actionClass;
|
||||
|
||||
BulkAction(Class<? extends ConsoleDomainActionType> actionClass) {
|
||||
this.actionClass = actionClass;
|
||||
}
|
||||
|
||||
public Class<? extends ConsoleDomainActionType> getActionClass() {
|
||||
return actionClass;
|
||||
}
|
||||
}
|
||||
|
||||
Escaper XML_ESCAPER = XmlEscapers.xmlContentEscaper();
|
||||
|
||||
static String fillSubstitutions(String xmlTemplate, ImmutableMap<String, String> replacements) {
|
||||
String xml = xmlTemplate;
|
||||
for (Map.Entry<String, String> entry : replacements.entrySet()) {
|
||||
xml = xml.replaceAll("%" + entry.getKey() + "%", XML_ESCAPER.escape(entry.getValue()));
|
||||
}
|
||||
return xml;
|
||||
}
|
||||
|
||||
String getXmlContentsToRun(String domainName);
|
||||
|
||||
ConsolePermission getNecessaryPermission();
|
||||
|
||||
static ConsoleDomainActionType parseActionType(String bulkDomainAction, JsonElement jsonElement) {
|
||||
BulkAction bulkAction = BulkAction.valueOf(bulkDomainAction);
|
||||
try {
|
||||
return bulkAction.getActionClass().getConstructor(JsonElement.class).newInstance(jsonElement);
|
||||
} catch (ReflectiveOperationException e) {
|
||||
throw new RuntimeException(e); // shouldn't happen
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,6 @@ package google.registry.export;
|
||||
import static com.google.common.net.MediaType.PLAIN_TEXT_UTF_8;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.export.ExportPremiumTermsAction.EXPORT_MIME_TYPE;
|
||||
import static google.registry.export.ExportPremiumTermsAction.PREMIUM_TERMS_FILENAME;
|
||||
import static google.registry.testing.DatabaseHelper.createTld;
|
||||
import static google.registry.testing.DatabaseHelper.deleteTld;
|
||||
import static google.registry.testing.DatabaseHelper.persistResource;
|
||||
@@ -52,11 +51,10 @@ import org.junit.jupiter.api.extension.RegisterExtension;
|
||||
/** Unit tests for {@link ExportPremiumTermsAction}. */
|
||||
public class ExportPremiumTermsActionTest {
|
||||
|
||||
private static final String DISCLAIMER_WITH_NEWLINE = "# Premium Terms Export Disclaimer\n";
|
||||
private static final ImmutableList<String> PREMIUM_NAMES =
|
||||
ImmutableList.of("2048,USD 549", "0,USD 549");
|
||||
private static final String EXPECTED_FILE_CONTENT =
|
||||
DISCLAIMER_WITH_NEWLINE + "0, 549.00\n" + "2048, 549.00\n";
|
||||
"# Premium Terms Export Disclaimer\n# TLD: tld\n0, 549.00\n" + "2048, 549.00\n";
|
||||
|
||||
@RegisterExtension
|
||||
final JpaIntegrationTestExtension jpa =
|
||||
@@ -69,7 +67,7 @@ public class ExportPremiumTermsActionTest {
|
||||
ExportPremiumTermsAction action = new ExportPremiumTermsAction();
|
||||
action.response = response;
|
||||
action.driveConnection = driveConnection;
|
||||
action.exportDisclaimer = DISCLAIMER_WITH_NEWLINE;
|
||||
action.exportDisclaimer = "# Premium Terms Export Disclaimer\n";
|
||||
action.tldStr = tld;
|
||||
action.run();
|
||||
}
|
||||
@@ -94,7 +92,7 @@ public class ExportPremiumTermsActionTest {
|
||||
|
||||
verify(driveConnection)
|
||||
.createOrUpdateFile(
|
||||
PREMIUM_TERMS_FILENAME,
|
||||
"CONFIDENTIAL_premium_terms_tld.txt",
|
||||
EXPORT_MIME_TYPE,
|
||||
"folder_id",
|
||||
EXPECTED_FILE_CONTENT.getBytes(UTF_8));
|
||||
@@ -157,7 +155,7 @@ public class ExportPremiumTermsActionTest {
|
||||
|
||||
verify(driveConnection)
|
||||
.createOrUpdateFile(
|
||||
PREMIUM_TERMS_FILENAME,
|
||||
"CONFIDENTIAL_premium_terms_tld.txt",
|
||||
EXPORT_MIME_TYPE,
|
||||
"bad_folder_id",
|
||||
EXPECTED_FILE_CONTENT.getBytes(UTF_8));
|
||||
|
||||
@@ -22,7 +22,6 @@ import static google.registry.flows.FlowTestCase.UserPrivileges.SUPERUSER;
|
||||
import static google.registry.model.billing.BillingBase.Flag.ANCHOR_TENANT;
|
||||
import static google.registry.model.billing.BillingBase.Flag.RESERVED;
|
||||
import static google.registry.model.billing.BillingBase.Flag.SUNRISE;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.DEFAULT;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.NONPREMIUM;
|
||||
import static google.registry.model.billing.BillingBase.RenewalPriceBehavior.SPECIFIED;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
|
||||
@@ -87,7 +86,6 @@ import google.registry.flows.domain.DomainCreateFlow.BulkDomainRegisteredForTooM
|
||||
import google.registry.flows.domain.DomainCreateFlow.MustHaveSignedMarksInCurrentPhaseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.NoGeneralRegistrationsInCurrentPhaseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.NoTrademarkedRegistrationsBeforeSunriseException;
|
||||
import google.registry.flows.domain.DomainCreateFlow.RenewalPriceInfo;
|
||||
import google.registry.flows.domain.DomainCreateFlow.SignedMarksOnlyDuringSunriseException;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkExpiredException;
|
||||
import google.registry.flows.domain.DomainFlowTmchUtils.FoundMarkNotYetValidException;
|
||||
@@ -303,10 +301,8 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
|
||||
boolean isAnchorTenant = expectedBillingFlags.contains(ANCHOR_TENANT);
|
||||
// Set up the creation cost.
|
||||
BigDecimal createCost =
|
||||
isDomainPremium(getUniqueIdFromCommand(), clock.nowUtc())
|
||||
? BigDecimal.valueOf(200)
|
||||
: BigDecimal.valueOf(24);
|
||||
boolean isDomainPremium = isDomainPremium(getUniqueIdFromCommand(), clock.nowUtc());
|
||||
BigDecimal createCost = isDomainPremium ? BigDecimal.valueOf(200) : BigDecimal.valueOf(24);
|
||||
if (isAnchorTenant) {
|
||||
createCost = BigDecimal.ZERO;
|
||||
}
|
||||
@@ -315,6 +311,26 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
createCost.multiply(
|
||||
BigDecimal.valueOf(1 - RegistryConfig.getSunriseDomainCreateDiscount()));
|
||||
}
|
||||
if (allocationToken != null) {
|
||||
if (allocationToken
|
||||
.getRegistrationBehavior()
|
||||
.equals(RegistrationBehavior.NONPREMIUM_CREATE)) {
|
||||
createCost =
|
||||
createCost.subtract(
|
||||
BigDecimal.valueOf(isDomainPremium ? 87 : 0)); // premium is 100, standard 13
|
||||
}
|
||||
if (allocationToken.getRenewalPriceBehavior().equals(NONPREMIUM)) {
|
||||
createCost =
|
||||
createCost.subtract(
|
||||
BigDecimal.valueOf(isDomainPremium ? 89 : 0)); // premium is 100, standard 11
|
||||
}
|
||||
if (allocationToken.getRenewalPriceBehavior().equals(SPECIFIED)) {
|
||||
createCost =
|
||||
createCost
|
||||
.subtract(BigDecimal.valueOf(isDomainPremium ? 100 : 11))
|
||||
.add(allocationToken.getRenewalPrice().get().getAmount());
|
||||
}
|
||||
}
|
||||
FeesAndCredits feesAndCredits =
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
@@ -343,8 +359,12 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.hasType(HistoryEntry.Type.DOMAIN_CREATE)
|
||||
.and()
|
||||
.hasPeriodYears(2);
|
||||
RenewalPriceInfo renewalPriceInfo =
|
||||
DomainCreateFlow.getRenewalPriceInfo(isAnchorTenant, Optional.ofNullable(allocationToken));
|
||||
RenewalPriceBehavior expectedRenewalPriceBehavior =
|
||||
isAnchorTenant
|
||||
? RenewalPriceBehavior.NONPREMIUM
|
||||
: Optional.ofNullable(allocationToken)
|
||||
.map(AllocationToken::getRenewalPriceBehavior)
|
||||
.orElse(RenewalPriceBehavior.DEFAULT);
|
||||
// There should be one bill for the create and one for the recurrence autorenew event.
|
||||
BillingEvent createBillingEvent =
|
||||
new BillingEvent.Builder()
|
||||
@@ -369,8 +389,11 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
.setEventTime(domain.getRegistrationExpirationTime())
|
||||
.setRecurrenceEndTime(END_OF_TIME)
|
||||
.setDomainHistory(historyEntry)
|
||||
.setRenewalPriceBehavior(renewalPriceInfo.renewalPriceBehavior())
|
||||
.setRenewalPrice(renewalPriceInfo.renewalPrice())
|
||||
.setRenewalPriceBehavior(expectedRenewalPriceBehavior)
|
||||
.setRenewalPrice(
|
||||
Optional.ofNullable(allocationToken)
|
||||
.flatMap(AllocationToken::getRenewalPrice)
|
||||
.orElse(null))
|
||||
.build();
|
||||
|
||||
ImmutableSet.Builder<BillingBase> expectedBillingEvents =
|
||||
@@ -3187,85 +3210,62 @@ class DomainCreateFlowTest extends ResourceFlowTestCase<DomainCreateFlow, Domain
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_isAnchorTenantWithoutToken_returnsNonPremiumAndNullPrice() {
|
||||
assertThat(DomainCreateFlow.getRenewalPriceInfo(true, Optional.empty()))
|
||||
.isEqualTo(RenewalPriceInfo.create(NONPREMIUM, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_isAnchorTenantWithDefaultToken_returnsNonPremiumAndNullPrice() {
|
||||
assertThat(DomainCreateFlow.getRenewalPriceInfo(true, Optional.of(allocationToken)))
|
||||
.isEqualTo(RenewalPriceInfo.create(NONPREMIUM, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_isNotAnchorTenantWithDefaultToken_returnsDefaultAndNullPrice() {
|
||||
assertThat(DomainCreateFlow.getRenewalPriceInfo(false, Optional.of(allocationToken)))
|
||||
.isEqualTo(RenewalPriceInfo.create(DEFAULT, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_isNotAnchorTenantWithoutToken_returnsDefaultAndNullPrice() {
|
||||
assertThat(DomainCreateFlow.getRenewalPriceInfo(false, Optional.empty()))
|
||||
.isEqualTo(RenewalPriceInfo.create(DEFAULT, null));
|
||||
}
|
||||
|
||||
@Test
|
||||
void
|
||||
testGetRenewalPriceInfo_isNotAnchorTenantWithSpecifiedInToken_returnsSpecifiedAndCreatePrice() {
|
||||
void testSuccess_anchorTenant_nonPremiumRenewal() throws Exception {
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 5))
|
||||
.setDomainName("example.tld")
|
||||
.setRegistrationBehavior(RegistrationBehavior.ANCHOR_TENANT)
|
||||
.build());
|
||||
assertThat(DomainCreateFlow.getRenewalPriceInfo(false, Optional.of(token)))
|
||||
.isEqualTo(RenewalPriceInfo.create(SPECIFIED, Money.of(USD, 5)));
|
||||
persistContactsAndHosts();
|
||||
setEppInput(
|
||||
"domain_create_allocationtoken.xml",
|
||||
ImmutableMap.of("DOMAIN", "example.tld", "YEARS", "2"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("tld", ImmutableSet.of(ANCHOR_TENANT), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_isAnchorTenantWithSpecifiedStateInToken_throwsError() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
DomainCreateFlow.getRenewalPriceInfo(
|
||||
true,
|
||||
Optional.of(
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 0))
|
||||
.build()))));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Renewal price behavior cannot be SPECIFIED for anchor tenant");
|
||||
void testSuccess_nonAnchorTenant_nonPremiumRenewal() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("rich.example")
|
||||
.setRenewalPriceBehavior(NONPREMIUM)
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
// Creation is still $100 but it'll create a NONPREMIUM renewal
|
||||
setEppInput(
|
||||
"domain_create_premium_allocationtoken.xml",
|
||||
ImmutableMap.of("YEARS", "2", "FEE", "111.00"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("example", ImmutableSet.of(), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetRenewalPriceInfo_withInvalidRenewalPriceBehavior_throwsError() {
|
||||
IllegalArgumentException thrown =
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
DomainCreateFlow.getRenewalPriceInfo(
|
||||
true,
|
||||
Optional.of(
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setRenewalPriceBehavior(RenewalPriceBehavior.valueOf("INVALID"))
|
||||
.build()))));
|
||||
assertThat(thrown)
|
||||
.hasMessageThat()
|
||||
.isEqualTo(
|
||||
"No enum constant"
|
||||
+ " google.registry.model.billing.BillingBase.RenewalPriceBehavior.INVALID");
|
||||
void testSuccess_specifiedRenewalPriceToken_specifiedRecurrencePrice() throws Exception {
|
||||
createTld("example");
|
||||
AllocationToken token =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("rich.example")
|
||||
.setRenewalPriceBehavior(SPECIFIED)
|
||||
.setRenewalPrice(Money.of(USD, 1))
|
||||
.build());
|
||||
persistContactsAndHosts();
|
||||
// Creation is still $100 but it'll create a $1 renewal
|
||||
setEppInput(
|
||||
"domain_create_premium_allocationtoken.xml",
|
||||
ImmutableMap.of("YEARS", "2", "FEE", "101.00"));
|
||||
runFlow();
|
||||
assertSuccessfulCreate("example", ImmutableSet.of(), token);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -1127,7 +1127,7 @@ public class DomainPricingLogicTest {
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("13.00"), CREATE, false))
|
||||
.build());
|
||||
// Two-year create should be 13 (standard price) + 100 (premium price)
|
||||
// Two-year create should be 13 (standard price) + 100 (premium price), and it's premium
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld,
|
||||
@@ -1140,7 +1140,7 @@ public class DomainPricingLogicTest {
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("113.00"), CREATE, false))
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("113.00"), CREATE, true))
|
||||
.build());
|
||||
assertThat(
|
||||
domainPricingLogic.getRenewPrice(
|
||||
@@ -1156,4 +1156,90 @@ public class DomainPricingLogicTest {
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("100.00"), RENEW, true))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainCreatePrice_premium_multiYear_nonpremiumCreateAndRenewal() throws Exception {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("premium.example")
|
||||
.setRegistrationBehavior(AllocationToken.RegistrationBehavior.NONPREMIUM_CREATE)
|
||||
.setRenewalPriceBehavior(NONPREMIUM)
|
||||
.build());
|
||||
// Two-year create should be standard create (13) + renewal (10) because both create and renewal
|
||||
// are standard
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("23.00"), CREATE, false))
|
||||
.build());
|
||||
// Similarly, 3 years should be 13 + 10 + 10
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("33.00"), CREATE, false))
|
||||
.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testGetDomainCreatePrice_premium_multiYear_onlyNonpremiumRenewal() throws Exception {
|
||||
AllocationToken allocationToken =
|
||||
persistResource(
|
||||
new AllocationToken.Builder()
|
||||
.setToken("abc123")
|
||||
.setTokenType(SINGLE_USE)
|
||||
.setDomainName("premium.example")
|
||||
.setRenewalPriceBehavior(NONPREMIUM)
|
||||
.build());
|
||||
// Two-year create should be 100 (premium 1st year) plus 10 (nonpremium 2nd year)
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
2,
|
||||
false,
|
||||
false,
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("110.00"), CREATE, true))
|
||||
.build());
|
||||
// Similarly, 3 years should be 100 + 10 + 10
|
||||
assertThat(
|
||||
domainPricingLogic.getCreatePrice(
|
||||
tld,
|
||||
"premium.example",
|
||||
clock.nowUtc(),
|
||||
3,
|
||||
false,
|
||||
false,
|
||||
Optional.of(allocationToken)))
|
||||
.isEqualTo(
|
||||
new FeesAndCredits.Builder()
|
||||
.setCurrency(USD)
|
||||
.addFeeOrCredit(Fee.create(new BigDecimal("120.00"), CREATE, true))
|
||||
.build());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,335 +0,0 @@
|
||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.keyring.api;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import google.registry.util.JdkLoggerConfig;
|
||||
import java.io.IOException;
|
||||
import java.util.logging.Level;
|
||||
import org.bouncycastle.bcpg.BCPGKey;
|
||||
import org.bouncycastle.bcpg.PublicKeyPacket;
|
||||
import org.bouncycastle.openpgp.PGPKeyPair;
|
||||
import org.bouncycastle.openpgp.PGPPrivateKey;
|
||||
import org.bouncycastle.openpgp.PGPPublicKey;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
/** Unit tests for {@link ComparatorKeyring}. */
|
||||
class ComparatorKeyringTest {
|
||||
|
||||
private static final String PUBLIC_KEY_FINGERPRINT = "fingerprint";
|
||||
private static final String PUBLIC_KEY_TO_STRING =
|
||||
"PGPPublicKey{fingerprint=66:69:6e:67:65:72:70:72:69:6e:74:}";
|
||||
private static final String PRIVATE_KEY_TO_STRING =
|
||||
"PGPPrivateKey{keyId=1}";
|
||||
private static final String KEY_PAIR_TO_STRING =
|
||||
String.format("PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, PRIVATE_KEY_TO_STRING);
|
||||
|
||||
private static PGPPublicKey mockPublicKey(
|
||||
boolean altFingerprint,
|
||||
boolean altEncoded) throws IOException {
|
||||
PGPPublicKey publicKey = mock(PGPPublicKey.class);
|
||||
String fingerprint = altFingerprint ? "alternate" : PUBLIC_KEY_FINGERPRINT;
|
||||
String encoded = altEncoded ? "alternate" : "publicKeyEncoded";
|
||||
when(publicKey.getFingerprint()).thenReturn(fingerprint.getBytes(UTF_8));
|
||||
when(publicKey.getEncoded()).thenReturn(encoded.getBytes(UTF_8));
|
||||
return publicKey;
|
||||
}
|
||||
|
||||
private static PGPPrivateKey mockPrivateKey(
|
||||
boolean altId,
|
||||
boolean altBcpgKeyFormat,
|
||||
boolean altBcpgKeyEncoded,
|
||||
boolean altPublicKeyPacketEncoded)
|
||||
throws IOException {
|
||||
String bcpgKeyFormat = altBcpgKeyFormat ? "alternate" : "bcpgFormat";
|
||||
String bcpgKeyEncoded = altBcpgKeyEncoded ? "alternate" : "bcpgEncoded";
|
||||
String publicKeyPacketEncoded = altPublicKeyPacketEncoded ? "alternate" : "packetEncoded";
|
||||
|
||||
BCPGKey bcpgKey = mock(BCPGKey.class);
|
||||
PublicKeyPacket publicKeyPacket = mock(PublicKeyPacket.class);
|
||||
when(bcpgKey.getFormat()).thenReturn(bcpgKeyFormat);
|
||||
when(bcpgKey.getEncoded()).thenReturn(bcpgKeyEncoded.getBytes(UTF_8));
|
||||
when(publicKeyPacket.getEncoded()).thenReturn(publicKeyPacketEncoded.getBytes(UTF_8));
|
||||
return new PGPPrivateKey(altId ? 2 : 1, publicKeyPacket, bcpgKey);
|
||||
}
|
||||
|
||||
private final TestLogHandler testLogHandler = new TestLogHandler();
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
JdkLoggerConfig.getConfig(ComparatorKeyring.class).addHandler(testLogHandler);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void afterEach() {
|
||||
JdkLoggerConfig.getConfig(ComparatorKeyring.class).removeHandler(testLogHandler);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublicKeyToString() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.stringify(
|
||||
mockPublicKey(false, false)))
|
||||
.isEqualTo(PUBLIC_KEY_TO_STRING);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublicKeyEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPublicKey(false, false),
|
||||
mockPublicKey(false, false)))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublicKeyDifferFingerprint_notEqual() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPublicKey(false, false),
|
||||
mockPublicKey(true, false)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPublicKeyDifferEncoded_notEqual() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPublicKey(false, false),
|
||||
mockPublicKey(false, true)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyToString() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.stringify(
|
||||
mockPrivateKey(false, false, false, false)))
|
||||
.isEqualTo(PRIVATE_KEY_TO_STRING);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPrivateKey(false, false, false, false),
|
||||
mockPrivateKey(false, false, false, false)))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyDifferId_notEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPrivateKey(false, false, false, false),
|
||||
mockPrivateKey(true, false, false, false)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyDifferBcpgFormat_notEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPrivateKey(false, false, false, false),
|
||||
mockPrivateKey(false, true, false, false)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyDifferBcpgEncoding_notEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPrivateKey(false, false, false, false),
|
||||
mockPrivateKey(false, false, true, false)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testPrivateKeyDifferPublicKeyEncoding_notEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
mockPrivateKey(false, false, false, false),
|
||||
mockPrivateKey(false, false, false, true)))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testKeyPairToString() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.stringify(
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false))))
|
||||
.isEqualTo(KEY_PAIR_TO_STRING);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testKeyPairEquals() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false)),
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false))))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testKeyPairDifferPublicKey_notEqual() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false)),
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(true, false),
|
||||
mockPrivateKey(false, false, false, false))))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void testKeyPairDifferPrivateKey_notEqual() throws Exception {
|
||||
assertThat(
|
||||
ComparatorKeyring.compare(
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false)),
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(true, false, false, false))))
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
// We don't need to check every single method in the generated instance to see that it behaves
|
||||
// correctly. This should have been tested in ComparatorGenerator.
|
||||
//
|
||||
// We will fully test a single method just to make sure everything is "connected" correctly.
|
||||
|
||||
@Test
|
||||
void testRdeSigningKey_actualThrows() throws Exception {
|
||||
Keyring actualKeyring = mock(Keyring.class);
|
||||
Keyring secondKeyring = mock(Keyring.class);
|
||||
PGPKeyPair keyPair =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false));
|
||||
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
||||
|
||||
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
|
||||
|
||||
assertAboutLogs()
|
||||
.that(testLogHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.SEVERE, ".getRdeSigningKey: Only actual implementation threw exception");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRdeSigningKey_secondThrows() throws Exception {
|
||||
Keyring actualKeyring = mock(Keyring.class);
|
||||
Keyring secondKeyring = mock(Keyring.class);
|
||||
PGPKeyPair keyPair =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false));
|
||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
||||
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
||||
|
||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
||||
|
||||
assertAboutLogs()
|
||||
.that(testLogHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.SEVERE, ".getRdeSigningKey: Only second implementation threw exception");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRdeSigningKey_bothThrow() {
|
||||
Keyring actualKeyring = mock(Keyring.class);
|
||||
Keyring secondKeyring = mock(Keyring.class);
|
||||
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
||||
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
|
||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
||||
|
||||
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
|
||||
|
||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRdeSigningKey_same() throws Exception {
|
||||
Keyring actualKeyring = mock(Keyring.class);
|
||||
Keyring secondKeyring = mock(Keyring.class);
|
||||
PGPKeyPair keyPair =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false));
|
||||
PGPKeyPair keyPairCopy =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false));
|
||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairCopy);
|
||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
||||
|
||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
||||
|
||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testRdeSigningKey_different() throws Exception {
|
||||
Keyring actualKeyring = mock(Keyring.class);
|
||||
Keyring secondKeyring = mock(Keyring.class);
|
||||
PGPKeyPair keyPair =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(false, false, false, false));
|
||||
PGPKeyPair keyPairDifferent =
|
||||
new PGPKeyPair(
|
||||
mockPublicKey(false, false),
|
||||
mockPrivateKey(true, false, false, false));
|
||||
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
|
||||
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairDifferent);
|
||||
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
|
||||
|
||||
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
|
||||
|
||||
String alternateKeyPairString = String.format(
|
||||
"PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, "PGPPrivateKey{keyId=2}");
|
||||
|
||||
assertAboutLogs()
|
||||
.that(testLogHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.SEVERE,
|
||||
String.format(
|
||||
".getRdeSigningKey: Got different results! '%s' vs '%s'",
|
||||
KEY_PAIR_TO_STRING,
|
||||
alternateKeyPairString));
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import dagger.Component;
|
||||
import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
|
||||
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
|
||||
import google.registry.privileges.secretmanager.SecretManagerModule;
|
||||
import google.registry.util.UtilsModule;
|
||||
@@ -84,7 +83,6 @@ class PersistenceModuleTest {
|
||||
ConfigModule.class,
|
||||
CredentialModule.class,
|
||||
PersistenceModule.class,
|
||||
SecretManagerKeyringModule.class,
|
||||
SecretManagerModule.class,
|
||||
UtilsModule.class
|
||||
})
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.console;
|
||||
package google.registry.ui.server.console.domains;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.common.FeatureFlag.FeatureName.MINIMUM_DATASET_CONTACTS_OPTIONAL;
|
||||
@@ -33,7 +33,6 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSortedMap;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import google.registry.flows.DaggerEppTestComponent;
|
||||
import google.registry.flows.EppController;
|
||||
import google.registry.flows.EppTestComponent;
|
||||
@@ -50,7 +49,7 @@ import google.registry.testing.ConsoleApiParamsUtils;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.tools.GsonUtils;
|
||||
import java.util.Map;
|
||||
import google.registry.ui.server.console.ConsoleApiParams;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
@@ -168,13 +167,13 @@ public class ConsoleBulkDomainActionTest {
|
||||
|
||||
@Test
|
||||
void testFailure_badActionString() {
|
||||
ConsoleBulkDomainAction action = createAction("bad", null);
|
||||
ConsoleBulkDomainAction action = createAction("bad", GSON.toJsonTree(ImmutableMap.of()));
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_BAD_REQUEST);
|
||||
assertThat(fakeResponse.getPayload())
|
||||
.isEqualTo(
|
||||
"No enum constant"
|
||||
+ " google.registry.ui.server.console.ConsoleBulkDomainAction.BulkAction.bad");
|
||||
+ " google.registry.ui.server.console.domains.ConsoleDomainActionType.BulkAction.bad");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -188,7 +187,8 @@ public class ConsoleBulkDomainActionTest {
|
||||
@Test
|
||||
void testFailure_noPermission() {
|
||||
JsonElement payload =
|
||||
GSON.toJsonTree(ImmutableMap.of("domainList", ImmutableList.of("domain.tld")));
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of("domainList", ImmutableList.of("domain.tld"), "reason", "reason"));
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"DELETE",
|
||||
@@ -205,29 +205,33 @@ public class ConsoleBulkDomainActionTest {
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testFailure_suspend_nonAdmin() {
|
||||
ConsoleBulkDomainAction action =
|
||||
createAction(
|
||||
"SUSPEND",
|
||||
GSON.toJsonTree(
|
||||
ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason", "test")));
|
||||
action.run();
|
||||
assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
Map<String, ConsoleBulkDomainAction.ConsoleEppOutput> payload =
|
||||
GSON.fromJson(fakeResponse.getPayload(), new TypeToken<>() {});
|
||||
assertThat(payload).containsKey("example.tld");
|
||||
assertThat(payload.get("example.tld").responseCode()).isEqualTo(2004);
|
||||
assertThat(payload.get("example.tld").message()).contains("cannot be set by clients");
|
||||
assertThat(loadByEntity(domain)).isEqualTo(domain);
|
||||
}
|
||||
// @ptkach - reenable with suspend change
|
||||
// @Test
|
||||
// void testFailure_suspend_nonAdmin() {
|
||||
// ConsoleBulkDomainAction action =
|
||||
// createAction(
|
||||
// "SUSPEND",
|
||||
// GSON.toJsonTree(
|
||||
// ImmutableMap.of("domainList", ImmutableList.of("example.tld"), "reason",
|
||||
// "test")),
|
||||
// user);
|
||||
// action.run();
|
||||
// assertThat(fakeResponse.getStatus()).isEqualTo(SC_OK);
|
||||
// Map<String, ConsoleBulkDomainAction.ConsoleEppOutput> payload =
|
||||
// GSON.fromJson(fakeResponse.getPayload(), new TypeToken<>() {});
|
||||
// assertThat(payload).containsKey("example.tld");
|
||||
// assertThat(payload.get("example.tld").responseCode()).isEqualTo(2004);
|
||||
// assertThat(payload.get("example.tld").message()).contains("cannot be set by clients");
|
||||
// assertThat(loadByEntity(domain)).isEqualTo(domain);
|
||||
// }
|
||||
|
||||
private ConsoleBulkDomainAction createAction(String action, JsonElement payload) {
|
||||
User user =
|
||||
persistResource(
|
||||
new User.Builder()
|
||||
.setEmailAddress("email@email.com")
|
||||
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||
.setUserRoles(
|
||||
new UserRoles.Builder().setIsAdmin(true).setGlobalRole(GlobalRole.FTE).build())
|
||||
.build());
|
||||
return createAction(action, payload, user);
|
||||
}
|
||||
@@ -77,8 +77,10 @@ public class ConsoleScreenshotTest extends WebDriverTestCase {
|
||||
assertThat(driver.getCurrentUrl()).endsWith("?registrarId=TheRegistrar");
|
||||
}
|
||||
|
||||
|
||||
@RetryingTest(3)
|
||||
void dums_mainPage() throws Exception {
|
||||
server.setGlobalRole(GlobalRole.FTE);
|
||||
clickSidebarElementByName("Domains");
|
||||
driver.diffPage("noRegistrarSelected");
|
||||
selectRegistrar();
|
||||
@@ -90,20 +92,19 @@ public class ConsoleScreenshotTest extends WebDriverTestCase {
|
||||
driver.diffPage("actionsButtonClicked");
|
||||
}
|
||||
|
||||
// TODO: Reenable failing test after kokoro issue is resolved
|
||||
// @RetryingTest(3)
|
||||
// void settingsPage() throws Exception {
|
||||
// clickSidebarElementByName("Settings");
|
||||
// driver.diffPage("noRegistrarSelected");
|
||||
// selectRegistrar();
|
||||
// driver.diffPage("registrarSelected_contacts");
|
||||
// driver.findElement(By.cssSelector("a[routerLink=\"whois\"]")).click();
|
||||
// Thread.sleep(500);
|
||||
// driver.diffPage("registrarSelected_whois");
|
||||
// driver.findElement(By.cssSelector("a[routerLink=\"security\"]")).click();
|
||||
// Thread.sleep(500);
|
||||
// driver.diffPage("registrarSelected_security");
|
||||
// }
|
||||
@RetryingTest(3)
|
||||
void settingsPage() throws Exception {
|
||||
clickSidebarElementByName("Settings");
|
||||
driver.diffPage("noRegistrarSelected");
|
||||
selectRegistrar();
|
||||
driver.diffPage("registrarSelected_contacts");
|
||||
driver.findElement(By.cssSelector("a[routerLink=\"whois\"]")).click();
|
||||
Thread.sleep(500);
|
||||
driver.diffPage("registrarSelected_whois");
|
||||
driver.findElement(By.cssSelector("a[routerLink=\"security\"]")).click();
|
||||
Thread.sleep(500);
|
||||
driver.diffPage("registrarSelected_security");
|
||||
}
|
||||
|
||||
@RetryingTest(3)
|
||||
void billingInfo() throws Exception {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
SERVICE PATH CLASS METHODS OK MIN USER_POLICY
|
||||
FRONTEND /_dr/epp EppTlsAction POST n APP ADMIN
|
||||
CONSOLE /console-api/bulk-domain ConsoleBulkDomainAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
@@ -13,4 +14,4 @@ CONSOLE /console-api/settings/contacts ContactAction GET,
|
||||
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
|
||||
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
|
||||
|
||||
@@ -66,6 +66,7 @@ PUBAPI /rdap/ip/(*) RdapIpAction
|
||||
PUBAPI /rdap/nameserver/(*) RdapNameserverAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /rdap/nameservers RdapNameserverSearchAction GET,HEAD n NONE PUBLIC
|
||||
PUBAPI /whois/(*) WhoisHttpAction GET n NONE PUBLIC
|
||||
CONSOLE /console-api/bulk-domain ConsoleBulkDomainAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/domain ConsoleDomainGetAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/domain-list ConsoleDomainListAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/dum-download ConsoleDumDownloadAction GET n USER PUBLIC
|
||||
@@ -79,4 +80,4 @@ CONSOLE /console-api/settings/contacts ContactAction
|
||||
CONSOLE /console-api/settings/security SecurityAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/settings/whois-fields WhoisRegistrarFieldsAction POST n USER PUBLIC
|
||||
CONSOLE /console-api/userdata ConsoleUserDataAction GET n USER PUBLIC
|
||||
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
|
||||
CONSOLE /console-api/users ConsoleUsersAction GET,POST,DELETE,PUT n USER PUBLIC
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 132 KiB After Width: | Height: | Size: 127 KiB |
|
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 129 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 39 KiB After Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 42 KiB After Width: | Height: | Size: 42 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 70 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 72 KiB |
@@ -9,6 +9,6 @@ com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.15.2=classpath
|
||||
com.fasterxml.jackson:jackson-bom:2.15.2=classpath
|
||||
gradle.plugin.org.flywaydb:gradle-plugin-publishing:11.0.1=classpath
|
||||
org.flywaydb.flyway:org.flywaydb.flyway.gradle.plugin:11.0.1=classpath
|
||||
org.flywaydb:flyway-core:11.1.0=classpath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.0=classpath
|
||||
org.flywaydb:flyway-core:11.1.1=classpath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.1=classpath
|
||||
empty=
|
||||
|
||||
@@ -16,29 +16,29 @@ com.github.docker-java:docker-java-transport:3.4.0=testCompileClasspath,testRunt
|
||||
com.github.jnr:jffi:1.3.13=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-a64asm:1.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-constants:0.10.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.17=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.16=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.19=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.22=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.18=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.17=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.20=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.23=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-x86asm:1.0.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.api-client:google-api-client:2.7.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.54.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20240925-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.27.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.27.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.58.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20241108-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.30.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.auto.value:auto-value-annotations:1.11.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auto.value:auto-value-annotations:1.9=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.auto:auto-common:1.2.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,checkstyle,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.code.gson:gson:2.11.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_annotation:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_annotations:2.28.0=testCompileClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.32.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.36.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.errorprone:error_prone_annotations:2.7.1=checkstyle
|
||||
com.google.errorprone:error_prone_check_api:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.errorprone:error_prone_core:2.23.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
@@ -55,8 +55,8 @@ com.google.guava:guava:33.2.1-android=testCompileClasspath
|
||||
com.google.guava:guava:33.3.1-android=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=checkstyle,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-apache-v2:1.45.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-gson:1.45.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:1.45.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client-gson:1.45.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.http-client:google-http-client:1.45.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.inject:guice:5.1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.j2objc:j2objc-annotations:1.3=checkstyle
|
||||
com.google.j2objc:j2objc-annotations:3.0.0=deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -72,8 +72,8 @@ info.picocli:picocli:4.6.2=checkstyle
|
||||
io.github.eisop:dataflow-errorprone:3.34.0-eisop1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.12=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
io.github.java-diff-utils:java-diff-utils:4.15=testCompileClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.66.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.66.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-api:1.68.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
io.grpc:grpc-context:1.68.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-api:0.31.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
io.opencensus:opencensus-contrib-http-util:0.31.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
jakarta.inject:jakarta.inject-api:1.0.5=testCompileClasspath,testRuntimeClasspath
|
||||
@@ -92,8 +92,8 @@ org.checkerframework:checker-qual:3.12.0=checkstyle
|
||||
org.checkerframework:checker-qual:3.33.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.checkerframework:checker-qual:3.42.0=testCompileClasspath
|
||||
org.checkerframework:checker-qual:3.43.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.1=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath
|
||||
org.jacoco:org.jacoco.agent:0.8.12=jacocoAgent,jacocoAnt
|
||||
org.jacoco:org.jacoco.ant:0.8.12=jacocoAnt
|
||||
@@ -108,14 +108,14 @@ org.junit.platform:junit-platform-commons:1.11.4=testCompileClasspath,testRuntim
|
||||
org.junit.platform:junit-platform-engine:1.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit:junit-bom:5.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-util:9.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.2=deploy_jar,runtimeClasspath
|
||||
org.ow2.asm:asm:9.7=jacocoAnt,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-util:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.7=jacocoAnt,testCompileClasspath
|
||||
org.ow2.asm:asm:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.postgresql:postgresql:42.7.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
|
||||
@@ -12,8 +12,8 @@ updated by running `nomulus` commands without having to deploy a new version.
|
||||
Here's a checklist of things that need to be configured upon initial
|
||||
installation of the project:
|
||||
|
||||
* Create Google Cloud Storage buckets (see the [Architecture
|
||||
documentation](./architecture.md) for more information).
|
||||
* Create Google Cloud Storage buckets (see the
|
||||
[Architecture documentation](./architecture.md) for more information).
|
||||
* Modify configuration files ("nomulus-config-*.yaml") for all environments
|
||||
you wish to deploy.
|
||||
|
||||
@@ -35,13 +35,13 @@ App Engine configuration isn't covered in depth in this document as it is
|
||||
thoroughly documented in the [App Engine configuration docs][app-engine-config].
|
||||
The main files of note that come pre-configured in Nomulus are:
|
||||
|
||||
* `cron.xml` -- Configuration of cronjobs
|
||||
* `web.xml` -- Configuration of URL paths on the webserver
|
||||
* `appengine-web.xml` -- Overall App Engine settings including number and type
|
||||
* `cron.xml` -- Configuration of cronjobs
|
||||
* `web.xml` -- Configuration of URL paths on the webserver
|
||||
* `appengine-web.xml` -- Overall App Engine settings including number and type
|
||||
of instances
|
||||
* `cloud-scheduler-tasks.xml` -- Configuration of Cloud Scheduler Tasks
|
||||
* * `cloud-tasks-queue.xml` -- Configuration of Cloud Tasks Queue
|
||||
* `application.xml` -- Configuration of the application name and its services
|
||||
* `cloud-scheduler-tasks.xml` -- Configuration of Cloud Scheduler Tasks
|
||||
* * `cloud-tasks-queue.xml` -- Configuration of Cloud Tasks Queue
|
||||
* `application.xml` -- Configuration of the application name and its services
|
||||
|
||||
Cron, web, and queue are covered in more detail in the "App Engine architecture"
|
||||
doc, and the rest are covered in the general App Engine documentation.
|
||||
@@ -53,10 +53,9 @@ likely you'll need to add cronjobs, URL paths, and task queues, and thus edit
|
||||
those associated XML files.
|
||||
|
||||
The existing codebase is configured for running a full-scale registry with
|
||||
multiple TLDs. In order to deploy to App Engine, you will either need to
|
||||
[increase your
|
||||
quota](https://cloud.google.com/compute/quotas#requesting_additional_quota) to
|
||||
allow for at least 100 running instances or reduce `max-instances` in the
|
||||
multiple TLDs. In order to deploy to App Engine, you will either need to
|
||||
[increase your quota](https://cloud.google.com/compute/quotas#requesting_additional_quota)
|
||||
to allow for at least 100 running instances or reduce `max-instances` in the
|
||||
backend `appengine-web.xml` files to 25 or less.
|
||||
|
||||
## Global configuration
|
||||
@@ -93,9 +92,9 @@ need to specify more settings.
|
||||
From a code perspective, all configuration settings ultimately come through the
|
||||
[`RegistryConfig`][registry-config] class. This includes a Dagger module called
|
||||
`ConfigModule` that provides injectable configuration options. While most
|
||||
configuration options can be changed from within the yaml config file,
|
||||
certain derived options may still need to be overriden by changing the code in
|
||||
this module.
|
||||
configuration options can be changed from within the yaml config file, certain
|
||||
derived options may still need to be overriden by changing the code in this
|
||||
module.
|
||||
|
||||
## OAuth 2 client id configuration
|
||||
|
||||
@@ -119,10 +118,9 @@ There are three steps to configuration.
|
||||
["Credentials" page](https://console.developers.google.com/apis/credentials)
|
||||
in the Developer's Console. Click "Create credentials" and select "OAuth
|
||||
client ID" from the dropdown. In the create credentials window, select an
|
||||
application type of "Desktop app". After creating the client id,
|
||||
copy the client id and client secret which are displayed in the popup
|
||||
window. You may also obtain this information by downloading the json file
|
||||
for the client id.
|
||||
application type of "Desktop app". After creating the client id, copy the
|
||||
client id and client secret which are displayed in the popup window. You may
|
||||
also obtain this information by downloading the json file for the client id.
|
||||
|
||||
* **Copy the client secret information to the config file:** The *client
|
||||
secret file* contains both the client ID and the client secret. Copy the
|
||||
@@ -150,29 +148,24 @@ Some configuration values, such as PGP private keys, are so sensitive that they
|
||||
should not be written in code as per the configuration methods above, as that
|
||||
would pose too high a risk of them accidentally being leaked, e.g. in a source
|
||||
control mishap. We use a secret store to persist these values in a secure
|
||||
manner, and abstract access to them using the `Keyring` interface.
|
||||
manner, which is backed by the GCP Secret Manager.
|
||||
|
||||
The `Keyring` interface contains methods for all sensitive configuration values,
|
||||
which are primarily credentials used to access various ICANN and ICANN-
|
||||
affiliated services (such as RDE). These values are only needed for real
|
||||
production registries and PDT environments. If you are just playing around with
|
||||
the platform at first, it is OK to put off defining these values until
|
||||
necessary. To that end, a `DummyKeyringModule` is included that simply provides
|
||||
an `InMemoryKeyring` populated with dummy values for all secret keys. This
|
||||
allows the codebase to compile and run, but of course any actions that attempt
|
||||
to connect to external services will fail because none of the keys are real.
|
||||
necessary. This allows the codebase to start and run, but of course any actions
|
||||
that attempt to connect to external services will fail because if the relevant
|
||||
key is not found in the Secret Manager.
|
||||
|
||||
To configure a production registry system, you will need to either use the
|
||||
SecretManagerKeyring or write your own replacement module using
|
||||
`DummyKeyringModule` for guidance. Such a module should provide either an
|
||||
instance of `InMemoryKeyring` or your own custom implementation of `Keyring`.
|
||||
|
||||
In either case, configure the `keyring` section of the config file with the
|
||||
appropriate parameters. Use an `activeKeyring` of "CSM" with a project id for
|
||||
SecretManager to configure accordingly, for example:
|
||||
|
||||
keyring:
|
||||
activeKeyring: CSM
|
||||
To configure a production registry system, you will need to add the required
|
||||
keys to the Secret Manager. To do so, you can use the Nomulus tool's
|
||||
`update_keyring_secret` command. First, run `nomulus -e ${ENV}
|
||||
update_keyring_secret` to get the list of all key names (whose meanings should
|
||||
be obvious); then, for each key to be added or updated, put the data in a file
|
||||
and run `nomulus -e ${ENV} update_keyring_secret --input ${FILE} --keyname
|
||||
${KEY_NAME}`.
|
||||
|
||||
## Per-TLD configuration
|
||||
|
||||
@@ -181,8 +174,8 @@ configuration. They contain any kind of configuration that is specific to a TLD,
|
||||
such as the create/renew price of a domain name, the pricing engine
|
||||
implementation, the DNS writer implementation, whether escrow exports are
|
||||
enabled, the default currency, the reserved label lists, and more. The `nomulus
|
||||
update_tld` command is used to set all of these options. See the [admin tool
|
||||
documentation](./admin-tool.md) for more information, as well as the
|
||||
update_tld` command is used to set all of these options. See the
|
||||
[admin tool documentation](./admin-tool.md) for more information, as well as the
|
||||
command-line help for the `update_tld` command. Unlike global configuration
|
||||
above, per-TLD configuration options are stored as data in the running system,
|
||||
and thus do not require code pushes to update.
|
||||
@@ -193,121 +186,150 @@ and thus do not require code pushes to update.
|
||||
|
||||
## Cloud SQL Configuration
|
||||
|
||||
Nomulus requires access to Cloud SQL and thus the necessary configuration
|
||||
must be applied.
|
||||
Nomulus requires access to Cloud SQL and thus the necessary configuration must
|
||||
be applied.
|
||||
|
||||
### Create Postgres Cloud SQL Instance
|
||||
|
||||
You can create a cloud SQL instance using the gcloud command:
|
||||
|
||||
$ gcloud sql instances create nomulus --database-version=POSTGRES_11 \
|
||||
--cpu=1 --memory=4G
|
||||
```
|
||||
$ gcloud sql instances create nomulus --database-version=POSTGRES_17 \
|
||||
--cpu=1 --memory=4G
|
||||
```
|
||||
|
||||
Note that for a production instance, you will likely want to be far more
|
||||
generous with both CPU and memory resources.
|
||||
|
||||
Now get the connection name for the new database:
|
||||
|
||||
$ gcloud sql instances describe nomulus | grep connectionName
|
||||
connectionName: your-project:us-central1:nomulus
|
||||
|
||||
Copy the connection name into your configuration (see below).
|
||||
|
||||
Now set the password for the default user:
|
||||
|
||||
$ gcloud sql users set-password postgres \
|
||||
--instance=nomulus --project=$PROJECT_ID \
|
||||
--prompt-for-password
|
||||
```
|
||||
$ gcloud sql users set-password postgres \
|
||||
--instance=nomulus --project=$PROJECT_ID \
|
||||
--prompt-for-password
|
||||
```
|
||||
|
||||
Store this password somewhere secure.
|
||||
|
||||
Now create database users for the tool and for the backend. First, you'll
|
||||
need to create a password. This can simply be a sequence of random
|
||||
characters. Write it to the file `/tmp/server.pass` (we'll use a single
|
||||
password for the two user accounts here, you are encouraged to use different
|
||||
passwords for your production systems). Make sure that this file does not
|
||||
contain a newline after the password. Now create the two user accounts:
|
||||
Now create database users for the tool and for the backend. First, you'll need
|
||||
to create a password. This can simply be a sequence of random characters. Write
|
||||
it to the file `/tmp/server.pass` (we'll use a single password for the two user
|
||||
accounts here, you are encouraged to use different passwords for your production
|
||||
systems). Make sure that this file does not contain a newline after the
|
||||
password. Now create the two user accounts:
|
||||
|
||||
$ gcloud sql users create nomulus --instance=nomulus \
|
||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||
$ gcloud sql users create tool --instance=nomulus \
|
||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||
```
|
||||
$ gcloud sql users create nomulus --instance=nomulus \
|
||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||
$ gcloud sql users create tool --instance=nomulus \
|
||||
--project=$PROJECT_ID "--password=`cat /tmp/server.pass`"
|
||||
```
|
||||
|
||||
Now enable access to the Cloud SQL admin APIs:
|
||||
|
||||
$ gcloud services enable sqladmin.googleapis.com \
|
||||
--project=$PROJECT_ID
|
||||
```
|
||||
$ gcloud services enable sqladmin.googleapis.com \
|
||||
--project=$PROJECT_ID
|
||||
```
|
||||
|
||||
Finally, add the database instance names to the keyring. First, get the
|
||||
connection name for the new database:
|
||||
|
||||
```
|
||||
$ gcloud sql instances describe nomulus | grep connectionName
|
||||
connectionName: your-project:us-central1:nomulus
|
||||
```
|
||||
|
||||
Use the `update_keyring_secret` command to update the `SQL_PRIMARY_CONN_NAME`
|
||||
key with the connection name. If you have created a read-replica, update the
|
||||
`SQL_REPLICA_CONN_NAME` key with the replica's connection time.
|
||||
|
||||
### Installing the Schema
|
||||
|
||||
Google's Nomulus team makes use of Spinnaker-based continuous integration to
|
||||
perform weekly pushes of both the Nomulus software and the SQL database
|
||||
schema. Organizations wishing to use the Nomulus software will likely want to
|
||||
do something similar. However, for purposes of this exercise we will push the
|
||||
perform weekly pushes of both the Nomulus software and the SQL database schema.
|
||||
Organizations wishing to use the Nomulus software will likely want to do
|
||||
something similar. However, for purposes of this exercise we will push the
|
||||
schema from the build system.
|
||||
|
||||
First, download the [Cloud SQL
|
||||
Proxy](https://cloud.google.com/sql/docs/mysql/sql-proxy). This will allow
|
||||
you to connect to your database from a local workstation without a lot of
|
||||
First, download the
|
||||
[Cloud SQL Proxy](https://cloud.google.com/sql/docs/mysql/sql-proxy). This will
|
||||
allow you to connect to your database from a local workstation without a lot of
|
||||
additional configuration.
|
||||
|
||||
Create a service account for use with the proxy:
|
||||
|
||||
$ gcloud iam service-accounts create sql-proxy \
|
||||
--project=$PROJECT_ID \
|
||||
--description="Service account for use with Cloud SQL Proxy" \
|
||||
--display-name="Cloud SQL Proxy"
|
||||
```
|
||||
$ gcloud iam service-accounts create sql-proxy \
|
||||
--project=$PROJECT_ID \
|
||||
--description="Service account for use with Cloud SQL Proxy" \
|
||||
--display-name="Cloud SQL Proxy"
|
||||
```
|
||||
|
||||
Give the service account admin permissions:
|
||||
|
||||
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
|
||||
--member=serviceAccount:sql-proxy@$PROJECT_ID.iam.gserviceaccount.com \
|
||||
--role=roles/cloudsql.admin
|
||||
```
|
||||
$ gcloud projects add-iam-policy-binding $PROJECT_ID \
|
||||
--member=serviceAccount:sql-proxy@$PROJECT_ID.iam.gserviceaccount.com \
|
||||
--role=roles/cloudsql.admin
|
||||
```
|
||||
|
||||
Create a JSON key for the service account:
|
||||
|
||||
$ gcloud iam service-accounts keys create sql-admin.json \
|
||||
--project=$PROJECT_ID \
|
||||
--iam-account=sql-proxy@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
$ gcloud iam service-accounts keys create sql-admin.json \
|
||||
--project=$PROJECT_ID \
|
||||
--iam-account=sql-proxy@$PROJECT_ID.iam.gserviceaccount.com
|
||||
```
|
||||
|
||||
Now start the proxy:
|
||||
|
||||
$ PORT=3306 # Use a different value for this if you like.
|
||||
$ ./cloud_sql_proxy -credential_file=sql-admin.json \
|
||||
-instances=$PROJECT_ID:nomulus=tcp:$PORT
|
||||
2020/07/01 12:11:20 current FDs rlimit set to 32768, wanted limit is 8500. Nothing to do here.
|
||||
2020/07/01 12:11:20 using credential file for authentication; email=sql-proxy@pproject-id.iam.gserviceaccount.com
|
||||
2020/07/01 12:11:20 Listening on 127.0.0.1:3306 for project-id:nomulus
|
||||
2020/07/01 12:11:20 Ready for new connections
|
||||
```
|
||||
$ PORT=3306 # Use a different value for this if you like.
|
||||
$ ./cloud_sql_proxy -credential_file=sql-admin.json \
|
||||
-instances=$PROJECT_ID:nomulus=tcp:$PORT
|
||||
2020/07/01 12:11:20 current FDs rlimit set to 32768, wanted limit is 8500. Nothing to do here.
|
||||
2020/07/01 12:11:20 using credential file for authentication; email=sql-proxy@pproject-id.iam.gserviceaccount.com
|
||||
2020/07/01 12:11:20 Listening on 127.0.0.1:3306 for project-id:nomulus
|
||||
2020/07/01 12:11:20 Ready for new connections
|
||||
```
|
||||
|
||||
Finally, upload the new database schema:
|
||||
|
||||
$ ./nom_build :db:flywayMigrate --dbServer=localhost:$PORT \
|
||||
--dbName=postgres --dbUser=nomulus --dbPassword=`cat /tmp/server.pass`
|
||||
```
|
||||
$ ./nom_build :db:flywayMigrate --dbServer=localhost:$PORT \
|
||||
--dbName=postgres --dbUser=nomulus --dbPassword=`cat /tmp/server.pass`
|
||||
```
|
||||
|
||||
Now you'll need to give the "tool" user access to all tables. You can do this
|
||||
Now you'll need to give the "tool" user access to all tables. You can do this
|
||||
either with a locally installed version of PostgreSQL or from the Cloud Shell.
|
||||
From local postgres, first, with your proxy is still running, connect using
|
||||
psql.
|
||||
|
||||
$ psql -h localhost -p 3306 postgres nomulus ~/w/nom.admin-docs
|
||||
Password for user nomulus: <enter the password from /tmp/server.pass>
|
||||
psql (12.2 (Debian 12.2-1+build2), server 11.6)
|
||||
Type "help" for help.
|
||||
```
|
||||
$ psql -h localhost -p 3306 postgres nomulus ~/w/nom.admin-docs
|
||||
Password for user nomulus: <enter the password from /tmp/server.pass>
|
||||
psql (12.2 (Debian 12.2-1+build2), server 11.6)
|
||||
Type "help" for help.
|
||||
|
||||
postgres=>
|
||||
postgres=>
|
||||
```
|
||||
|
||||
Enter the following command at the postgres prompt:
|
||||
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE
|
||||
ON ALL TABLES IN SCHEMA public
|
||||
TO tool;
|
||||
```
|
||||
GRANT SELECT, INSERT, UPDATE, DELETE
|
||||
ON ALL TABLES IN SCHEMA public
|
||||
TO tool;
|
||||
```
|
||||
|
||||
From the [Google Cloud Console](https://console.developers.google.com), click
|
||||
the cloud shell icon in the toolbar (the ">_" icon). You should be able to
|
||||
the cloud shell icon in the toolbar (the ">_" icon). You should be able to
|
||||
connect to your database with gcloud:
|
||||
|
||||
$ gcloud sql connect nomulus --user=nomulus
|
||||
```
|
||||
$ gcloud sql connect nomulus --user=nomulus
|
||||
```
|
||||
|
||||
From this, you should have a postgres prompt and be able to enter the "GRANT"
|
||||
command specified above.
|
||||
@@ -319,40 +341,31 @@ You'll need to enable the SecretManager API in your project.
|
||||
#### Install Cloud SQL Passwords in Nomulus Server
|
||||
|
||||
Use the update_keyring_secret command to upload the Cloud SQL passwords to the
|
||||
Nomulus server. We'll use the password same set of passwords we specified
|
||||
above when creating database user accounts. These should currently be stored
|
||||
in `/tmp/server.pass`.
|
||||
Nomulus server. We'll use the password same set of passwords we specified above
|
||||
when creating database user accounts. These should currently be stored in
|
||||
`/tmp/server.pass`.
|
||||
|
||||
Paste the password for the Registry server user to a file, say
|
||||
/tmp/server.pass. Make sure to avoid any trailing '\n' inserted by the editor.
|
||||
Paste the password for the Registry server user to a file, say /tmp/server.pass.
|
||||
Make sure to avoid any trailing '\n' inserted by the editor.
|
||||
|
||||
$ set ENV=alpha
|
||||
$ nomulus -e $ENV update_keyring_secret --keyname CLOUD_SQL_PASSWORD \
|
||||
--input /tmp/server.pass
|
||||
```
|
||||
$ set ENV=alpha
|
||||
$ nomulus -e $ENV update_keyring_secret --keyname CLOUD_SQL_PASSWORD \
|
||||
--input /tmp/server.pass
|
||||
```
|
||||
|
||||
Repeat the steps for the tools sql password:
|
||||
|
||||
$ nomulus -e $ENV update_keyring_secret --keyname TOOLS_CLOUD_SQL_PASSWORD \
|
||||
--input /tmp/tools.pass
|
||||
```
|
||||
$ nomulus -e $ENV update_keyring_secret --keyname TOOLS_CLOUD_SQL_PASSWORD \
|
||||
--input /tmp/tools.pass
|
||||
```
|
||||
|
||||
Use get_keyring_secret command to verify the data you put in:
|
||||
|
||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||
[your password]
|
||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||
[your password]
|
||||
|
||||
#### The Relevant Parts of the Configuration File
|
||||
|
||||
cloudSql:
|
||||
jdbcUrl: jdbc:postgresql://google/postgres
|
||||
username: nomulus
|
||||
instanceConnectionName: THE_NAME_SHOWN_ON_THE_DB_INFO_PAGE
|
||||
|
||||
keyring:
|
||||
activeKeyring: CSM
|
||||
|
||||
registryTool:
|
||||
clientId: TOOLS_OAUTH_CLIENT_ID
|
||||
clientSecret: TOOLS_OAUTH_SECRET
|
||||
username: tool
|
||||
```
|
||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||
[your password]
|
||||
$ nomulus -e alpha -e alpha get_keyring_secret --keyname CLOUD_SQL_PASSWORD
|
||||
[your password]
|
||||
```
|
||||
|
||||
2
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
3
gradlew
vendored
@@ -86,8 +86,7 @@ done
|
||||
# shellcheck disable=SC2034
|
||||
APP_BASE_NAME=${0##*/}
|
||||
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s
|
||||
' "$PWD" ) || exit
|
||||
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
|
||||
|
||||
# Use the maximum available, or set MAX_FD != -1 to use that value.
|
||||
MAX_FD=maximum
|
||||
|
||||
@@ -87,7 +87,7 @@ tasks.register('buildDeployer', Exec) {
|
||||
commandLine 'go', 'build', '-o', "${buildDir}/deployer", 'deployCloudSchedulerAndQueue.go'
|
||||
}
|
||||
|
||||
// Once GKE is the only option, we can use the same task in the root project instaead.
|
||||
// Once GKE is the only option, we can use the same task in the root project instead.
|
||||
tasks.register('deployCloudSchedulerAndQueue') {
|
||||
dependsOn(tasks.named('deployCloudScheduler'), tasks.named('deployQueue'))
|
||||
}
|
||||
@@ -99,6 +99,8 @@ tasks.register('deployCloudScheduler', Exec) {
|
||||
"${rootDir}/core/src/main/java/google/registry/config/files/nomulus-config-${rootProject.environment}.yaml",
|
||||
"${rootDir}/core/src/main/java/google/registry/env/${rootProject.environment}/default/WEB-INF/cloud-scheduler-tasks.xml",
|
||||
rootProject.gcpProject, '--gke'
|
||||
// Only deploy the tasks after Nomulus itself is deployed.
|
||||
mustRunAfter(tasks.named('deployToGke'))
|
||||
}
|
||||
|
||||
tasks.register('deployQueue', Exec) {
|
||||
@@ -108,14 +110,20 @@ tasks.register('deployQueue', Exec) {
|
||||
"${rootDir}/core/src/main/java/google/registry/config/files/nomulus-config-${rootProject.environment}.yaml",
|
||||
"${rootDir}/core/src/main/java/google/registry/env/common/default/WEB-INF/cloud-tasks-queue.xml",
|
||||
rootProject.gcpProject, '--gke'
|
||||
// Only deploy the queues after Nomulus itself is deployed.
|
||||
mustRunAfter(tasks.named('deployToGke'))
|
||||
}
|
||||
|
||||
tasks.register('deployNomulus', Exec) {
|
||||
dependsOn('pushNomulusImage', ':proxy:pushProxyImage', 'deployCloudSchedulerAndQueue')
|
||||
tasks.register('deployToGke', Exec) {
|
||||
dependsOn('pushNomulusImage', ':proxy:pushProxyImage')
|
||||
configure verifyDeploymentConfig
|
||||
commandLine './deploy-nomulus-for-env.sh', "${rootProject.environment}", "${rootProject.baseDomain}"
|
||||
}
|
||||
|
||||
tasks.register('deployNomulus') {
|
||||
dependsOn('deployToGke', 'deployCloudSchedulerAndQueue')
|
||||
}
|
||||
|
||||
tasks.register('getEndpoints', Exec) {
|
||||
configure verifyDeploymentConfig
|
||||
commandLine './get-endpoints.py', "${rootProject.gcpProject}"
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
# kills all running pods to force k8s to create new pods using the just-pushed
|
||||
# manifest.
|
||||
|
||||
# Abort on error.
|
||||
set -e
|
||||
|
||||
if [[ $# -ne 2 ]]; then
|
||||
echo "Usage: $0 alpha|crash|qa [base_domain]}"
|
||||
exit 1
|
||||
@@ -30,8 +33,7 @@ while read line
|
||||
do
|
||||
parts=(${line})
|
||||
echo "Updating cluster ${parts[0]} in location ${parts[1]}..."
|
||||
gcloud container clusters get-credentials "${parts[0]}" \
|
||||
--project "${project}" --location "${parts[1]}"
|
||||
gcloud container fleet memberships get-credentials "${parts[0]}" --project "${project}"
|
||||
for service in frontend backend pubapi console
|
||||
do
|
||||
sed s/GCP_PROJECT/"${project}"/g "./kubernetes/nomulus-${service}.yaml" | \
|
||||
|
||||
@@ -21,10 +21,10 @@ com.github.docker-java:docker-java-transport:3.4.0=deploy_jar,runtimeClasspath,t
|
||||
com.github.jnr:jffi:1.3.13=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-a64asm:1.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-constants:0.10.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.17=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.16=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.19=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.22=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.18=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.17=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.20=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.23=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-x86asm:1.0.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.github.kevinstern:software-and-algorithms:1.0=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
com.google.android:annotations:4.1.1.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -77,16 +77,16 @@ com.google.apis:google-api-services-bigquery:v2-rev20240815-2.0.0=deploy_jar,run
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20240310-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20241209-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20240719-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241027-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241206-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20240520-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20240530-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20241114-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iamcredentials:v1-rev20211203-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241017-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20220904-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sheets:v4-rev20241203-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20240925-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20241108-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20240706-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -101,8 +101,8 @@ com.google.cloud.bigdataoss:util:2.2.16=deploy_jar,runtimeClasspath,testRuntimeC
|
||||
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:2.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:detector-resources-support:0.31.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigtable:2.43.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-compute:1.65.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -196,7 +196,6 @@ com.zaxxer:HikariCP:6.2.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
commons-beanutils:commons-beanutils:1.9.4=checkstyle
|
||||
commons-codec:commons-codec:1.17.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
commons-collections:commons-collections:3.2.2=checkstyle
|
||||
commons-dbutils:commons-dbutils:1.8.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
commons-io:commons-io:2.17.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
commons-logging:commons-logging:1.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
dnsjava:dnsjava:3.6.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -328,8 +327,8 @@ org.eclipse.angus:angus-activation:2.0.2=deploy_jar,runtimeClasspath,testRuntime
|
||||
org.eclipse.angus:jakarta.mail:2.0.3=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections-api:11.1.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections:11.1.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-runtime:4.0.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:txw2:4.0.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -366,13 +365,14 @@ org.json:json:20240303=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.jsoup:jsoup:1.18.3=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:0.3.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ogce:xpp3:1.1.6=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.5=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-tree:9.5=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7=jacocoAnt
|
||||
org.ow2.asm:asm-util:9.5=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.7=deploy_jar,jacocoAnt,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-util:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.7=jacocoAnt
|
||||
org.ow2.asm:asm:9.7.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.pcollections:pcollections:3.1.4=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
org.postgresql:postgresql:42.7.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.reflections:reflections:0.10.2=checkstyle
|
||||
@@ -388,13 +388,13 @@ org.threeten:threetenbp:1.7.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.w3c.css:sac:1.3=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.xerial.snappy:snappy-java:1.1.10.4=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
org.yaml:snakeyaml:2.3=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.24.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.25.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
xerces:xmlParserAPIs:2.6.2=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
empty=compileClasspath,providedCompile,providedRuntime,testCompileClasspath
|
||||
|
||||
@@ -38,6 +38,10 @@ spec:
|
||||
ports:
|
||||
- containerPort: 30001
|
||||
name: whois
|
||||
- containerPort: 30010
|
||||
name: http-whois
|
||||
- containerPort: 30011
|
||||
name: https-whois
|
||||
resources:
|
||||
requests:
|
||||
cpu: "500m"
|
||||
@@ -104,6 +108,12 @@ spec:
|
||||
- port: 43
|
||||
targetPort: whois
|
||||
name: whois
|
||||
- port: 80
|
||||
targetPort: http-whois
|
||||
name: http-whois
|
||||
- port: 443
|
||||
targetPort: https-whois
|
||||
name: https-whois
|
||||
---
|
||||
apiVersion: net.gke.io/v1
|
||||
kind: ServiceExport
|
||||
|
||||
@@ -20,7 +20,7 @@ com.google.api:api-common:2.42.0=deploy_jar,runtimeClasspath,testRuntimeClasspat
|
||||
com.google.api:gax-grpc:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241017-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
|
||||
@@ -20,7 +20,7 @@ com.google.api:api-common:2.42.0=deploy_jar,runtimeClasspath,testRuntimeClasspat
|
||||
com.google.api:gax-grpc:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax-httpjson:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.59.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241017-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.30.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.auto.service:auto-service-annotations:1.0.1=annotationProcessor,errorprone,testAnnotationProcessor
|
||||
@@ -121,8 +121,8 @@ javax.annotation:javax.annotation-api:1.3.2=deploy_jar,runtimeClasspath,testRunt
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
joda-time:joda-time:2.13.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.4=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.4=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.java.dev.jna:jna:5.13.0=testCompileClasspath,testRuntimeClasspath
|
||||
net.ltgt.gradle.incap:incap:0.2=annotationProcessor,testAnnotationProcessor
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
@@ -170,7 +170,7 @@ org.junit.platform:junit-platform-runner:1.11.4=testCompileClasspath,testRuntime
|
||||
org.junit.platform:junit-platform-suite-api:1.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-commons:1.11.4=testRuntimeClasspath
|
||||
org.junit:junit-bom:5.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.14.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.15.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7=jacocoAnt
|
||||
|
||||
@@ -40,7 +40,7 @@ com.google.api:gax-httpjson:2.59.0=compileClasspath,testCompileClasspath
|
||||
com.google.api:gax:2.54.1=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.api:gax:2.59.0=compileClasspath,testCompileClasspath
|
||||
com.google.apis:google-api-services-cloudkms:v1-rev20241111-2.0.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241017-2.0.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-2.0.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20231012-2.0.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20241206-2.0.0=compileClasspath,testCompileClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.27.0=deploy_jar,runtimeClasspath,testRuntimeClasspath
|
||||
@@ -185,8 +185,8 @@ javax.annotation:javax.annotation-api:1.3.2=compileClasspath,deploy_jar,runtimeC
|
||||
javax.inject:javax.inject:1=annotationProcessor,compileClasspath,deploy_jar,errorprone,runtimeClasspath,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath
|
||||
joda-time:joda-time:2.13.0=compileClasspath,deploy_jar,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.4=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.4=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy-agent:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.bytebuddy:byte-buddy:1.15.11=testCompileClasspath,testRuntimeClasspath
|
||||
net.java.dev.jna:jna:5.13.0=testCompileClasspath,testRuntimeClasspath
|
||||
net.ltgt.gradle.incap:incap:0.2=annotationProcessor,testAnnotationProcessor
|
||||
net.sf.saxon:Saxon-HE:10.6=checkstyle
|
||||
@@ -234,7 +234,7 @@ org.junit.platform:junit-platform-runner:1.11.4=testCompileClasspath,testRuntime
|
||||
org.junit.platform:junit-platform-suite-api:1.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.junit.platform:junit-platform-suite-commons:1.11.4=testRuntimeClasspath
|
||||
org.junit:junit-bom:5.11.4=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.14.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.mockito:mockito-core:5.15.2=testCompileClasspath,testRuntimeClasspath
|
||||
org.objenesis:objenesis:3.3=testRuntimeClasspath
|
||||
org.opentest4j:opentest4j:1.3.0=testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7=jacocoAnt
|
||||
|
||||
@@ -20,10 +20,10 @@ com.github.docker-java:docker-java-transport:3.4.0=compileClasspath,runtimeClass
|
||||
com.github.jnr:jffi:1.3.13=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.17=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.19=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.22=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-enxio:0.32.18=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-ffi:2.2.17=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-posix:3.1.20=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.github.jnr:jnr-unixsocket:0.38.23=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-jackson2:2.0.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -75,16 +75,16 @@ com.google.apis:google-api-services-bigquery:v2-rev20240815-2.0.0=compileClasspa
|
||||
com.google.apis:google-api-services-cloudresourcemanager:v1-rev20240310-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dataflow:v1b3-rev20241209-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-dns:v1-rev20240719-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241027-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-drive:v3-rev20241206-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-gmail:v1-rev20240520-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-groupssettings:v1-rev20220614-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-healthcare:v1-rev20240130-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20240530-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-iam:v2-rev20241114-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-rev20241017-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-monitoring:v3-rev20241114-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-rev20241203-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20240925-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev20241108-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.apis:google-api-services-storage:v1-rev20240706-2.0.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-credentials:1.30.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.auth:google-auth-library-oauth2-http:1.30.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -96,8 +96,8 @@ com.google.cloud.bigdataoss:util:2.2.16=compileClasspath,runtimeClasspath,testCo
|
||||
com.google.cloud.bigtable:bigtable-client-core-config:1.28.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:2.21.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.opentelemetry:detector-resources-support:0.31.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.21.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud.sql:postgres-socket-factory:1.21.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigquerystorage:3.9.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-bigtable:2.43.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
com.google.cloud:google-cloud-compute:1.65.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -174,7 +174,6 @@ com.squareup:kotlinpoet:1.15.1=compileClasspath,runtimeClasspath,testCompileClas
|
||||
com.sun.istack:istack-commons-runtime:4.1.1=runtimeClasspath,testRuntimeClasspath
|
||||
com.zaxxer:HikariCP:6.2.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-codec:commons-codec:1.17.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-dbutils:commons-dbutils:1.8.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-io:commons-io:2.17.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
commons-logging:commons-logging:1.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
dnsjava:dnsjava:3.6.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -304,8 +303,8 @@ org.eclipse.angus:angus-activation:2.0.2=runtimeClasspath,testRuntimeClasspath
|
||||
org.eclipse.angus:jakarta.mail:2.0.3=runtimeClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections-api:11.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.eclipse.collections:eclipse-collections:11.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.0=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-core:11.1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.flywaydb:flyway-database-postgresql:11.1.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-core:4.0.2=runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:jaxb-runtime:4.0.2=runtimeClasspath,testRuntimeClasspath
|
||||
org.glassfish.jaxb:txw2:4.0.2=runtimeClasspath,testRuntimeClasspath
|
||||
@@ -336,12 +335,11 @@ org.json:json:20240303=compileClasspath,runtimeClasspath,testCompileClasspath,te
|
||||
org.jsoup:jsoup:1.18.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.jspecify:jspecify:0.3.0=runtimeClasspath,testRuntimeClasspath
|
||||
org.ogce:xpp3:1.1.6=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.5=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.5=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,testCompileClasspath
|
||||
org.ow2.asm:asm:9.7=runtimeClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-analysis:9.7.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-commons:9.7.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-tree:9.7.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm-util:9.7.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.ow2.asm:asm:9.7.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.postgresql:postgresql:42.7.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.slf4j:slf4j-api:2.0.16=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
@@ -355,13 +353,13 @@ org.threeten:threetenbp:1.7.0=compileClasspath,runtimeClasspath,testCompileClass
|
||||
org.w3c.css:sac:1.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.xerial.snappy:snappy-java:1.1.10.4=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
org.yaml:snakeyaml:2.3=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.24.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-api:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-diagram:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-loader:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-postgresql:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-text:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-tools:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler-utility:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
us.fatehi:schemacrawler:16.25.1=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
xerces:xmlParserAPIs:2.6.2=compileClasspath,runtimeClasspath,testCompileClasspath,testRuntimeClasspath
|
||||
empty=annotationProcessor,providedCompile,providedRuntime,testAnnotationProcessor
|
||||
|
||||