Compare commits

..
Author SHA1 Message Date
gbrodmanandGitHub 083a9dc8c9 Remove old console history Java classes (#2726)
1. This doesn't remove the SQL tables yet (this is necessary to pass
   tests and also good practice just in case we need or want to look at
history for a little bit)
2. This also removes the Registrar, RegistrarPoc, and User base classes
   that were only necessary because we were saving copies of those
objects in the old history classes.
2025-04-18 22:05:29 +00:00
gbrodmanandGitHub 0153c6284a Add user objects for local test server (#2744)
Also don't try to do anything related to Google admin directory objects
when running the local test server, for obvious reasons
2025-04-18 15:48:06 +00:00
Pavlo TkachandGitHub ca240adfb6 Add new last_poc_verification_date field to Registrar object (#2746) 2025-04-17 19:41:10 +00:00
Pavlo TkachandGitHub b17125ae9a Disable k8s whois routing (#2740) 2025-04-17 15:20:32 +00:00
Pavlo TkachandGitHub dfef733360 Incerase memory request for pubapi and frontend to 1Gi (#2743) 2025-04-11 16:17:43 +00:00
Pavlo TkachandGitHub 04a0659197 Disable console whois (#2741) 2025-04-11 15:32:34 +00:00
Pavlo TkachandGitHub 70010886b1 Increase hikari maximum pool size to 20 (#2742) 2025-04-10 20:51:51 +00:00
135 changed files with 2229 additions and 3428 deletions
+4 -4
View File
@@ -24,8 +24,8 @@ import { ResourcesComponent } from './resources/resources.component';
import ContactComponent from './settings/contact/contact.component';
import SecurityComponent from './settings/security/security.component';
import { SettingsComponent } from './settings/settings.component';
import WhoisComponent from './settings/whois/whois.component';
import { SupportComponent } from './support/support.component';
import RdapComponent from './settings/rdap/rdap.component';
export interface RouteWithIcon extends Route {
iconName?: string;
@@ -83,9 +83,9 @@ export const routes: RouteWithIcon[] = [
title: 'Contacts',
},
{
path: WhoisComponent.PATH,
component: WhoisComponent,
title: 'WHOIS Info',
path: RdapComponent.PATH,
component: RdapComponent,
title: 'RDAP Info',
},
{
path: SecurityComponent.PATH,
+10 -10
View File
@@ -47,8 +47,6 @@ import EppPasswordEditComponent from './settings/security/eppPasswordEdit.compon
import SecurityComponent from './settings/security/security.component';
import SecurityEditComponent from './settings/security/securityEdit.component';
import { SettingsComponent } from './settings/settings.component';
import WhoisComponent from './settings/whois/whois.component';
import WhoisEditComponent from './settings/whois/whoisEdit.component';
import { NotificationsComponent } from './shared/components/notifications/notifications.component';
import { SelectedRegistrarWrapper } from './shared/components/selectedRegistrarWrapper/selectedRegistrarWrapper.component';
import { LocationBackDirective } from './shared/directives/locationBack.directive';
@@ -60,6 +58,8 @@ import { SnackBarModule } from './snackbar.module';
import { SupportComponent } from './support/support.component';
import { TldsComponent } from './tlds/tlds.component';
import { ForceFocusDirective } from './shared/directives/forceFocus.directive';
import RdapComponent from './settings/rdap/rdap.component';
import RdapEditComponent from './settings/rdap/rdapEdit.component';
@NgModule({
declarations: [SelectedRegistrarWrapper],
@@ -76,30 +76,30 @@ export class SelectedRegistrarModule {}
ContactDetailsComponent,
DomainListComponent,
EppPasswordEditComponent,
ForceFocusDirective,
HeaderComponent,
HomeComponent,
LocationBackDirective,
ForceFocusDirective,
UserLevelVisibility,
NavigationComponent,
NewRegistrarComponent,
NotificationsComponent,
RdapComponent,
RdapEditComponent,
ReasonDialogComponent,
RegistrarComponent,
RegistrarDetailsComponent,
RegistryLockComponent,
RegistrarSelectorComponent,
RegistryLockComponent,
RegistryLockVerifyComponent,
ResourcesComponent,
ResponseDialogComponent,
SecurityComponent,
SecurityEditComponent,
SettingsComponent,
SettingsContactComponent,
SupportComponent,
TldsComponent,
WhoisComponent,
WhoisEditComponent,
ReasonDialogComponent,
ResponseDialogComponent,
UserLevelVisibility,
],
bootstrap: [AppComponent],
imports: [
@@ -108,8 +108,8 @@ export class SelectedRegistrarModule {}
BrowserModule,
FormsModule,
MaterialModule,
SnackBarModule,
SelectedRegistrarModule,
SnackBarModule,
],
providers: [
BackendService,
@@ -48,7 +48,6 @@ export default class NewRegistrarComponent {
this.newRegistrar = {
registrarId: '',
url: '',
whoisServer: '',
registrarName: '',
icannReferralEmail: '',
localizedAddress: {
@@ -50,17 +50,16 @@ export interface SecuritySettings
ipAddressAllowList?: Array<IpAllowListItem>;
}
export interface WhoisRegistrarFields {
export interface RdapRegistrarFields {
ianaIdentifier?: number;
icannReferralEmail: string;
localizedAddress: Address;
registrarId: string;
url: string;
whoisServer: string;
}
export interface Registrar
extends WhoisRegistrarFields,
extends RdapRegistrarFields,
SecuritySettingsBackendModel {
allowedTlds?: string[];
billingAccountMap?: object;
@@ -24,7 +24,7 @@ export type contactType =
| 'LEGAL'
| 'MARKETING'
| 'TECH'
| 'WHOIS';
| 'RDAP';
type contactTypesToUserFriendlyTypes = { [type in contactType]: string };
@@ -35,7 +35,7 @@ export const contactTypeToTextMap: contactTypesToUserFriendlyTypes = {
LEGAL: 'Legal contact',
MARKETING: 'Marketing contact',
TECH: 'Technical contact',
WHOIS: 'WHOIS-Inquiry contact',
RDAP: 'RDAP-Inquiry contact',
};
type UserFriendlyType = (typeof contactTypeToTextMap)[contactType];
@@ -97,12 +97,12 @@
</section>
<section>
<h1>WHOIS Preferences</h1>
<h1>RDAP Preferences</h1>
<div>
<mat-checkbox
[(ngModel)]="contactService.contactInEdit.visibleInWhoisAsAdmin"
[ngModelOptions]="{ standalone: true }"
>Show in Registrar WHOIS record as admin contact</mat-checkbox
>Show in Registrar RDAP record as admin contact</mat-checkbox
>
</div>
@@ -110,7 +110,7 @@
<mat-checkbox
[(ngModel)]="contactService.contactInEdit.visibleInWhoisAsTech"
[ngModelOptions]="{ standalone: true }"
>Show in Registrar WHOIS record as technical contact</mat-checkbox
>Show in Registrar RDAP record as technical contact</mat-checkbox
>
</div>
@@ -118,8 +118,8 @@
<mat-checkbox
[(ngModel)]="contactService.contactInEdit.visibleInDomainWhoisAsAbuse"
[ngModelOptions]="{ standalone: true }"
>Show Phone and Email in Domain WHOIS Record as registrar abuse
contact (per CL&D requirements)</mat-checkbox
>Show Phone and Email in Domain RDAP Record as registrar abuse contact
(per CL&D requirements)</mat-checkbox
>
</div>
</section>
@@ -176,13 +176,13 @@
<mat-card-content>
<mat-list role="list">
<mat-list-item role="listitem">
<h2>WHOIS Preferences</h2>
<h2>RDAP Preferences</h2>
</mat-list-item>
@if(contactService.contactInEdit.visibleInWhoisAsAdmin) {
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<span class="console-app__list-value"
>Show in Registrar WHOIS record as admin contact</span
>Show in Registrar RDAP record as admin contact</span
>
</mat-list-item>
} @if(contactService.contactInEdit.visibleInWhoisAsTech) {
@@ -192,14 +192,14 @@
*ngIf="contactService.contactInEdit.visibleInWhoisAsTech"
>
<span class="console-app__list-value"
>Show in Registrar WHOIS record as technical contact</span
>Show in Registrar RDAP record as technical contact</span
>
</mat-list-item>
} @if(contactService.contactInEdit.visibleInDomainWhoisAsAbuse) {
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<span class="console-app__list-value"
>Show Phone and Email in Domain WHOIS Record as registrar abuse
>Show Phone and Email in Domain RDAP Record as registrar abuse
contact (per CL&D requirements)</span
>
</mat-list-item>
@@ -1,18 +1,18 @@
@if(whoisService.editing) {
<app-whois-edit></app-whois-edit>
@if(rdapService.editing) {
<app-rdap-edit></app-rdap-edit>
} @else {
<div class="console-app__whois">
<div class="console-app__whois-controls">
<div class="console-app__rdap">
<div class="console-app__rdap-controls">
<span>
General registrar information for your WHOIS record. This information is
always visible in WHOIS.
General registrar information for your RDAP record. This information is
always visible in RDAP.
</span>
<div class="spacer"></div>
<button
mat-flat-button
color="primary"
aria-label="Edit WHOIS record"
(click)="whoisService.editing = true"
aria-label="Edit RDAP record"
(click)="rdapService.editing = true"
>
<mat-icon>edit</mat-icon>
Edit
@@ -61,45 +61,5 @@
</mat-list>
</mat-card-content>
</mat-card>
<mat-card appearance="outlined">
<mat-card-content>
<mat-list role="list">
<mat-list-item role="listitem">
<h2>Technical Info</h2>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<span class="console-app__list-key">IANA Identifier</span>
<span class="console-app__list-value">{{
registrarService.registrar()?.ianaIdentifier
}}</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<div>
<span class="console-app__list-key">ICANN Referral Email</span>
<span class="console-app__list-value">{{
registrarService.registrar()?.icannReferralEmail
}}</span>
</div>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<span class="console-app__list-key">WHOIS server</span>
<span class="console-app__list-value">{{
registrarService.registrar()?.whoisServer
}}</span>
</mat-list-item>
<mat-divider></mat-divider>
<mat-list-item role="listitem">
<span class="console-app__list-key">Referral URL</span>
<span class="console-app__list-value">{{
registrarService.registrar()?.url
}}</span>
</mat-list-item>
</mat-list>
</mat-card-content>
</mat-card>
</div>
}
@@ -1,4 +1,4 @@
.console-app__whois {
.console-app__rdap {
max-width: 616px;
&-controls {
@@ -20,15 +20,15 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MaterialModule } from 'src/app/material.module';
import { RegistrarService } from 'src/app/registrar/registrar.service';
import { BackendService } from 'src/app/shared/services/backend.service';
import WhoisComponent from './whois.component';
import RdapComponent from './rdap.component';
describe('WhoisComponent', () => {
let component: WhoisComponent;
let fixture: ComponentFixture<WhoisComponent>;
describe('RdapComponent', () => {
let component: RdapComponent;
let fixture: ComponentFixture<RdapComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [WhoisComponent],
declarations: [RdapComponent],
imports: [MaterialModule, BrowserAnimationsModule],
providers: [
BackendService,
@@ -45,7 +45,7 @@ describe('WhoisComponent', () => {
],
}).compileComponents();
fixture = TestBed.createComponent(WhoisComponent);
fixture = TestBed.createComponent(RdapComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
@@ -14,17 +14,16 @@
import { Component, computed } from '@angular/core';
import { RegistrarService } from 'src/app/registrar/registrar.service';
import { WhoisService } from './whois.service';
import { RdapService } from './rdap.service';
@Component({
selector: 'app-whois',
templateUrl: './whois.component.html',
styleUrls: ['./whois.component.scss'],
selector: 'app-rdap',
templateUrl: './rdap.component.html',
styleUrls: ['./rdap.component.scss'],
standalone: false,
})
export default class WhoisComponent {
public static PATH = 'whois';
export default class RdapComponent {
public static PATH = 'rdap';
formattedAddress = computed(() => {
let result = '';
const registrar = this.registrarService.registrar();
@@ -47,7 +46,7 @@ export default class WhoisComponent {
});
constructor(
public whoisService: WhoisService,
public rdapService: RdapService,
public registrarService: RegistrarService
) {}
}
@@ -16,14 +16,14 @@ import { Injectable } from '@angular/core';
import { switchMap } from 'rxjs';
import {
RegistrarService,
WhoisRegistrarFields,
RdapRegistrarFields,
} from 'src/app/registrar/registrar.service';
import { BackendService } from 'src/app/shared/services/backend.service';
@Injectable({
providedIn: 'root',
})
export class WhoisService {
export class RdapService {
editing: boolean = false;
constructor(
@@ -31,8 +31,8 @@ export class WhoisService {
private registrarService: RegistrarService
) {}
saveChanges(newWhoisRegistrarFields: WhoisRegistrarFields) {
return this.backend.postWhoisRegistrarFields(newWhoisRegistrarFields).pipe(
saveChanges(newRdapRegistrarFields: RdapRegistrarFields) {
return this.backend.postRdapRegistrarFields(newRdapRegistrarFields).pipe(
switchMap(() => {
return this.registrarService.loadRegistrars();
})
@@ -1,27 +1,27 @@
<div
class="console-app__whois-edit"
class="console-app__rdap-edit"
*ngIf="registrarInEdit"
cdkTrapFocus
[cdkTrapFocusAutoCapture]="true"
>
<button
mat-icon-button
class="console-app__whois-edit-back"
aria-label="Back to whois view"
(click)="whoisService.editing = false"
class="console-app__rdap-edit-back"
aria-label="Back to rdap view"
(click)="rdapService.editing = false"
>
<mat-icon>arrow_back</mat-icon>
</button>
<div class="console-app__whois-edit-controls">
<div class="console-app__rdap-edit-controls">
<span>
General registrar information for your WHOIS record. This information is
always visible in WHOIS.
General registrar information for your RDAP record. This information is
always visible in RDAP.
</span>
<div class="spacer"></div>
</div>
<div class="console-app__whois-edit">
<div class="console-app__rdap-edit">
<h1>Personal info</h1>
<form (ngSubmit)="save($event)">
@@ -115,45 +115,11 @@
/>
</mat-form-field>
<h1>Technical info</h1>
<mat-form-field appearance="outline">
<mat-label>WHOIS server: </mat-label>
<input
matInput
type="text"
[(ngModel)]="registrarInEdit.whoisServer"
[ngModelOptions]="{ standalone: true }"
/>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Referral URL: </mat-label>
<input
matInput
type="text"
[(ngModel)]="registrarInEdit.url"
[ngModelOptions]="{ standalone: true }"
/>
</mat-form-field>
@if((userDataService.userData()?.globalRole || 'NONE') !== "NONE") {
<mat-form-field appearance="outline">
<mat-label>ICANN Referral Email: </mat-label>
<input
matInput
type="text"
[(ngModel)]="registrarInEdit.icannReferralEmail"
[ngModelOptions]="{ standalone: true }"
/>
</mat-form-field>
}
<button
mat-flat-button
color="primary"
type="submit"
aria-label="Save WHOIS settings"
aria-label="Save RDAO settings"
>
Save
</button>
@@ -1,4 +1,4 @@
.console-app__whois-edit {
.console-app__rdap-edit {
max-width: 616px;
&-controls {
@@ -20,20 +20,20 @@ import {
RegistrarService,
} from 'src/app/registrar/registrar.service';
import { UserDataService } from 'src/app/shared/services/userData.service';
import { WhoisService } from './whois.service';
import { RdapService } from './rdap.service';
@Component({
selector: 'app-whois-edit',
templateUrl: './whoisEdit.component.html',
styleUrls: ['./whoisEdit.component.scss'],
selector: 'app-rdap-edit',
templateUrl: './rdapEdit.component.html',
styleUrls: ['./rdapEdit.component.scss'],
standalone: false,
})
export default class WhoisEditComponent {
export default class RdapEditComponent {
registrarInEdit: Registrar | undefined;
constructor(
public userDataService: UserDataService,
public whoisService: WhoisService,
public rdapService: RdapService,
public registrarService: RegistrarService,
private _snackBar: MatSnackBar
) {
@@ -49,9 +49,9 @@ export default class WhoisEditComponent {
e.preventDefault();
if (!this.registrarInEdit) return;
this.whoisService.saveChanges(this.registrarInEdit).subscribe({
this.rdapService.saveChanges(this.registrarInEdit).subscribe({
complete: () => {
this.whoisService.editing = false;
this.rdapService.editing = false;
},
error: (err: HttpErrorResponse) => {
this._snackBar.open(err.error);
@@ -19,13 +19,13 @@
>
<a
mat-tab-link
routerLink="whois"
routerLink="rdap"
routerLinkActive
queryParamsHandling="merge"
#rla2="routerLinkActive"
[active]="rla2.isActive"
aria-label="Access whois settings"
>WHOIS Info</a
aria-label="Access rdap settings"
>RDAP Info</a
>
<a
mat-tab-link
@@ -25,7 +25,7 @@ import { User } from 'src/app/users/users.service';
import {
Registrar,
SecuritySettingsBackendModel,
WhoisRegistrarFields,
RdapRegistrarFields,
} from '../../registrar/registrar.service';
import { Contact } from '../../settings/contact/contact.service';
import { EppPasswordBackendModel } from '../../settings/security/security.service';
@@ -209,12 +209,12 @@ export class BackendService {
.pipe(catchError((err) => this.errorCatcher<UserData>(err)));
}
postWhoisRegistrarFields(
whoisRegistrarFields: WhoisRegistrarFields
): Observable<WhoisRegistrarFields> {
return this.http.post<WhoisRegistrarFields>(
'/console-api/settings/whois-fields',
whoisRegistrarFields
postRdapRegistrarFields(
rdapRegistrarFields: RdapRegistrarFields
): Observable<RdapRegistrarFields> {
return this.http.post<RdapRegistrarFields>(
'/console-api/settings/rdap-fields',
rdapRegistrarFields
);
}
@@ -33,7 +33,7 @@ import google.registry.flows.certs.CertificateChecker;
import google.registry.groups.GmailClient;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase.Type;
import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.Response;
@@ -58,7 +58,7 @@ import google.registry.model.host.Host;
import google.registry.model.host.HostHistory;
import google.registry.model.rde.RdeMode;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.Type;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
@@ -144,7 +144,6 @@ public abstract class CredentialModule {
Duration tokenRefreshDelay,
Clock clock) {
GoogleCredentials signer = credentialsBundle.getGoogleCredentials();
checkArgument(
signer instanceof ServiceAccountSigner,
"Expecting a ServiceAccountSigner, found %s.",
@@ -243,7 +243,7 @@ hibernate:
# that BEAM pipelines are not subject to the maximumPoolSize value defined
# here. See PersistenceModule.java for more information.
hikariMinimumIdle: 1
hikariMaximumPoolSize: 10
hikariMaximumPoolSize: 20
hikariIdleTimeout: 300000
# The batch size is basically the number of insertions / updates in a single
# transaction that will be batched together into one INSERT/UPDATE statement.
@@ -50,7 +50,6 @@ import google.registry.model.domain.Domain;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.model.tld.Tld;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
@@ -296,7 +295,7 @@ public final class PublishDnsUpdatesAction implements Runnable, Callable<Void> {
ImmutableList<InternetAddress> recipients =
registrar.get().getContacts().stream()
.filter(c -> c.getTypes().contains(RegistrarPocBase.Type.ADMIN))
.filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN))
.map(RegistrarPoc::getEmailAddress)
.map(PublishDnsUpdatesAction::emailToInternetAddress)
.collect(toImmutableList());
@@ -33,7 +33,6 @@ import google.registry.groups.GroupsConnection;
import google.registry.groups.GroupsConnection.Role;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.Response;
@@ -101,7 +100,7 @@ public final class SyncGroupMembersAction implements Runnable {
* Returns the Google Groups email address for the given registrar ID and RegistrarContact.Type.
*/
public static String getGroupEmailAddressForContactType(
String registrarId, RegistrarPocBase.Type type, String gSuiteDomainName) {
String registrarId, RegistrarPoc.Type type, String gSuiteDomainName) {
// Take the registrar's ID, make it lowercase, and remove all characters that aren't
// alphanumeric, hyphens, or underscores.
return String.format(
@@ -176,7 +175,7 @@ public final class SyncGroupMembersAction implements Runnable {
Set<RegistrarPoc> registrarPocs = registrar.getContacts();
long totalAdded = 0;
long totalRemoved = 0;
for (final RegistrarPocBase.Type type : RegistrarPocBase.Type.values()) {
for (final RegistrarPoc.Type type : RegistrarPoc.Type.values()) {
groupKey =
getGroupEmailAddressForContactType(registrar.getRegistrarId(), type, gSuiteDomainName);
Set<String> currentMembers = groupsConnection.getMembersOfGroup(groupKey);
@@ -17,13 +17,13 @@ package google.registry.export.sheet;
import static com.google.common.base.MoreObjects.firstNonNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.common.Cursor.CursorType.SYNC_REGISTRAR_SHEET;
import static google.registry.model.registrar.RegistrarPocBase.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPocBase.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPocBase.Type.BILLING;
import static google.registry.model.registrar.RegistrarPocBase.Type.LEGAL;
import static google.registry.model.registrar.RegistrarPocBase.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPocBase.Type.TECH;
import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS;
import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.BILLING;
import static google.registry.model.registrar.RegistrarPoc.Type.LEGAL;
import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DateTimeUtils.START_OF_TIME;
@@ -36,7 +36,6 @@ import google.registry.model.common.Cursor;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.util.Clock;
import google.registry.util.DateTimeUtils;
import jakarta.inject.Inject;
@@ -174,7 +173,7 @@ class SyncRegistrarsSheet {
return result.toString();
}
private static Predicate<RegistrarPoc> byType(final RegistrarPocBase.Type type) {
private static Predicate<RegistrarPoc> byType(final RegistrarPoc.Type type) {
return contact -> contact.getTypes().contains(type);
}
@@ -124,7 +124,7 @@ import google.registry.model.eppoutput.EppResponse.ResponseExtension;
import google.registry.model.host.Host;
import google.registry.model.poll.PollMessage.Autorenew;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
@@ -1,99 +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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
import google.registry.persistence.VKey;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.AttributeOverride;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.Table;
/**
* A persisted history object representing an EPP action via the console.
*
* <p>In addition to the generic history fields (time, URL, etc.) we also persist a reference to the
* history entry so that we can refer to it if necessary.
*/
@Access(AccessType.FIELD)
@Entity
@Table(
indexes = {
@Index(columnList = "historyActingUser"),
@Index(columnList = "repoId"),
@Index(columnList = "revisionId")
})
public class ConsoleEppActionHistory extends ConsoleUpdateHistory {
@AttributeOverride(name = "repoId", column = @Column(nullable = false))
HistoryEntryId historyEntryId;
@Column(nullable = false)
Class<? extends HistoryEntry> historyEntryClass;
public HistoryEntryId getHistoryEntryId() {
return historyEntryId;
}
public Class<? extends HistoryEntry> getHistoryEntryClass() {
return historyEntryClass;
}
/** Creates a {@link VKey} instance for this entity. */
@Override
public VKey<ConsoleEppActionHistory> createVKey() {
return VKey.create(ConsoleEppActionHistory.class, getRevisionId());
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for the immutable UserUpdateHistory. */
public static class Builder
extends ConsoleUpdateHistory.Builder<ConsoleEppActionHistory, Builder> {
public Builder() {}
public Builder(ConsoleEppActionHistory instance) {
super(instance);
}
@Override
public ConsoleEppActionHistory build() {
checkArgumentNotNull(getInstance().historyEntryId, "History entry ID must be specified");
checkArgumentNotNull(
getInstance().historyEntryClass, "History entry class must be specified");
return super.build();
}
public Builder setHistoryEntryId(HistoryEntryId historyEntryId) {
getInstance().historyEntryId = historyEntryId;
return this;
}
public Builder setHistoryEntryClass(Class<? extends HistoryEntry> historyEntryClass) {
getInstance().historyEntryClass = historyEntryClass;
return this;
}
}
}
@@ -1,4 +1,4 @@
// Copyright 2024 The Nomulus Authors. All Rights Reserved.
// 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.
@@ -19,26 +19,87 @@ import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import google.registry.model.annotations.IdAllocation;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import google.registry.persistence.WithVKey;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Table;
import java.util.Optional;
import org.joda.time.DateTime;
/**
* A record of a resource that was updated through the console.
*
* <p>This abstract class has several subclasses that (mostly) include the modified resource itself
* so that the entire object history is persisted to SQL.
*/
@Access(AccessType.FIELD)
@MappedSuperclass
public abstract class ConsoleUpdateHistory extends ImmutableObject implements Buildable {
@Entity
@WithVKey(Long.class)
@Table(
indexes = {
@Index(columnList = "actingUser", name = "idx_console_update_history_acting_user"),
@Index(columnList = "type", name = "idx_console_update_history_type"),
@Index(columnList = "modificationTime", name = "idx_console_update_history_modification_time")
})
public class ConsoleUpdateHistory extends ImmutableObject implements Buildable {
@Id @IdAllocation @Column Long revisionId;
@Column(nullable = false)
DateTime modificationTime;
/** The HTTP method (e.g. POST, PUT) used to make this modification. */
@Column(nullable = false)
String method;
/** The type of modification. */
@Column(nullable = false)
@Enumerated(EnumType.STRING)
Type type;
/** The URL of the action that was used to make the modification. */
@Column(nullable = false)
String url;
/** An optional further description of the action. */
String description;
/** The user that performed the modification. */
@JoinColumn(name = "actingUser", referencedColumnName = "emailAddress", nullable = false)
@ManyToOne
User actingUser;
public Long getRevisionId() {
return revisionId;
}
public DateTime getModificationTime() {
return modificationTime;
}
public Optional<String> getDescription() {
return Optional.ofNullable(description);
}
public String getMethod() {
return method;
}
public Type getType() {
return type;
}
public String getUrl() {
return url;
}
public User getActingUser() {
return actingUser;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
public enum Type {
DOMAIN_DELETE,
@@ -53,118 +114,51 @@ public abstract class ConsoleUpdateHistory extends ImmutableObject implements Bu
USER_UPDATE
}
/** Autogenerated ID of this event. */
@Id
@IdAllocation
@Column(nullable = false, name = "historyRevisionId")
protected Long revisionId;
public static class Builder extends Buildable.Builder<ConsoleUpdateHistory> {
public Builder() {}
/** The user that performed the modification. */
@JoinColumn(name = "historyActingUser", referencedColumnName = "emailAddress", nullable = false)
@ManyToOne
User actingUser;
/** The URL of the action that was used to make the modification. */
@Column(nullable = false, name = "historyUrl")
String url;
/** The HTTP method (e.g. POST, PUT) used to make this modification. */
@Column(nullable = false, name = "historyMethod")
String method;
/** The raw body of the request that was used to make this modification. */
@Column(name = "historyRequestBody")
String requestBody;
/** The time at which the modification was mode. */
@Column(nullable = false, name = "historyModificationTime")
DateTime modificationTime;
/** The type of modification. */
@Column(nullable = false, name = "historyType")
@Enumerated(EnumType.STRING)
Type type;
public long getRevisionId() {
return revisionId;
}
public User getActingUser() {
return actingUser;
}
public String getUrl() {
return url;
}
public String getMethod() {
return method;
}
public String getRequestBody() {
return requestBody;
}
public DateTime getModificationTime() {
return modificationTime;
}
public Type getType() {
return type;
}
@Override
public abstract Builder<? extends ConsoleUpdateHistory, ?> asBuilder();
/** Builder for the immutable ConsoleUpdateHistory. */
public abstract static class Builder<
T extends ConsoleUpdateHistory, B extends ConsoleUpdateHistory.Builder<?, ?>>
extends GenericBuilder<T, B> {
protected Builder() {}
protected Builder(T instance) {
private Builder(ConsoleUpdateHistory instance) {
super(instance);
}
@Override
public T build() {
public ConsoleUpdateHistory build() {
checkArgumentNotNull(getInstance().modificationTime, "Modification time must be specified");
checkArgumentNotNull(getInstance().actingUser, "Acting user must be specified");
checkArgumentNotNull(getInstance().url, "URL must be specified");
checkArgumentNotNull(getInstance().method, "HTTP method must be specified");
checkArgumentNotNull(getInstance().modificationTime, "modificationTime must be specified");
checkArgumentNotNull(getInstance().type, "Console History type must be specified");
checkArgumentNotNull(getInstance().type, "ConsoleUpdateHistory type must be specified");
return super.build();
}
public B setActingUser(User actingUser) {
getInstance().actingUser = actingUser;
return thisCastToDerived();
}
public B setUrl(String url) {
getInstance().url = url;
return thisCastToDerived();
}
public B setMethod(String method) {
getInstance().method = method;
return thisCastToDerived();
}
public B setRequestBody(String requestBody) {
getInstance().requestBody = requestBody;
return thisCastToDerived();
}
public B setModificationTime(DateTime modificationTime) {
public Builder setModificationTime(DateTime modificationTime) {
getInstance().modificationTime = modificationTime;
return thisCastToDerived();
return this;
}
public B setType(Type type) {
public Builder setActingUser(User actingUser) {
getInstance().actingUser = actingUser;
return this;
}
public Builder setUrl(String url) {
getInstance().url = url;
return this;
}
public Builder setMethod(String method) {
getInstance().method = method;
return this;
}
public Builder setDescription(String description) {
getInstance().description = description;
return this;
}
public Builder setType(Type type) {
getInstance().type = type;
return thisCastToDerived();
return this;
}
}
}
@@ -1,99 +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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.persistence.VKey;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.PostLoad;
import jakarta.persistence.Table;
/**
* A persisted history object representing an update to a RegistrarPoc.
*
* <p>In addition to the generic history fields (time, URL, etc.) we also persist a copy of the
* modified RegistrarPoc object at this point in time.
*/
@Access(AccessType.FIELD)
@Entity
@Table(
indexes = {
@Index(columnList = "historyActingUser"),
@Index(columnList = "emailAddress"),
@Index(columnList = "registrarId")
})
public class RegistrarPocUpdateHistory extends ConsoleUpdateHistory {
RegistrarPocBase registrarPoc;
// These fields exist so that they can be populated in the SQL table
@Column(nullable = false)
String emailAddress;
@Column(nullable = false)
String registrarId;
public RegistrarPocBase getRegistrarPoc() {
return registrarPoc;
}
@PostLoad
void postLoad() {
registrarPoc.setEmailAddress(emailAddress);
registrarPoc.setRegistrarId(registrarId);
}
/** Creates a {@link VKey} instance for this entity. */
@Override
public VKey<RegistrarPocUpdateHistory> createVKey() {
return VKey.create(RegistrarPocUpdateHistory.class, getRevisionId());
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for the immutable UserUpdateHistory. */
public static class Builder
extends ConsoleUpdateHistory.Builder<RegistrarPocUpdateHistory, Builder> {
public Builder() {}
public Builder(RegistrarPocUpdateHistory instance) {
super(instance);
}
@Override
public RegistrarPocUpdateHistory build() {
checkArgumentNotNull(getInstance().registrarPoc, "Registrar POC must be specified");
return super.build();
}
public Builder setRegistrarPoc(RegistrarPoc registrarPoc) {
getInstance().registrarPoc = registrarPoc;
getInstance().registrarId = registrarPoc.getRegistrarId();
getInstance().emailAddress = registrarPoc.getEmailAddress();
return this;
}
}
}
@@ -1,89 +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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.registrar.RegistrarBase;
import google.registry.persistence.VKey;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.PostLoad;
import jakarta.persistence.Table;
/**
* A persisted history object representing an update to a Registrar.
*
* <p>In addition to the generic history fields (time, URL, etc.) we also persist a copy of the
* modified Registrar object at this point in time.
*/
@Access(AccessType.FIELD)
@Entity
@Table(indexes = {@Index(columnList = "historyActingUser"), @Index(columnList = "registrarId")})
public class RegistrarUpdateHistory extends ConsoleUpdateHistory {
RegistrarBase registrar;
// This field exists so that it exists in the SQL table
@Column(nullable = false)
@SuppressWarnings("unused")
private String registrarId;
public RegistrarBase getRegistrar() {
return registrar;
}
@PostLoad
void postLoad() {
registrar.setRegistrarId(registrarId);
}
/** Creates a {@link VKey} instance for this entity. */
@Override
public VKey<RegistrarUpdateHistory> createVKey() {
return VKey.create(RegistrarUpdateHistory.class, getRevisionId());
}
@Override
public Builder asBuilder() {
return new RegistrarUpdateHistory.Builder(clone(this));
}
/** Builder for the immutable UserUpdateHistory. */
public static class Builder
extends ConsoleUpdateHistory.Builder<RegistrarUpdateHistory, Builder> {
public Builder() {}
public Builder(RegistrarUpdateHistory instance) {
super(instance);
}
@Override
public RegistrarUpdateHistory build() {
checkArgumentNotNull(getInstance().registrar, "Registrar must be specified");
return super.build();
}
public Builder setRegistrar(RegistrarBase registrar) {
getInstance().registrar = registrar;
getInstance().registrarId = registrar.getRegistrarId();
return this;
}
}
}
@@ -1,153 +0,0 @@
// 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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import google.registry.model.annotations.IdAllocation;
import google.registry.persistence.WithVKey;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.Index;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;
import java.util.Optional;
import org.joda.time.DateTime;
@Entity
@WithVKey(Long.class)
@Table(
name = "ConsoleUpdateHistory",
indexes = {
@Index(columnList = "actingUser", name = "idx_console_update_history_acting_user"),
@Index(columnList = "type", name = "idx_console_update_history_type"),
@Index(columnList = "modificationTime", name = "idx_console_update_history_modification_time")
})
// TODO: rename this to ConsoleUpdateHistory when that class is removed
public class SimpleConsoleUpdateHistory extends ImmutableObject implements Buildable {
@Id @IdAllocation @Column Long revisionId;
@Column(nullable = false)
DateTime modificationTime;
/** The HTTP method (e.g. POST, PUT) used to make this modification. */
@Column(nullable = false)
String method;
/** The type of modification. */
@Column(nullable = false)
@Enumerated(EnumType.STRING)
ConsoleUpdateHistory.Type type;
/** The URL of the action that was used to make the modification. */
@Column(nullable = false)
String url;
/** An optional further description of the action. */
String description;
/** The user that performed the modification. */
@JoinColumn(name = "actingUser", referencedColumnName = "emailAddress", nullable = false)
@ManyToOne
User actingUser;
public Long getRevisionId() {
return revisionId;
}
public DateTime getModificationTime() {
return modificationTime;
}
public Optional<String> getDescription() {
return Optional.ofNullable(description);
}
public String getMethod() {
return method;
}
public ConsoleUpdateHistory.Type getType() {
return type;
}
public String getUrl() {
return url;
}
public User getActingUser() {
return actingUser;
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
public static class Builder extends Buildable.Builder<SimpleConsoleUpdateHistory> {
public Builder() {}
private Builder(SimpleConsoleUpdateHistory instance) {
super(instance);
}
@Override
public SimpleConsoleUpdateHistory build() {
checkArgumentNotNull(getInstance().modificationTime, "Modification time must be specified");
checkArgumentNotNull(getInstance().actingUser, "Acting user must be specified");
checkArgumentNotNull(getInstance().url, "URL must be specified");
checkArgumentNotNull(getInstance().method, "HTTP method must be specified");
checkArgumentNotNull(getInstance().type, "ConsoleUpdateHistory type must be specified");
return super.build();
}
public Builder setModificationTime(DateTime modificationTime) {
getInstance().modificationTime = modificationTime;
return this;
}
public Builder setActingUser(User actingUser) {
getInstance().actingUser = actingUser;
return this;
}
public Builder setUrl(String url) {
getInstance().url = url;
return this;
}
public Builder setMethod(String method) {
getInstance().method = method;
return this;
}
public Builder setDescription(String description) {
getInstance().description = description;
return this;
}
public Builder setType(ConsoleUpdateHistory.Type type) {
getInstance().type = type;
return this;
}
}
}
@@ -1,4 +1,4 @@
// Copyright 2022 The Nomulus Authors. All Rights Reserved.
// 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.
@@ -15,23 +15,30 @@
package google.registry.model.console;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.model.registrar.Registrar.checkValidEmail;
import static google.registry.tools.server.UpdateUserGroupAction.GROUP_UPDATE_QUEUE;
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
import static google.registry.util.PasswordUtils.hashPassword;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.cloud.tasks.v2.Task;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.flogger.FluentLogger;
import com.google.common.net.MediaType;
import com.google.gson.annotations.Expose;
import google.registry.batch.CloudTasksUtils;
import google.registry.persistence.VKey;
import google.registry.model.Buildable;
import google.registry.model.UpdateAutoTimestampEntity;
import google.registry.request.Action;
import google.registry.tools.IamClient;
import google.registry.tools.ServiceConnection;
import google.registry.tools.server.UpdateUserGroupAction;
import google.registry.tools.server.UpdateUserGroupAction.Mode;
import google.registry.util.PasswordUtils;
import google.registry.util.RegistryEnvironment;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
@@ -44,11 +51,33 @@ import javax.annotation.Nullable;
@Embeddable
@Entity
@Table
public class User extends UserBase {
public class User extends UpdateAutoTimestampEntity implements Buildable {
public static final String IAP_SECURED_WEB_APP_USER_ROLE = "roles/iap.httpsResourceAccessor";
private static final long serialVersionUID = 6936728603828566721L;
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
/** Email address of the user in question. */
@Id @Expose String emailAddress;
/** Optional external email address to use for registry lock confirmation emails. */
@Column String registryLockEmailAddress;
/** Roles (which grant permissions) associated with this user. */
@Expose
@Column(nullable = false)
UserRoles userRoles;
/**
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
* encoded SHA256 string.
*/
String registryLockPasswordHash;
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
/**
* Grants the user permission to pass IAP.
*
@@ -113,9 +142,13 @@ public class User extends UserBase {
logger.atInfo().log("Removing %s from group %s", emailAddress, groupEmailAddress.get());
if (cloudTasksUtils != null) {
modifyGroupMembershipAsync(
emailAddress, groupEmailAddress.get(), cloudTasksUtils, Mode.REMOVE);
emailAddress,
groupEmailAddress.get(),
cloudTasksUtils,
UpdateUserGroupAction.Mode.REMOVE);
} else {
modifyGroupMembershipSync(emailAddress, groupEmailAddress.get(), connection, Mode.REMOVE);
modifyGroupMembershipSync(
emailAddress, groupEmailAddress.get(), connection, UpdateUserGroupAction.Mode.REMOVE);
}
}
}
@@ -124,7 +157,7 @@ public class User extends UserBase {
String userEmailAddress,
String groupEmailAddress,
CloudTasksUtils cloudTasksUtils,
Mode mode) {
UpdateUserGroupAction.Mode mode) {
Task task =
cloudTasksUtils.createTask(
UpdateUserGroupAction.class,
@@ -140,7 +173,10 @@ public class User extends UserBase {
}
private static void modifyGroupMembershipSync(
String userEmailAddress, String groupEmailAddress, ServiceConnection connection, Mode mode) {
String userEmailAddress,
String groupEmailAddress,
ServiceConnection connection,
UpdateUserGroupAction.Mode mode) {
try {
connection.sendPostRequest(
UpdateUserGroupAction.PATH,
@@ -158,30 +194,117 @@ public class User extends UserBase {
}
}
@Id
@Override
@Access(AccessType.PROPERTY)
/**
* Sets the user email address.
*
* <p>This should only be used for restoring an object being loaded in a PostLoad method
* (effectively, when it is still under construction by Hibernate). In all other cases, the object
* should be regarded as immutable and changes should go through a Builder.
*
* <p>In addition to this special case use, this method must exist to satisfy Hibernate.
*/
void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return super.getEmailAddress();
return emailAddress;
}
public Optional<String> getRegistryLockEmailAddress() {
return Optional.ofNullable(registryLockEmailAddress);
}
public UserRoles getUserRoles() {
return userRoles;
}
public boolean hasRegistryLockPassword() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
public boolean verifyRegistryLockPassword(String registryLockPassword) {
if (isNullOrEmpty(registryLockPassword)
|| isNullOrEmpty(registryLockPasswordSalt)
|| isNullOrEmpty(registryLockPasswordHash)) {
return false;
}
return PasswordUtils.verifyPassword(
registryLockPassword, registryLockPasswordHash, registryLockPasswordSalt);
}
/**
* Whether the user has the registry lock permission on any registrar or globally.
*
* <p>If so, they should be allowed to (re)set their registry lock password.
*/
public boolean hasAnyRegistryLockPermission() {
if (userRoles == null) {
return false;
}
if (userRoles.isAdmin() || userRoles.hasGlobalPermission(ConsolePermission.REGISTRY_LOCK)) {
return true;
}
return userRoles.getRegistrarRoles().values().stream()
.anyMatch(role -> role.hasPermission(ConsolePermission.REGISTRY_LOCK));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
@Override
public VKey<User> createVKey() {
return VKey.create(User.class, getEmailAddress());
public Builder<? extends User, ?> asBuilder() {
return new Builder<>(clone(this));
}
/** Builder for constructing immutable {@link User} objects. */
public static class Builder extends UserBase.Builder<User, Builder> {
public static class Builder<T extends User, B extends Builder<T, B>>
extends GenericBuilder<T, B> {
public Builder() {}
public Builder(User user) {
super(user);
public Builder(T abstractUser) {
super(abstractUser);
}
@Override
public T build() {
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
checkArgumentNotNull(getInstance().userRoles, "User roles cannot be null");
return super.build();
}
public B setEmailAddress(String emailAddress) {
getInstance().emailAddress = checkValidEmail(emailAddress);
return thisCastToDerived();
}
public B setRegistryLockEmailAddress(@Nullable String registryLockEmailAddress) {
getInstance().registryLockEmailAddress =
registryLockEmailAddress == null ? null : checkValidEmail(registryLockEmailAddress);
return thisCastToDerived();
}
public B setUserRoles(UserRoles userRoles) {
checkArgumentNotNull(userRoles, "User roles cannot be null");
getInstance().userRoles = userRoles;
return thisCastToDerived();
}
public B removeRegistryLockPassword() {
getInstance().registryLockPasswordHash = null;
getInstance().registryLockPasswordSalt = null;
return thisCastToDerived();
}
public B setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().hasAnyRegistryLockPermission(), "User has no registry lock permission");
checkArgument(
!getInstance().hasRegistryLockPassword(), "User already has a password, remove it first");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
byte[] salt = SALT_SUPPLIER.get();
getInstance().registryLockPasswordSalt = base64().encode(salt);
getInstance().registryLockPasswordHash = hashPassword(registryLockPassword, salt);
return thisCastToDerived();
}
}
}
@@ -1,186 +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.model.console;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.model.registrar.Registrar.checkValidEmail;
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
import static google.registry.util.PasswordUtils.hashPassword;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.gson.annotations.Expose;
import google.registry.model.Buildable;
import google.registry.model.UpdateAutoTimestampEntity;
import google.registry.util.PasswordUtils;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Transient;
import java.util.Optional;
import javax.annotation.Nullable;
/**
* A console user, either a registry employee or a registrar partner.
*
* <p>This class deliberately does not include an {@link Id} so that any foreign-keyed fields can
* refer to the proper parent entity's ID, whether we're storing this in the DB itself or as part of
* another entity.
*/
@Access(AccessType.FIELD)
@Embeddable
@MappedSuperclass
public class UserBase extends UpdateAutoTimestampEntity implements Buildable {
private static final long serialVersionUID = 6936728603828566721L;
/** Email address of the user in question. */
@Transient @Expose String emailAddress;
/** Optional external email address to use for registry lock confirmation emails. */
@Column String registryLockEmailAddress;
/** Roles (which grant permissions) associated with this user. */
@Expose
@Column(nullable = false)
UserRoles userRoles;
/**
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
* encoded SHA256 string.
*/
String registryLockPasswordHash;
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
/**
* Sets the user email address.
*
* <p>This should only be used for restoring an object being loaded in a PostLoad method
* (effectively, when it is still under construction by Hibernate). In all other cases, the object
* should be regarded as immutable and changes should go through a Builder.
*
* <p>In addition to this special case use, this method must exist to satisfy Hibernate.
*/
void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public String getEmailAddress() {
return emailAddress;
}
public Optional<String> getRegistryLockEmailAddress() {
return Optional.ofNullable(registryLockEmailAddress);
}
public UserRoles getUserRoles() {
return userRoles;
}
public boolean hasRegistryLockPassword() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
public boolean verifyRegistryLockPassword(String registryLockPassword) {
if (isNullOrEmpty(registryLockPassword)
|| isNullOrEmpty(registryLockPasswordSalt)
|| isNullOrEmpty(registryLockPasswordHash)) {
return false;
}
return PasswordUtils.verifyPassword(
registryLockPassword, registryLockPasswordHash, registryLockPasswordSalt);
}
/**
* Whether the user has the registry lock permission on any registrar or globally.
*
* <p>If so, they should be allowed to (re)set their registry lock password.
*/
public boolean hasAnyRegistryLockPermission() {
if (userRoles == null) {
return false;
}
if (userRoles.isAdmin() || userRoles.hasGlobalPermission(ConsolePermission.REGISTRY_LOCK)) {
return true;
}
return userRoles.getRegistrarRoles().values().stream()
.anyMatch(role -> role.hasPermission(ConsolePermission.REGISTRY_LOCK));
}
@Override
public Builder<? extends UserBase, ?> asBuilder() {
return new Builder<>(clone(this));
}
/** Builder for constructing immutable {@link UserBase} objects. */
public static class Builder<T extends UserBase, B extends Builder<T, B>>
extends GenericBuilder<T, B> {
public Builder() {}
public Builder(T abstractUser) {
super(abstractUser);
}
@Override
public T build() {
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
checkArgumentNotNull(getInstance().userRoles, "User roles cannot be null");
return super.build();
}
public B setEmailAddress(String emailAddress) {
getInstance().emailAddress = checkValidEmail(emailAddress);
return thisCastToDerived();
}
public B setRegistryLockEmailAddress(@Nullable String registryLockEmailAddress) {
getInstance().registryLockEmailAddress =
registryLockEmailAddress == null ? null : checkValidEmail(registryLockEmailAddress);
return thisCastToDerived();
}
public B setUserRoles(UserRoles userRoles) {
checkArgumentNotNull(userRoles, "User roles cannot be null");
getInstance().userRoles = userRoles;
return thisCastToDerived();
}
public B removeRegistryLockPassword() {
getInstance().registryLockPasswordHash = null;
getInstance().registryLockPasswordSalt = null;
return thisCastToDerived();
}
public B setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().hasAnyRegistryLockPermission(), "User has no registry lock permission");
checkArgument(
!getInstance().hasRegistryLockPassword(), "User already has a password, remove it first");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
byte[] salt = SALT_SUPPLIER.get();
getInstance().registryLockPasswordSalt = base64().encode(salt);
getInstance().registryLockPasswordHash = hashPassword(registryLockPassword, salt);
return thisCastToDerived();
}
}
}
@@ -1,85 +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.model.console;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.persistence.VKey;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Index;
import jakarta.persistence.PostLoad;
import jakarta.persistence.Table;
/**
* A persisted history object representing an update to a User.
*
* <p>In addition to the generic history fields (time, URL, etc.) we also persist a copy of the
* modified User object at this point in time.
*/
@Access(AccessType.FIELD)
@Entity
@Table(indexes = {@Index(columnList = "historyActingUser"), @Index(columnList = "emailAddress")})
public class UserUpdateHistory extends ConsoleUpdateHistory {
UserBase user;
@Column(nullable = false, name = "emailAddress")
String emailAddress;
public UserBase getUser() {
return user;
}
@PostLoad
void postLoad() {
user.setEmailAddress(emailAddress);
}
/** Creates a {@link VKey} instance for this entity. */
@Override
public VKey<UserUpdateHistory> createVKey() {
return VKey.create(UserUpdateHistory.class, getRevisionId());
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for the immutable UserUpdateHistory. */
public static class Builder extends ConsoleUpdateHistory.Builder<UserUpdateHistory, Builder> {
public Builder() {}
public Builder(UserUpdateHistory instance) {
super(instance);
}
@Override
public UserUpdateHistory build() {
checkArgumentNotNull(getInstance().user, "User must be specified");
return super.build();
}
public Builder setUser(User user) {
getInstance().user = user;
getInstance().emailAddress = user.getEmailAddress();
return this;
}
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,4 @@
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
// 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.
@@ -14,17 +14,40 @@
package google.registry.model.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.model.registrar.Registrar.checkValidEmail;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
import static google.registry.util.PasswordUtils.hashPassword;
import static java.util.stream.Collectors.joining;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.annotations.Expose;
import google.registry.model.Buildable.GenericBuilder;
import google.registry.model.ImmutableObject;
import google.registry.model.registrar.RegistrarPoc.RegistrarPocId;
import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import google.registry.model.UnsafeSerializable;
import google.registry.persistence.VKey;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import google.registry.util.PasswordUtils;
import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import java.io.Serializable;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
/**
* A contact for a Registrar. Note, equality, hashCode and comparable have been overridden to only
@@ -35,21 +58,244 @@ import java.io.Serializable;
* set to true.
*/
@Entity
@IdClass(RegistrarPocId.class)
@Access(AccessType.FIELD)
public class RegistrarPoc extends RegistrarPocBase {
@IdClass(RegistrarPoc.RegistrarPocId.class)
public class RegistrarPoc extends ImmutableObject implements Jsonifiable, UnsafeSerializable {
/**
* Registrar contacts types for partner communication tracking.
*
* <p><b>Note:</b> These types only matter to the registry. They are not meant to be used for
* WHOIS or RDAP results.
*/
public enum Type {
ABUSE("abuse", true),
ADMIN("primary", true),
BILLING("billing", true),
LEGAL("legal", true),
MARKETING("marketing", false),
TECH("technical", true),
WHOIS("whois-inquiry", true);
private final String displayName;
private final boolean required;
public String getDisplayName() {
return displayName;
}
public boolean isRequired() {
return required;
}
Type(String display, boolean required) {
displayName = display;
this.required = required;
}
}
/** The name of the contact. */
@Expose String name;
/** The contact email address of the contact. */
@Id @Expose String emailAddress;
@Id @Expose public String registrarId;
/** External email address of this contact used for registry lock confirmations. */
String registryLockEmailAddress;
/** The voice number of the contact. */
@Expose String phoneNumber;
/** The fax number of the contact. */
@Expose String faxNumber;
/**
* Multiple types are used to associate the registrar contact with various mailing groups. This
* data is internal to the registry.
*/
@Enumerated(EnumType.STRING)
@Expose
Set<Type> types;
/**
* Whether this contact is publicly visible in WHOIS registrar query results as an Admin contact.
*/
@Column(nullable = false)
@Expose
boolean visibleInWhoisAsAdmin = false;
/**
* Whether this contact is publicly visible in WHOIS registrar query results as a Technical
* contact.
*/
@Column(nullable = false)
@Expose
boolean visibleInWhoisAsTech = false;
/**
* Whether this contact's phone number and email address is publicly visible in WHOIS domain query
* results as registrar abuse contact info.
*/
@Column(nullable = false)
@Expose
boolean visibleInDomainWhoisAsAbuse = false;
/**
* Whether the contact is allowed to set their registry lock password through the registrar
* console. This will be set to false on contact creation and when the user sets a password.
*/
@Column(nullable = false)
boolean allowedToSetRegistryLockPassword = false;
/**
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
* encoded SHA256 string.
*/
String registryLockPasswordHash;
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
/**
* Helper to update the contacts associated with a Registrar. This requires querying for the
* existing contacts, deleting existing contacts that are not part of the given {@code contacts}
* set, and then saving the given {@code contacts}.
*
* <p>IMPORTANT NOTE: If you call this method then it is your responsibility to also persist the
* relevant Registrar entity with the {@link Registrar#contactsRequireSyncing} field set to true.
*/
public static void updateContacts(
final Registrar registrar, final ImmutableSet<RegistrarPoc> contacts) {
ImmutableSet<String> emailAddressesToKeep =
contacts.stream().map(RegistrarPoc::getEmailAddress).collect(toImmutableSet());
tm().query(
"DELETE FROM RegistrarPoc WHERE registrarId = :registrarId AND "
+ "emailAddress NOT IN :emailAddressesToKeep")
.setParameter("registrarId", registrar.getRegistrarId())
.setParameter("emailAddressesToKeep", emailAddressesToKeep)
.executeUpdate();
tm().putAll(contacts);
}
public String getName() {
return name;
}
@Id
@Access(AccessType.PROPERTY)
@Override
public String getEmailAddress() {
return emailAddress;
}
@Id
@Access(AccessType.PROPERTY)
public String getRegistrarId() {
return registrarId;
public Optional<String> getRegistryLockEmailAddress() {
return Optional.ofNullable(registryLockEmailAddress);
}
public String getPhoneNumber() {
return phoneNumber;
}
public String getFaxNumber() {
return faxNumber;
}
public ImmutableSortedSet<Type> getTypes() {
return nullToEmptyImmutableSortedCopy(types);
}
public boolean getVisibleInWhoisAsAdmin() {
return visibleInWhoisAsAdmin;
}
public boolean getVisibleInWhoisAsTech() {
return visibleInWhoisAsTech;
}
public boolean getVisibleInDomainWhoisAsAbuse() {
return visibleInDomainWhoisAsAbuse;
}
public Builder<? extends RegistrarPoc, ?> asBuilder() {
return new Builder<>(clone(this));
}
public boolean isAllowedToSetRegistryLockPassword() {
return allowedToSetRegistryLockPassword;
}
public boolean isRegistryLockAllowed() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
public boolean verifyRegistryLockPassword(String registryLockPassword) {
if (isNullOrEmpty(registryLockPassword)
|| isNullOrEmpty(registryLockPasswordSalt)
|| isNullOrEmpty(registryLockPasswordHash)) {
return false;
}
return PasswordUtils.verifyPassword(
registryLockPassword, registryLockPasswordHash, registryLockPasswordSalt);
}
/**
* Returns a string representation that's human friendly.
*
* <p>The output will look something like this:
*
* <pre>{@code
* Some Person
* person@example.com
* Tel: +1.2125650666
* Types: [ADMIN, WHOIS]
* Visible in WHOIS as Admin contact: Yes
* Visible in WHOIS as Technical contact: No
* Registrar-Console access: Yes
* Login Email Address: person@registry.example
* }</pre>
*/
public String toStringMultilinePlainText() {
StringBuilder result = new StringBuilder(256);
result.append(getName()).append('\n');
result.append(getEmailAddress()).append('\n');
if (phoneNumber != null) {
result.append("Tel: ").append(getPhoneNumber()).append('\n');
}
if (faxNumber != null) {
result.append("Fax: ").append(getFaxNumber()).append('\n');
}
result.append("Types: ").append(getTypes()).append('\n');
result
.append("Visible in registrar WHOIS query as Admin contact: ")
.append(getVisibleInWhoisAsAdmin() ? "Yes" : "No")
.append('\n');
result
.append("Visible in registrar WHOIS query as Technical contact: ")
.append(getVisibleInWhoisAsTech() ? "Yes" : "No")
.append('\n');
result
.append(
"Phone number and email visible in domain WHOIS query as "
+ "Registrar Abuse contact info: ")
.append(getVisibleInDomainWhoisAsAbuse() ? "Yes" : "No")
.append('\n');
return result.toString();
}
@Override
public Map<String, Object> toJsonMap() {
return new JsonMapBuilder()
.put("name", name)
.put("emailAddress", emailAddress)
.put("registryLockEmailAddress", registryLockEmailAddress)
.put("phoneNumber", phoneNumber)
.put("faxNumber", faxNumber)
.put("types", getTypes().stream().map(Object::toString).collect(joining(",")))
.put("visibleInWhoisAsAdmin", visibleInWhoisAsAdmin)
.put("visibleInWhoisAsTech", visibleInWhoisAsTech)
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
.put("allowedToSetRegistryLockPassword", allowedToSetRegistryLockPassword)
.put("registryLockAllowed", isRegistryLockAllowed())
.build();
}
@Override
@@ -57,9 +303,124 @@ public class RegistrarPoc extends RegistrarPocBase {
return VKey.create(RegistrarPoc.class, new RegistrarPocId(emailAddress, registrarId));
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
/**
* These methods set the email address and registrar ID
*
* <p>This should only be used for restoring the fields of an object being loaded in a PostLoad
* method (effectively, when it is still under construction by Hibernate). In all other cases, the
* object should be regarded as immutable and changes should go through a Builder.
*
* <p>In addition to this special case use, this method must exist to satisfy Hibernate.
*/
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public void setRegistrarId(String registrarId) {
this.registrarId = registrarId;
}
/** A builder for constructing a {@link RegistrarPoc}, since it is immutable. */
public static class Builder<T extends RegistrarPoc, B extends Builder<T, B>>
extends GenericBuilder<T, B> {
public Builder() {}
protected Builder(T instance) {
super(instance);
}
/** Build the registrar, nullifying empty fields. */
@Override
public T build() {
checkNotNull(getInstance().registrarId, "Registrar ID cannot be null");
checkValidEmail(getInstance().emailAddress);
// Check allowedToSetRegistryLockPassword here because if we want to allow the user to set
// a registry lock password, we must also set up the correct registry lock email concurrently
// or beforehand.
if (getInstance().allowedToSetRegistryLockPassword) {
checkArgument(
!isNullOrEmpty(getInstance().registryLockEmailAddress),
"Registry lock email must not be null if allowing registry lock access");
}
return cloneEmptyToNull(super.build());
}
public B setName(String name) {
getInstance().name = name;
return thisCastToDerived();
}
public B setEmailAddress(String emailAddress) {
getInstance().emailAddress = emailAddress;
return thisCastToDerived();
}
public B setRegistryLockEmailAddress(@Nullable String registryLockEmailAddress) {
getInstance().registryLockEmailAddress = registryLockEmailAddress;
return thisCastToDerived();
}
public B setPhoneNumber(String phoneNumber) {
getInstance().phoneNumber = phoneNumber;
return thisCastToDerived();
}
public B setRegistrarId(String registrarId) {
getInstance().registrarId = registrarId;
return thisCastToDerived();
}
public B setRegistrar(Registrar registrar) {
getInstance().registrarId = registrar.getRegistrarId();
return thisCastToDerived();
}
public B setFaxNumber(String faxNumber) {
getInstance().faxNumber = faxNumber;
return thisCastToDerived();
}
public B setTypes(Iterable<Type> types) {
getInstance().types = ImmutableSet.copyOf(types);
return thisCastToDerived();
}
public B setVisibleInWhoisAsAdmin(boolean visible) {
getInstance().visibleInWhoisAsAdmin = visible;
return thisCastToDerived();
}
public B setVisibleInWhoisAsTech(boolean visible) {
getInstance().visibleInWhoisAsTech = visible;
return thisCastToDerived();
}
public B setVisibleInDomainWhoisAsAbuse(boolean visible) {
getInstance().visibleInDomainWhoisAsAbuse = visible;
return thisCastToDerived();
}
public B setAllowedToSetRegistryLockPassword(boolean allowedToSetRegistryLockPassword) {
if (allowedToSetRegistryLockPassword) {
getInstance().registryLockPasswordSalt = null;
getInstance().registryLockPasswordHash = null;
}
getInstance().allowedToSetRegistryLockPassword = allowedToSetRegistryLockPassword;
return thisCastToDerived();
}
public B setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().allowedToSetRegistryLockPassword,
"Not allowed to set registry lock password for this contact");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
byte[] salt = SALT_SUPPLIER.get();
getInstance().registryLockPasswordSalt = base64().encode(salt);
getInstance().registryLockPasswordHash = hashPassword(registryLockPassword, salt);
getInstance().allowedToSetRegistryLockPassword = false;
return thisCastToDerived();
}
}
/** Class to represent the composite primary key for {@link RegistrarPoc} entity. */
@@ -90,13 +451,4 @@ public class RegistrarPoc extends RegistrarPocBase {
return registrarId;
}
}
public static class Builder extends RegistrarPocBase.Builder<RegistrarPoc, Builder> {
public Builder() {}
public Builder(RegistrarPoc registrarPoc) {
super(registrarPoc);
}
}
}
@@ -1,425 +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.model.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.model.registrar.RegistrarBase.checkValidEmail;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableSortedCopy;
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
import static google.registry.util.PasswordUtils.hashPassword;
import static java.util.stream.Collectors.joining;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.ImmutableSortedSet;
import com.google.gson.annotations.Expose;
import google.registry.model.Buildable.GenericBuilder;
import google.registry.model.ImmutableObject;
import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import google.registry.model.UnsafeSerializable;
import google.registry.util.PasswordUtils;
import jakarta.persistence.Access;
import jakarta.persistence.AccessType;
import jakarta.persistence.Column;
import jakarta.persistence.Embeddable;
import jakarta.persistence.EnumType;
import jakarta.persistence.Enumerated;
import jakarta.persistence.Id;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.Transient;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import javax.annotation.Nullable;
/**
* A contact for a Registrar. Note, equality, hashCode and comparable have been overridden to only
* enable key equality.
*
* <p>IMPORTANT NOTE: Any time that you change, update, or delete RegistrarContact entities, you
* *MUST* also modify the persisted Registrar entity with {@link Registrar#contactsRequireSyncing}
* set to true.
*
* <p>This class deliberately does not include an {@link Id} so that any foreign-keyed fields can
* refer to the proper parent entity's ID, whether we're storing this in the DB itself or as part of
* another entity.
*/
@Access(AccessType.FIELD)
@Embeddable
@MappedSuperclass
public class RegistrarPocBase extends ImmutableObject implements Jsonifiable, UnsafeSerializable {
/**
* Registrar contacts types for partner communication tracking.
*
* <p><b>Note:</b> These types only matter to the registry. They are not meant to be used for
* WHOIS or RDAP results.
*/
public enum Type {
ABUSE("abuse", true),
ADMIN("primary", true),
BILLING("billing", true),
LEGAL("legal", true),
MARKETING("marketing", false),
TECH("technical", true),
WHOIS("whois-inquiry", true);
private final String displayName;
private final boolean required;
public String getDisplayName() {
return displayName;
}
public boolean isRequired() {
return required;
}
Type(String display, boolean required) {
displayName = display;
this.required = required;
}
}
/** The name of the contact. */
@Expose String name;
/** The contact email address of the contact. */
@Expose @Transient String emailAddress;
@Expose @Transient public String registrarId;
/** External email address of this contact used for registry lock confirmations. */
String registryLockEmailAddress;
/** The voice number of the contact. */
@Expose String phoneNumber;
/** The fax number of the contact. */
@Expose String faxNumber;
/**
* Multiple types are used to associate the registrar contact with various mailing groups. This
* data is internal to the registry.
*/
@Enumerated(EnumType.STRING)
@Expose
Set<Type> types;
/**
* Whether this contact is publicly visible in WHOIS registrar query results as an Admin contact.
*/
@Column(nullable = false)
@Expose
boolean visibleInWhoisAsAdmin = false;
/**
* Whether this contact is publicly visible in WHOIS registrar query results as a Technical
* contact.
*/
@Column(nullable = false)
@Expose
boolean visibleInWhoisAsTech = false;
/**
* Whether this contact's phone number and email address is publicly visible in WHOIS domain query
* results as registrar abuse contact info.
*/
@Column(nullable = false)
@Expose
boolean visibleInDomainWhoisAsAbuse = false;
/**
* Whether the contact is allowed to set their registry lock password through the registrar
* console. This will be set to false on contact creation and when the user sets a password.
*/
@Column(nullable = false)
boolean allowedToSetRegistryLockPassword = false;
/**
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
* encoded SHA256 string.
*/
String registryLockPasswordHash;
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
/**
* Helper to update the contacts associated with a Registrar. This requires querying for the
* existing contacts, deleting existing contacts that are not part of the given {@code contacts}
* set, and then saving the given {@code contacts}.
*
* <p>IMPORTANT NOTE: If you call this method then it is your responsibility to also persist the
* relevant Registrar entity with the {@link Registrar#contactsRequireSyncing} field set to true.
*/
public static void updateContacts(
final Registrar registrar, final ImmutableSet<RegistrarPoc> contacts) {
ImmutableSet<String> emailAddressesToKeep =
contacts.stream().map(RegistrarPoc::getEmailAddress).collect(toImmutableSet());
tm().query(
"DELETE FROM RegistrarPoc WHERE registrarId = :registrarId AND "
+ "emailAddress NOT IN :emailAddressesToKeep")
.setParameter("registrarId", registrar.getRegistrarId())
.setParameter("emailAddressesToKeep", emailAddressesToKeep)
.executeUpdate();
tm().putAll(contacts);
}
public String getName() {
return name;
}
public String getEmailAddress() {
return emailAddress;
}
public Optional<String> getRegistryLockEmailAddress() {
return Optional.ofNullable(registryLockEmailAddress);
}
public String getPhoneNumber() {
return phoneNumber;
}
public String getFaxNumber() {
return faxNumber;
}
public ImmutableSortedSet<Type> getTypes() {
return nullToEmptyImmutableSortedCopy(types);
}
public boolean getVisibleInWhoisAsAdmin() {
return visibleInWhoisAsAdmin;
}
public boolean getVisibleInWhoisAsTech() {
return visibleInWhoisAsTech;
}
public boolean getVisibleInDomainWhoisAsAbuse() {
return visibleInDomainWhoisAsAbuse;
}
public Builder<? extends RegistrarPocBase, ?> asBuilder() {
return new Builder<>(clone(this));
}
public boolean isAllowedToSetRegistryLockPassword() {
return allowedToSetRegistryLockPassword;
}
public boolean isRegistryLockAllowed() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
public boolean verifyRegistryLockPassword(String registryLockPassword) {
if (isNullOrEmpty(registryLockPassword)
|| isNullOrEmpty(registryLockPasswordSalt)
|| isNullOrEmpty(registryLockPasswordHash)) {
return false;
}
return PasswordUtils.verifyPassword(
registryLockPassword, registryLockPasswordHash, registryLockPasswordSalt);
}
/**
* Returns a string representation that's human friendly.
*
* <p>The output will look something like this:
*
* <pre>{@code
* Some Person
* person@example.com
* Tel: +1.2125650666
* Types: [ADMIN, WHOIS]
* Visible in WHOIS as Admin contact: Yes
* Visible in WHOIS as Technical contact: No
* Registrar-Console access: Yes
* Login Email Address: person@registry.example
* }</pre>
*/
public String toStringMultilinePlainText() {
StringBuilder result = new StringBuilder(256);
result.append(getName()).append('\n');
result.append(getEmailAddress()).append('\n');
if (phoneNumber != null) {
result.append("Tel: ").append(getPhoneNumber()).append('\n');
}
if (faxNumber != null) {
result.append("Fax: ").append(getFaxNumber()).append('\n');
}
result.append("Types: ").append(getTypes()).append('\n');
result
.append("Visible in registrar WHOIS query as Admin contact: ")
.append(getVisibleInWhoisAsAdmin() ? "Yes" : "No")
.append('\n');
result
.append("Visible in registrar WHOIS query as Technical contact: ")
.append(getVisibleInWhoisAsTech() ? "Yes" : "No")
.append('\n');
result
.append(
"Phone number and email visible in domain WHOIS query as "
+ "Registrar Abuse contact info: ")
.append(getVisibleInDomainWhoisAsAbuse() ? "Yes" : "No")
.append('\n');
return result.toString();
}
@Override
public Map<String, Object> toJsonMap() {
return new JsonMapBuilder()
.put("name", name)
.put("emailAddress", emailAddress)
.put("registryLockEmailAddress", registryLockEmailAddress)
.put("phoneNumber", phoneNumber)
.put("faxNumber", faxNumber)
.put("types", getTypes().stream().map(Object::toString).collect(joining(",")))
.put("visibleInWhoisAsAdmin", visibleInWhoisAsAdmin)
.put("visibleInWhoisAsTech", visibleInWhoisAsTech)
.put("visibleInDomainWhoisAsAbuse", visibleInDomainWhoisAsAbuse)
.put("allowedToSetRegistryLockPassword", allowedToSetRegistryLockPassword)
.put("registryLockAllowed", isRegistryLockAllowed())
.build();
}
/**
* These methods set the email address and registrar ID
*
* <p>This should only be used for restoring the fields of an object being loaded in a PostLoad
* method (effectively, when it is still under construction by Hibernate). In all other cases, the
* object should be regarded as immutable and changes should go through a Builder.
*
* <p>In addition to this special case use, this method must exist to satisfy Hibernate.
*/
public void setEmailAddress(String emailAddress) {
this.emailAddress = emailAddress;
}
public void setRegistrarId(String registrarId) {
this.registrarId = registrarId;
}
/** A builder for constructing a {@link RegistrarPoc}, since it is immutable. */
public static class Builder<T extends RegistrarPocBase, B extends Builder<T, B>>
extends GenericBuilder<T, B> {
public Builder() {}
protected Builder(T instance) {
super(instance);
}
/** Build the registrar, nullifying empty fields. */
@Override
public T build() {
checkNotNull(getInstance().registrarId, "Registrar ID cannot be null");
checkValidEmail(getInstance().emailAddress);
// Check allowedToSetRegistryLockPassword here because if we want to allow the user to set
// a registry lock password, we must also set up the correct registry lock email concurrently
// or beforehand.
if (getInstance().allowedToSetRegistryLockPassword) {
checkArgument(
!isNullOrEmpty(getInstance().registryLockEmailAddress),
"Registry lock email must not be null if allowing registry lock access");
}
return cloneEmptyToNull(super.build());
}
public B setName(String name) {
getInstance().name = name;
return thisCastToDerived();
}
public B setEmailAddress(String emailAddress) {
getInstance().emailAddress = emailAddress;
return thisCastToDerived();
}
public B setRegistryLockEmailAddress(@Nullable String registryLockEmailAddress) {
getInstance().registryLockEmailAddress = registryLockEmailAddress;
return thisCastToDerived();
}
public B setPhoneNumber(String phoneNumber) {
getInstance().phoneNumber = phoneNumber;
return thisCastToDerived();
}
public B setRegistrarId(String registrarId) {
getInstance().registrarId = registrarId;
return thisCastToDerived();
}
public B setRegistrar(Registrar registrar) {
getInstance().registrarId = registrar.getRegistrarId();
return thisCastToDerived();
}
public B setFaxNumber(String faxNumber) {
getInstance().faxNumber = faxNumber;
return thisCastToDerived();
}
public B setTypes(Iterable<Type> types) {
getInstance().types = ImmutableSet.copyOf(types);
return thisCastToDerived();
}
public B setVisibleInWhoisAsAdmin(boolean visible) {
getInstance().visibleInWhoisAsAdmin = visible;
return thisCastToDerived();
}
public B setVisibleInWhoisAsTech(boolean visible) {
getInstance().visibleInWhoisAsTech = visible;
return thisCastToDerived();
}
public B setVisibleInDomainWhoisAsAbuse(boolean visible) {
getInstance().visibleInDomainWhoisAsAbuse = visible;
return thisCastToDerived();
}
public B setAllowedToSetRegistryLockPassword(boolean allowedToSetRegistryLockPassword) {
if (allowedToSetRegistryLockPassword) {
getInstance().registryLockPasswordSalt = null;
getInstance().registryLockPasswordHash = null;
}
getInstance().allowedToSetRegistryLockPassword = allowedToSetRegistryLockPassword;
return thisCastToDerived();
}
public B setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().allowedToSetRegistryLockPassword,
"Not allowed to set registry lock password for this contact");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
byte[] salt = SALT_SUPPLIER.get();
getInstance().registryLockPasswordSalt = base64().encode(salt);
getInstance().registryLockPasswordHash = hashPassword(registryLockPassword, salt);
getInstance().allowedToSetRegistryLockPassword = false;
return thisCastToDerived();
}
}
}
@@ -127,8 +127,8 @@ 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.RdapRegistrarFieldsAction;
import google.registry.ui.server.console.settings.SecurityAction;
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
import google.registry.whois.WhoisAction;
import google.registry.whois.WhoisHttpAction;
import google.registry.whois.WhoisModule;
@@ -337,7 +337,7 @@ interface RequestComponent {
WhoisHttpAction whoisHttpAction();
WhoisRegistrarFieldsAction whoisRegistrarFieldsAction();
RdapRegistrarFieldsAction rdapRegistrarFieldsAction();
WipeOutContactHistoryPiiAction wipeOutContactHistoryPiiAction();
@@ -41,8 +41,8 @@ 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.RdapRegistrarFieldsAction;
import google.registry.ui.server.console.settings.SecurityAction;
import google.registry.ui.server.console.settings.WhoisRegistrarFieldsAction;
/** Dagger component with per-request lifetime for "default" App Engine module. */
@RequestScope
@@ -92,7 +92,7 @@ public interface FrontendRequestComponent {
SecurityAction securityAction();
WhoisRegistrarFieldsAction whoisRegistrarFieldsAction();
RdapRegistrarFieldsAction rdapRegistrarFieldsAction();
@Subcomponent.Builder
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
@@ -19,9 +19,8 @@ import static com.google.common.base.Preconditions.checkState;
import com.google.common.collect.ImmutableMap;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.xjc.contact.XjcContactE164Type;
import google.registry.xjc.rderegistrar.XjcRdeRegistrar;
import google.registry.xjc.rderegistrar.XjcRdeRegistrarAddrType;
@@ -41,7 +40,7 @@ final class RegistrarToXjcConverter {
private static final String UNKNOWN_CC = "US";
/** A conversion map between internal Registrar states and external RDE states. */
private static final ImmutableMap<RegistrarBase.State, XjcRdeRegistrarStatusType>
private static final ImmutableMap<Registrar.State, XjcRdeRegistrarStatusType>
REGISTRAR_STATUS_CONVERSIONS =
ImmutableMap.of(
State.ACTIVE, XjcRdeRegistrarStatusType.OK,
@@ -27,7 +27,7 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.groups.GroupsConnection;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import jakarta.inject.Inject;
import java.util.Optional;
import javax.annotation.concurrent.Immutable;
@@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableSet;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase;
import google.registry.tools.params.KeyValueMapParameter.CurrencyUnitToStringMap;
import google.registry.tools.params.OptionalLongParameter;
import google.registry.tools.params.OptionalPhoneNumberParameter;
@@ -61,11 +60,11 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
List<String> mainParameters;
@Parameter(names = "--registrar_type", description = "Type of the registrar")
RegistrarBase.Type registrarType;
Registrar.Type registrarType;
@Nullable
@Parameter(names = "--registrar_state", description = "Initial state of the registrar")
RegistrarBase.State registrarState;
Registrar.State registrarState;
@Parameter(
names = "--allowed_tlds",
@@ -18,7 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.Iterables.getOnlyElement;
import static google.registry.model.registrar.RegistrarBase.State.ACTIVE;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.tools.RegistryToolEnvironment.PRODUCTION;
import static google.registry.tools.RegistryToolEnvironment.SANDBOX;
import static google.registry.tools.RegistryToolEnvironment.UNITTEST;
@@ -29,7 +29,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.tools.params.OptionalPhoneNumberParameter;
import google.registry.tools.params.PathParameter;
import google.registry.tools.params.StringListParameter;
@@ -153,7 +152,7 @@ final class RegistrarPocCommand extends MutatingCommand {
private static final ImmutableSet<Mode> MODES_REQUIRING_CONTACT_SYNC =
ImmutableSet.of(Mode.CREATE, Mode.UPDATE, Mode.DELETE);
@Nullable private ImmutableSet<RegistrarPocBase.Type> contactTypes;
@Nullable private ImmutableSet<RegistrarPoc.Type> contactTypes;
@Override
protected void init() throws Exception {
@@ -169,7 +168,7 @@ final class RegistrarPocCommand extends MutatingCommand {
} else {
contactTypes =
contactTypeNames.stream()
.map(Enums.stringConverter(RegistrarPocBase.Type.class))
.map(Enums.stringConverter(RegistrarPoc.Type.class))
.collect(toImmutableSet());
}
ImmutableSet<RegistrarPoc> contacts = registrar.getContacts();
@@ -24,7 +24,7 @@ import google.registry.config.RegistryConfig.Config;
import google.registry.groups.GroupsConnection;
import google.registry.groups.GroupsConnection.Role;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
import google.registry.request.HttpException.BadRequestException;
@@ -65,7 +65,7 @@ public class CreateGroupsAction implements Runnable {
if (registrar == null) {
return;
}
List<RegistrarPocBase.Type> types = asList(RegistrarPocBase.Type.values());
List<RegistrarPoc.Type> types = asList(RegistrarPoc.Type.values());
// Concurrently create the groups for each RegistrarContact.Type, collecting the results from
// each call (which are either an Exception if it failed, or absent() if it succeeded).
List<Optional<Exception>> results =
@@ -29,7 +29,6 @@ import com.google.re2j.Pattern;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.ui.forms.FormException;
import google.registry.ui.forms.FormField;
import google.registry.ui.forms.FormFieldException;
@@ -201,10 +200,10 @@ public final class RegistrarFormFields {
public static final FormField<String, String> CONTACT_REGISTRY_LOCK_PASSWORD_FIELD =
FormFields.NAME.asBuilderNamed("registryLockPassword").build();
public static final FormField<String, Set<RegistrarPocBase.Type>> CONTACT_TYPES =
public static final FormField<String, Set<RegistrarPoc.Type>> CONTACT_TYPES =
FormField.named("types")
.uppercased()
.asEnum(RegistrarPocBase.Type.class)
.asEnum(RegistrarPoc.Type.class)
.asSet(Splitter.on(',').omitEmptyStrings().trimResults())
.build();
@@ -37,11 +37,10 @@ import google.registry.batch.CloudTasksUtils;
import google.registry.config.RegistryConfig;
import google.registry.export.sheet.SyncRegistrarsSheetAction;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.request.HttpException;
import google.registry.security.XsrfTokenManager;
import google.registry.util.DiffUtils;
@@ -218,7 +217,7 @@ public abstract class ConsoleApiAction implements Runnable {
consoleApiParams.authResult().userIdForLogging(),
DiffUtils.prettyPrintDiffedMap(diffs, null)),
contacts.stream()
.filter(c -> c.getTypes().contains(RegistrarPocBase.Type.ADMIN))
.filter(c -> c.getTypes().contains(RegistrarPoc.Type.ADMIN))
.map(RegistrarPoc::getEmailAddress)
.collect(toImmutableList()));
}
@@ -262,7 +261,7 @@ public abstract class ConsoleApiAction implements Runnable {
}
}
protected void finishAndPersistConsoleUpdateHistory(SimpleConsoleUpdateHistory.Builder builder) {
protected void finishAndPersistConsoleUpdateHistory(ConsoleUpdateHistory.Builder builder) {
builder.setActingUser(consoleApiParams.authResult().user().get());
builder.setUrl(consoleApiParams.request().getRequestURI());
builder.setMethod(consoleApiParams.request().getMethod());
@@ -28,7 +28,6 @@ import com.google.gson.annotations.Expose;
import google.registry.flows.EppException.AuthenticationErrorException;
import google.registry.flows.PasswordOnlyTransportCredentials;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.request.Action;
@@ -108,7 +107,7 @@ public class ConsoleEppPasswordAction extends ConsoleApiAction {
registrar.asBuilder().setPassword(eppRequestBody.newPassword()).build();
tm().put(updatedRegistrar);
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.EPP_PASSWORD_UPDATE)
.setDescription(registrar.getRegistrarId()));
sendExternalUpdates(
@@ -35,7 +35,6 @@ import google.registry.model.OteStats.StatType;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase;
import google.registry.request.Action;
import google.registry.request.Action.GkeService;
import google.registry.request.Parameter;
@@ -140,7 +139,7 @@ public class ConsoleOteAction extends ConsoleApiAction {
SC_BAD_REQUEST);
return;
}
if (!RegistrarBase.Type.OTE.equals(registrar.get().getType())) {
if (!Registrar.Type.OTE.equals(registrar.get().getType())) {
setFailedResponse(
String.format("Registrar with ID %s is not an OT&E registrar", registrarId),
SC_BAD_REQUEST);
@@ -24,7 +24,6 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableSet;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.request.Action;
@@ -102,7 +101,7 @@ public class ConsoleUpdateRegistrarAction extends ConsoleApiAction {
tm().put(updatedRegistrar);
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
.setDescription(updatedRegistrar.getRegistrarId()));
sendExternalUpdatesIfNecessary(
@@ -165,7 +165,7 @@ public class ConsoleUsersAction extends ConsoleApiAction {
User updatedUser = updateUserRegistrarRoles(email, registrarId, null);
// User has no registrars assigned
if (updatedUser.getUserRoles().getRegistrarRoles().size() == 0) {
if (updatedUser.getUserRoles().getRegistrarRoles().isEmpty()) {
try {
directory.users().delete(email).execute();
} catch (IOException e) {
@@ -28,11 +28,9 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
@@ -55,8 +53,8 @@ import java.util.Optional;
public class RegistrarsAction extends ConsoleApiAction {
private static final int PASSWORD_LENGTH = 16;
private static final int PASSCODE_LENGTH = 5;
private static final ImmutableList<RegistrarBase.Type> allowedRegistrarTypes =
ImmutableList.of(Registrar.Type.REAL, RegistrarBase.Type.OTE);
private static final ImmutableList<Registrar.Type> allowedRegistrarTypes =
ImmutableList.of(Registrar.Type.REAL, Registrar.Type.OTE);
private static final String SQL_TEMPLATE =
"""
SELECT * FROM "Registrar"
@@ -174,7 +172,7 @@ public class RegistrarsAction extends ConsoleApiAction {
registrar.getRegistrarId());
tm().putAll(registrar, contact);
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.REGISTRAR_CREATE)
.setDescription(registrar.getRegistrarId()));
});
@@ -26,7 +26,7 @@ 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.SimpleConsoleUpdateHistory;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.eppcommon.ProtocolDefinition;
import google.registry.model.eppoutput.EppOutput;
@@ -113,7 +113,7 @@ public class ConsoleBulkDomainAction extends ConsoleApiAction {
.forEach(
e ->
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setDescription(e.getKey())
.setType(actionType.getConsoleUpdateHistoryType()))));
}
@@ -32,7 +32,7 @@ import google.registry.model.console.ConsolePermission;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase.Type;
import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.persistence.transaction.QueryComposer.Comparator;
import google.registry.request.Action;
import google.registry.request.Action.GaeService;
@@ -17,13 +17,11 @@ package google.registry.ui.server.console.settings;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.request.Action.Method.POST;
import static jakarta.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
import static jakarta.servlet.http.HttpServletResponse.SC_FORBIDDEN;
import static jakarta.servlet.http.HttpServletResponse.SC_OK;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.request.Action;
@@ -36,7 +34,6 @@ import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAcce
import google.registry.ui.server.console.ConsoleApiAction;
import google.registry.ui.server.console.ConsoleApiParams;
import jakarta.inject.Inject;
import java.util.Objects;
import java.util.Optional;
/**
@@ -48,17 +45,17 @@ import java.util.Optional;
@Action(
service = GaeService.DEFAULT,
gkeService = GkeService.CONSOLE,
path = WhoisRegistrarFieldsAction.PATH,
path = RdapRegistrarFieldsAction.PATH,
method = {POST},
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class WhoisRegistrarFieldsAction extends ConsoleApiAction {
public class RdapRegistrarFieldsAction extends ConsoleApiAction {
static final String PATH = "/console-api/settings/whois-fields";
static final String PATH = "/console-api/settings/rdap-fields";
private final AuthenticatedRegistrarAccessor registrarAccessor;
private final Optional<Registrar> registrar;
@Inject
public WhoisRegistrarFieldsAction(
public RdapRegistrarFieldsAction(
ConsoleApiParams consoleApiParams,
AuthenticatedRegistrarAccessor registrarAccessor,
@Parameter("registrar") Optional<Registrar> registrar) {
@@ -72,10 +69,10 @@ public class WhoisRegistrarFieldsAction extends ConsoleApiAction {
checkArgument(registrar.isPresent(), "'registrar' parameter is not present");
checkPermission(
user, registrar.get().getRegistrarId(), ConsolePermission.EDIT_REGISTRAR_DETAILS);
tm().transact(() -> loadAndModifyRegistrar(registrar.get(), user));
tm().transact(() -> loadAndModifyRegistrar(registrar.get()));
}
private void loadAndModifyRegistrar(Registrar providedRegistrar, User user) {
private void loadAndModifyRegistrar(Registrar providedRegistrar) {
Registrar savedRegistrar;
try {
// reload to make sure the object has all the correct fields
@@ -85,29 +82,17 @@ public class WhoisRegistrarFieldsAction extends ConsoleApiAction {
return;
}
// icannReferralEmail can't be updated by partners, only by global users with
// EDIT_REGISTRAR_DETAILS permission
if (!Objects.equals(
savedRegistrar.getIcannReferralEmail(), providedRegistrar.getIcannReferralEmail())
&& !user.getUserRoles().hasGlobalPermission(ConsolePermission.EDIT_REGISTRAR_DETAILS)) {
setFailedResponse(
"Icann Referral Email update is not permitted for this user", SC_BAD_REQUEST);
}
Registrar newRegistrar =
savedRegistrar
.asBuilder()
.setWhoisServer(providedRegistrar.getWhoisServer())
.setUrl(providedRegistrar.getUrl())
.setLocalizedAddress(providedRegistrar.getLocalizedAddress())
.setPhoneNumber(providedRegistrar.getPhoneNumber())
.setFaxNumber(providedRegistrar.getFaxNumber())
.setIcannReferralEmail(providedRegistrar.getIcannReferralEmail())
.setEmailAddress(providedRegistrar.getEmailAddress())
.build();
tm().put(newRegistrar);
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE)
.setDescription(newRegistrar.getRegistrarId()));
sendExternalUpdatesIfNecessary(
@@ -26,7 +26,6 @@ import google.registry.flows.certs.CertificateChecker;
import google.registry.flows.certs.CertificateChecker.InsecureCertificateException;
import google.registry.model.console.ConsolePermission;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.registrar.Registrar;
import google.registry.request.Action;
@@ -120,7 +119,7 @@ public class SecurityAction extends ConsoleApiAction {
Registrar updatedRegistrar = updatedRegistrarBuilder.build();
tm().put(updatedRegistrar);
finishAndPersistConsoleUpdateHistory(
new SimpleConsoleUpdateHistory.Builder()
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.REGISTRAR_SECURITY_UPDATE)
.setDescription(registrarId));
@@ -47,12 +47,8 @@
<class>google.registry.model.billing.BillingRecurrence</class>
<class>google.registry.model.common.Cursor</class>
<class>google.registry.model.common.DnsRefreshRequest</class>
<class>google.registry.model.console.ConsoleEppActionHistory</class>
<class>google.registry.model.console.RegistrarPocUpdateHistory</class>
<class>google.registry.model.console.RegistrarUpdateHistory</class>
<class>google.registry.model.console.SimpleConsoleUpdateHistory</class>
<class>google.registry.model.console.ConsoleUpdateHistory</class>
<class>google.registry.model.console.User</class>
<class>google.registry.model.console.UserUpdateHistory</class>
<class>google.registry.model.contact.ContactHistory</class>
<class>google.registry.model.contact.Contact</class>
<class>google.registry.model.domain.Domain</class>
@@ -36,8 +36,7 @@ import google.registry.groups.GmailClient;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.model.registrar.RegistrarPocBase.Type;
import google.registry.model.registrar.RegistrarPoc.Type;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
@@ -57,13 +56,13 @@ class SendExpiringCertificateNotificationEmailActionTest {
private static final String EXPIRATION_WARNING_EMAIL_BODY_TEXT =
"""
Dear %1$s,
Dear %1$s,
We would like to inform you that your %2$s certificate will expire at %3$s.
Kind update your account using the following steps:
1. Navigate to support and login using your %4$s@registry.example credentials.
2. Click Settings -> Privacy on the top left corner.
3. Click Edit and enter certificate string. 3. Click SaveRegards,Example Registry""";
We would like to inform you that your %2$s certificate will expire at %3$s.
Kind update your account using the following steps:
1. Navigate to support and login using your %4$s@registry.example credentials.
2. Click Settings -> Privacy on the top left corner.
3. Click Edit and enter certificate string. 3. Click SaveRegards,Example Registry""";
private static final String EXPIRATION_WARNING_EMAIL_SUBJECT_TEXT = "Expiration Warning Email";
@@ -220,7 +219,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("will@example-registrar.tld")
.setPhoneNumber("+1.3105551213")
.setFaxNumber("+1.3105551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.build());
@@ -510,7 +509,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("jd@example-registrar.tld")
.setPhoneNumber("+1.3105551213")
.setFaxNumber("+1.3105551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.build(),
@@ -520,7 +519,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("js@example-registrar.tld")
.setPhoneNumber("+1.1111111111")
.setFaxNumber("+1.1111111111")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
@@ -528,7 +527,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("will@example-registrar.tld")
.setPhoneNumber("+1.3105551213")
.setFaxNumber("+1.3105551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.build(),
@@ -538,7 +537,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("mike@example-registrar.tld")
.setPhoneNumber("+1.1111111111")
.setFaxNumber("+1.1111111111")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
@@ -546,7 +545,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
.setEmailAddress("john@example-registrar.tld")
.setPhoneNumber("+1.3105551215")
.setFaxNumber("+1.3105551216")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsTech(true)
.build());
persistSimpleResources(contacts);
@@ -700,7 +699,7 @@ class SendExpiringCertificateNotificationEmailActionTest {
/** Returns persisted sample contacts with a customized contact email type. */
private static ImmutableList<RegistrarPoc> persistSampleContacts(
Registrar registrar, RegistrarPocBase.Type emailType) {
Registrar registrar, RegistrarPoc.Type emailType) {
return persistSimpleResources(
ImmutableList.of(
new RegistrarPoc.Builder()
@@ -70,7 +70,7 @@ import google.registry.model.rde.RdeMode;
import google.registry.model.rde.RdeRevision;
import google.registry.model.rde.RdeRevision.RdeRevisionId;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
@@ -388,22 +388,22 @@ public class RdePipelineTest {
assertThat(domainFrags.stream().findFirst().get().xml().strip())
.isEqualTo(
"""
<rdeDomain:domain>
<rdeDomain:name>cat.fun</rdeDomain:name>
<rdeDomain:roid>15-FUN</rdeDomain:roid>
<rdeDomain:uName>cat.fun</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:contact type="admin">contact456</rdeDomain:contact>
<rdeDomain:contact type="tech">contact456</rdeDomain:contact>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.hello.soy</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
<rdeDomain:domain>
<rdeDomain:name>cat.fun</rdeDomain:name>
<rdeDomain:roid>15-FUN</rdeDomain:roid>
<rdeDomain:uName>cat.fun</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:contact type="admin">contact456</rdeDomain:contact>
<rdeDomain:contact type="tech">contact456</rdeDomain:contact>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.hello.soy</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
}
if (kv.getKey().mode().equals(FULL)) {
// Contact fragments for hello.soy.
@@ -425,23 +425,23 @@ public class RdePipelineTest {
assertThat(domainFrags.stream().findFirst().get().xml().strip())
.isEqualTo(
"""
<rdeDomain:domain>
<rdeDomain:name>hello.soy</rdeDomain:name>
<rdeDomain:roid>E-SOY</rdeDomain:roid>
<rdeDomain:uName>hello.soy</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:registrant>contact1234</rdeDomain:registrant>
<rdeDomain:contact type="admin">contact789</rdeDomain:contact>
<rdeDomain:contact type="tech">contact1234</rdeDomain:contact>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.lol.cat</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
<rdeDomain:domain>
<rdeDomain:name>hello.soy</rdeDomain:name>
<rdeDomain:roid>E-SOY</rdeDomain:roid>
<rdeDomain:uName>hello.soy</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:registrant>contact1234</rdeDomain:registrant>
<rdeDomain:contact type="admin">contact789</rdeDomain:contact>
<rdeDomain:contact type="tech">contact1234</rdeDomain:contact>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.lol.cat</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
} else {
// Contact fragments for cat.fun.
assertThat(
@@ -471,20 +471,20 @@ public class RdePipelineTest {
assertThat(domainFrags.stream().findFirst().get().xml().strip())
.isEqualTo(
"""
<rdeDomain:domain>
<rdeDomain:name>hello.soy</rdeDomain:name>
<rdeDomain:roid>E-SOY</rdeDomain:roid>
<rdeDomain:uName>hello.soy</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.lol.cat</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
<rdeDomain:domain>
<rdeDomain:name>hello.soy</rdeDomain:name>
<rdeDomain:roid>E-SOY</rdeDomain:roid>
<rdeDomain:uName>hello.soy</rdeDomain:uName>
<rdeDomain:status s="ok"/>
<rdeDomain:ns>
<domain:hostObj>ns1.external.tld</domain:hostObj>
<domain:hostObj>ns1.lol.cat</domain:hostObj>
</rdeDomain:ns>
<rdeDomain:clID>TheRegistrar</rdeDomain:clID>
<rdeDomain:crRr>TheRegistrar</rdeDomain:crRr>
<rdeDomain:crDate>1970-01-01T00:00:00Z</rdeDomain:crDate>
<rdeDomain:exDate>294247-01-10T04:00:54Z</rdeDomain:exDate>
</rdeDomain:domain>""");
}
});
return null;
@@ -16,9 +16,9 @@ package google.registry.export;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.export.SyncGroupMembersAction.getGroupEmailAddressForContactType;
import static google.registry.model.registrar.RegistrarPocBase.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPocBase.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPocBase.Type.TECH;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.MARKETING;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -38,7 +38,6 @@ import google.registry.model.common.Cursor;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.DatabaseHelper;
@@ -158,8 +157,7 @@ public class SyncRegistrarsSheetTest {
.setName("Jane Doe")
.setEmailAddress("contact@example.com")
.setPhoneNumber("+1.1234567890")
.setTypes(
ImmutableSet.of(RegistrarPocBase.Type.ADMIN, RegistrarPocBase.Type.BILLING))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN, RegistrarPoc.Type.BILLING))
.build(),
new RegistrarPoc.Builder()
.setRegistrar(registrar)
@@ -167,7 +165,7 @@ public class SyncRegistrarsSheetTest {
.setEmailAddress("john.doe@example.tld")
.setPhoneNumber("+1.1234567890")
.setFaxNumber("+1.1234567891")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
// Purposely flip the internal/external admin/tech
// distinction to make sure we're not relying on it. Sigh.
.setVisibleInWhoisAsAdmin(false)
@@ -177,7 +175,7 @@ public class SyncRegistrarsSheetTest {
.setRegistrar(registrar)
.setName("Jane Smith")
.setEmailAddress("pride@example.net")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.build());
// Use registrar key for contacts' parent.
DateTime registrarCreationTime = persistResource(registrar).getCreationTime();
@@ -199,37 +197,37 @@ public class SyncRegistrarsSheetTest {
.containsEntry(
"primaryContacts",
"""
Jane Doe
contact@example.com
Tel: +1.1234567890
Types: [ADMIN, BILLING]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
Jane Doe
contact@example.com
Tel: +1.1234567890
Types: [ADMIN, BILLING]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
John Doe
john.doe@example.tld
Tel: +1.1234567890
Fax: +1.1234567891
Types: [ADMIN]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: Yes
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
John Doe
john.doe@example.tld
Tel: +1.1234567890
Fax: +1.1234567891
Types: [ADMIN]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: Yes
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
assertThat(row)
.containsEntry(
"techContacts",
"""
Jane Smith
pride@example.net
Types: [TECH]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
Jane Smith
pride@example.net
Types: [TECH]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
assertThat(row).containsEntry("marketingContacts", "");
assertThat(row).containsEntry("abuseContacts", "");
assertThat(row).containsEntry("whoisInquiryContacts", "");
@@ -238,30 +236,30 @@ public class SyncRegistrarsSheetTest {
.containsEntry(
"billingContacts",
"""
Jane Doe
contact@example.com
Tel: +1.1234567890
Types: [ADMIN, BILLING]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
Jane Doe
contact@example.com
Tel: +1.1234567890
Types: [ADMIN, BILLING]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: No
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
assertThat(row).containsEntry("contactsMarkedAsWhoisAdmin", "");
assertThat(row)
.containsEntry(
"contactsMarkedAsWhoisTech",
"""
John Doe
john.doe@example.tld
Tel: +1.1234567890
Fax: +1.1234567891
Types: [ADMIN]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: Yes
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
John Doe
john.doe@example.tld
Tel: +1.1234567890
Fax: +1.1234567891
Types: [ADMIN]
Visible in registrar WHOIS query as Admin contact: No
Visible in registrar WHOIS query as Technical contact: Yes
Phone number and email visible in domain WHOIS query as Registrar Abuse contact\
info: No
""");
assertThat(row).containsEntry("emailAddress", "nowhere@example.org");
assertThat(row).containsEntry(
"address.street", "I get fallen back upon since there's no l10n addr");
@@ -174,7 +174,7 @@ import google.registry.model.eppoutput.EppResponse;
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
@@ -93,7 +93,7 @@ import google.registry.model.domain.token.AllocationToken.TokenStatus;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
@@ -69,7 +69,7 @@ import google.registry.model.domain.rgp.GracePeriodStatus;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.DomainTransactionRecord.TransactionReportField;
import google.registry.model.reporting.HistoryEntry;
@@ -114,7 +114,7 @@ import google.registry.model.eppcommon.Trid;
import google.registry.model.poll.PendingActionNotificationResponse;
import google.registry.model.poll.PollMessage;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.reporting.DomainTransactionRecord;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntry.HistoryEntryId;
@@ -36,7 +36,7 @@ import google.registry.flows.session.LoginFlow.TooManyFailedLoginsException;
import google.registry.flows.session.LoginFlow.UnsupportedLanguageException;
import google.registry.model.eppoutput.EppOutput;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -1,68 +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.model.console;
import static com.google.common.collect.Iterables.getOnlyElement;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.persistActiveContact;
import static google.registry.testing.DatabaseHelper.persistDomainWithDependentResources;
import google.registry.model.EntityTestCase;
import google.registry.model.domain.DomainHistory;
import google.registry.testing.DatabaseHelper;
import google.registry.util.DateTimeUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Tests for {@link ConsoleEppActionHistory}. */
public class ConsoleEppActionHistoryTest extends EntityTestCase {
ConsoleEppActionHistoryTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@BeforeEach
void beforeEach() {
createTld("tld");
persistDomainWithDependentResources(
"example",
"tld",
persistActiveContact("contact1234"),
fakeClock.nowUtc(),
fakeClock.nowUtc(),
DateTimeUtils.END_OF_TIME);
}
@Test
void testPersistence() {
User user = DatabaseHelper.createAdminUser("email@email.com");
DomainHistory domainHistory = getOnlyElement(DatabaseHelper.loadAllOf(DomainHistory.class));
ConsoleEppActionHistory history =
new ConsoleEppActionHistory.Builder()
.setType(ConsoleUpdateHistory.Type.DOMAIN_DELETE)
.setActingUser(user)
.setModificationTime(fakeClock.nowUtc())
.setMethod("POST")
.setUrl("https://some/url/for/creating/a/domain")
.setHistoryEntryClass(DomainHistory.class)
.setHistoryEntryId(domainHistory.getHistoryEntryId())
.build();
tm().transact(() -> tm().put(history));
assertThat(getOnlyElement(DatabaseHelper.loadAllOf(ConsoleEppActionHistory.class)))
.isEqualTo(history);
}
}
@@ -27,8 +27,8 @@ import google.registry.util.DateTimeUtils;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
public class SimpleConsoleUpdateHistoryTest extends EntityTestCase {
SimpleConsoleUpdateHistoryTest() {
public class ConsoleUpdateHistoryTest extends EntityTestCase {
ConsoleUpdateHistoryTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@@ -47,8 +47,8 @@ public class SimpleConsoleUpdateHistoryTest extends EntityTestCase {
@Test
void testPersistence() {
User user = persistResource(DatabaseHelper.createAdminUser("email@email.com"));
SimpleConsoleUpdateHistory history =
new SimpleConsoleUpdateHistory.Builder()
ConsoleUpdateHistory history =
new ConsoleUpdateHistory.Builder()
.setType(ConsoleUpdateHistory.Type.DOMAIN_SUSPEND)
.setActingUser(user)
.setMethod("POST")
@@ -1,61 +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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.Iterables;
import google.registry.model.EntityTestCase;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPoc.RegistrarPocId;
import google.registry.persistence.VKey;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.Test;
/** Tests for {@link RegistrarPocUpdateHistory}. */
public class RegistrarPocUpdateHistoryTest extends EntityTestCase {
RegistrarPocUpdateHistoryTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@Test
void testPersistence() {
User user = DatabaseHelper.createAdminUser("email@email.com");
RegistrarPoc registrarPoc =
DatabaseHelper.loadByKey(
VKey.create(
RegistrarPoc.class,
new RegistrarPocId("johndoe@theregistrar.com", "TheRegistrar")));
RegistrarPocUpdateHistory history =
new RegistrarPocUpdateHistory.Builder()
.setRegistrarPoc(registrarPoc)
.setActingUser(user)
.setModificationTime(fakeClock.nowUtc())
.setType(ConsoleUpdateHistory.Type.USER_UPDATE)
.setMethod("POST")
.setUrl("someUrl")
.build();
tm().transact(() -> tm().put(history));
// Change the POC and make sure the history stays the same
tm().transact(() -> tm().put(registrarPoc.asBuilder().setName("Some Othername").build()));
RegistrarPocUpdateHistory fromDb =
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(RegistrarPocUpdateHistory.class));
assertThat(fromDb.getRegistrarPoc().getName()).isEqualTo("John Doe");
}
}
@@ -1,55 +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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import com.google.common.collect.Iterables;
import google.registry.model.EntityTestCase;
import google.registry.model.registrar.Registrar;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.Test;
/** Tests for {@link RegistrarUpdateHistory}. */
public class RegistrarUpdateHistoryTest extends EntityTestCase {
RegistrarUpdateHistoryTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@Test
void testPersistence() {
User user = DatabaseHelper.createAdminUser("email@email.com");
Registrar theRegistrar = DatabaseHelper.loadRegistrar("TheRegistrar");
RegistrarUpdateHistory history =
new RegistrarUpdateHistory.Builder()
.setRegistrar(theRegistrar)
.setActingUser(user)
.setModificationTime(fakeClock.nowUtc())
.setType(ConsoleUpdateHistory.Type.USER_UPDATE)
.setMethod("POST")
.setUrl("someUrl")
.build();
tm().transact(() -> tm().put(history));
// Change the registrar and make sure the history stays the same
tm().transact(() -> tm().put(theRegistrar.asBuilder().setUrl("https://other.url").build()));
RegistrarUpdateHistory fromDb =
Iterables.getOnlyElement(DatabaseHelper.loadAllOf(RegistrarUpdateHistory.class));
assertThat(fromDb.getRegistrar().getUrl()).isEqualTo("http://my.fake.url");
}
}
@@ -1,65 +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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.loadAllOf;
import com.google.common.collect.Iterables;
import google.registry.model.EntityTestCase;
import google.registry.testing.DatabaseHelper;
import org.junit.jupiter.api.Test;
/** Tests for {@link UserUpdateHistory}. */
public class UserUpdateHistoryTest extends EntityTestCase {
UserUpdateHistoryTest() {
super(JpaEntityCoverageCheck.ENABLED);
}
@Test
void testPersistence() {
User user = DatabaseHelper.createAdminUser("email@email.com");
User otherUser = DatabaseHelper.createAdminUser("otherEmail@email.com");
UserUpdateHistory history =
new UserUpdateHistory.Builder()
.setUser(otherUser)
.setActingUser(user)
.setModificationTime(fakeClock.nowUtc())
.setType(ConsoleUpdateHistory.Type.USER_UPDATE)
.setMethod("POST")
.setUrl("someUrl")
.build();
tm().transact(() -> tm().put(history));
// Change the acted-upon user and make sure that nothing changed in the history DB
tm().transact(
() ->
tm().put(
otherUser
.asBuilder()
.setUserRoles(
otherUser
.getUserRoles()
.asBuilder()
.setGlobalRole(GlobalRole.SUPPORT_LEAD)
.build())
.build()));
UserUpdateHistory fromDb = Iterables.getOnlyElement(loadAllOf(UserUpdateHistory.class));
assertThat(fromDb.getUser().getUserRoles().getGlobalRole()).isEqualTo(GlobalRole.FTE);
}
}
@@ -39,8 +39,8 @@ import com.google.common.collect.ImmutableSortedMap;
import com.google.common.collect.ImmutableSortedSet;
import google.registry.config.RegistryConfig;
import google.registry.model.EntityTestCase;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.Registrar.Type;
import google.registry.model.tld.Tld;
import google.registry.model.tld.Tld.TldType;
import google.registry.model.tld.Tlds;
@@ -129,7 +129,7 @@ class RegistrarTest extends EntityTestCase {
.setVisibleInWhoisAsTech(false)
.setPhoneNumber("+1.2125551213")
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ABUSE, RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ABUSE, RegistrarPoc.Type.ADMIN))
.build();
persistSimpleResources(
ImmutableList.of(
@@ -140,8 +140,7 @@ class RegistrarTest extends EntityTestCase {
.setEmailAddress("johndoe@example.com")
.setPhoneNumber("+1.2125551213")
.setFaxNumber("+1.2125551213")
.setTypes(
ImmutableSet.of(RegistrarPocBase.Type.LEGAL, RegistrarPocBase.Type.MARKETING))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.LEGAL, RegistrarPoc.Type.MARKETING))
.build()));
}
@@ -327,7 +326,7 @@ class RegistrarTest extends EntityTestCase {
.setVisibleInWhoisAsTech(true)
.setPhoneNumber("+1.2125551213")
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.build());
RegistrarPoc newTechAbuseContact =
persistSimpleResource(
@@ -339,13 +338,13 @@ class RegistrarTest extends EntityTestCase {
.setVisibleInWhoisAsTech(true)
.setPhoneNumber("+1.2125551213")
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH, RegistrarPocBase.Type.ABUSE))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH, RegistrarPoc.Type.ABUSE))
.build());
ImmutableSortedSet<RegistrarPoc> techContacts =
registrar.getContactsOfType(RegistrarPocBase.Type.TECH);
registrar.getContactsOfType(RegistrarPoc.Type.TECH);
assertThat(techContacts).containsExactly(newTechContact, newTechAbuseContact).inOrder();
ImmutableSortedSet<RegistrarPoc> abuseContacts =
registrar.getContactsOfType(RegistrarPocBase.Type.ABUSE);
registrar.getContactsOfType(RegistrarPoc.Type.ABUSE);
assertThat(abuseContacts).containsExactly(newTechAbuseContact, abuseAdminContact).inOrder();
}
@@ -0,0 +1,60 @@
// 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.module.frontend;
import dagger.Component;
import google.registry.config.CloudTasksUtilsModule;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig;
import google.registry.flows.ServerTridProviderModule;
import google.registry.flows.custom.CustomLogicFactoryModule;
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.KeyModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.privileges.secretmanager.SecretManagerModule;
import google.registry.request.Modules;
import google.registry.request.auth.AuthModule;
import google.registry.ui.ConsoleDebug;
import google.registry.util.UtilsModule;
import jakarta.inject.Singleton;
@Singleton
@Component(
modules = {
AuthModule.class,
CloudTasksUtilsModule.class,
RegistryConfig.ConfigModule.class,
ConsoleDebug.ConsoleConfigModule.class,
CredentialModule.class,
CustomLogicFactoryModule.class,
CloudTasksUtilsModule.class,
FrontendRequestComponent.FrontendRequestComponentModule.class,
GmailModule.class,
GroupsModule.class,
GroupssettingsModule.class,
MockDirectoryModule.class,
Modules.GsonModule.class,
KeyModule.class,
KeyringModule.class,
Modules.NetHttpTransportModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
StackdriverModule.class,
UtilsModule.class
})
interface FrontendTestComponent extends FrontendComponent {}
@@ -0,0 +1,30 @@
// 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.module.frontend;
import com.google.monitoring.metrics.MetricReporter;
import dagger.Lazy;
import google.registry.module.ServletBase;
public class FrontendTestServlet extends ServletBase {
private static final FrontendTestComponent component = DaggerFrontendTestComponent.create();
private static final FrontendRequestHandler requestHandler = component.requestHandler();
private static final Lazy<MetricReporter> metricReporter = component.metricReporter();
public FrontendTestServlet() {
super(requestHandler, metricReporter);
}
}
@@ -0,0 +1,45 @@
// 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.module.frontend;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.api.services.directory.Directory;
import com.google.api.services.directory.model.User;
import dagger.Module;
import dagger.Provides;
import java.io.IOException;
@Module
public class MockDirectoryModule {
@Provides
static Directory provideDirectory() {
Directory directory = mock(Directory.class);
Directory.Users users = mock(Directory.Users.class);
Directory.Users.Insert insert = mock(Directory.Users.Insert.class);
Directory.Users.Delete delete = mock(Directory.Users.Delete.class);
when(directory.users()).thenReturn(users);
try {
when(users.insert(any(User.class))).thenReturn(insert);
when(users.delete(anyString())).thenReturn(delete);
} catch (IOException e) {
throw new RuntimeException(e);
}
return directory;
}
}
@@ -19,7 +19,7 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
import static google.registry.testing.DatabaseHelper.insertInDb;
import google.registry.model.ImmutableObject;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaUnitTestExtension;
import jakarta.persistence.Entity;
@@ -30,10 +30,9 @@ import com.google.common.collect.Maps;
import com.google.common.collect.Streams;
import com.google.common.io.Resources;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.persistence.HibernateSchemaExporter;
import google.registry.persistence.NomulusPostgreSql;
import google.registry.persistence.PersistenceModule;
@@ -410,7 +409,7 @@ public abstract class JpaTransactionManagerExtension
.setVisibleInWhoisAsTech(false)
.setEmailAddress("janedoe@theregistrar.com")
.setPhoneNumber("+1.1234567890")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.build();
}
@@ -424,7 +423,7 @@ public abstract class JpaTransactionManagerExtension
.setName("John Doe")
.setEmailAddress("johndoe@theregistrar.com")
.setPhoneNumber("+1.1234567890")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.build();
}
@@ -435,7 +434,7 @@ public abstract class JpaTransactionManagerExtension
.setEmailAddress("Marla.Singer@crr.com")
.setRegistryLockEmailAddress("Marla.Singer.RegistryLock@crr.com")
.setPhoneNumber("+1.2128675309")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
.setAllowedToSetRegistryLockPassword(true)
.setRegistryLockPassword("hi")
.build();
@@ -39,7 +39,6 @@ import google.registry.model.eppcommon.StatusValue;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.transfer.DomainTransferData;
import google.registry.model.transfer.TransferStatus;
@@ -261,7 +260,7 @@ class RdapJsonFormatterTest {
.setEmailAddress("babydoe@example.com")
.setPhoneNumber("+1.2125551217")
.setFaxNumber("+1.2125551218")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsAdmin(false)
.setVisibleInWhoisAsTech(false)
.build(),
@@ -270,7 +269,7 @@ class RdapJsonFormatterTest {
.setName("John Doe")
.setEmailAddress("johndoe@example.com")
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsAdmin(false)
.setVisibleInWhoisAsTech(true)
.build(),
@@ -279,7 +278,7 @@ class RdapJsonFormatterTest {
.setName("Jane Doe")
.setEmailAddress("janedoe@example.com")
.setPhoneNumber("+1.2125551215")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH, RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH, RegistrarPoc.Type.ADMIN))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(false)
.build(),
@@ -289,7 +288,7 @@ class RdapJsonFormatterTest {
.setEmailAddress("playdoe@example.com")
.setPhoneNumber("+1.2125551217")
.setFaxNumber("+1.2125551218")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.BILLING))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.BILLING))
.setVisibleInWhoisAsAdmin(true)
.setVisibleInWhoisAsTech(true)
.build());
@@ -30,7 +30,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.request.HttpException.InternalServerErrorException;
@@ -50,22 +49,22 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
// This reply simulates part of the actual IANA CSV reply
private static final String CSV_REPLY =
"""
"ID",Registrar Name,Status,RDAP Base URL
1,Reserved,Reserved,
81,Gandi SAS,Accredited,https://rdap.gandi.net/
100,Whois Corp.,Accredited,https://www.yesnic.com/rdap/
134,BB-Online UK Limited,Accredited,https://rdap.bb-online.com/
1316,"Xiamen 35.Com Technology Co., Ltd.",Accredited,https://rdap.35.com/rdap/
1448,Blacknight Internet Solutions Ltd.,Accredited,https://rdap.blacknight.com/
1463,"Global Domains International, Inc. DBA DomainCostClub.com",Accredited,\
https://rdap.domaincostclub.com/
1556,"Chengdu West Dimension Digital Technology Co., Ltd.",Accredited,\
https://rdap.west.cn/rdap/
2288,Metaregistrar BV,Accredited,https://rdap.metaregistrar.com/
4000,Gname 031 Inc,Accredited,
9999,Reserved for non-billable transactions where Registry Operator acts as\
Registrar,Reserved,
""";
"ID",Registrar Name,Status,RDAP Base URL
1,Reserved,Reserved,
81,Gandi SAS,Accredited,https://rdap.gandi.net/
100,Whois Corp.,Accredited,https://www.yesnic.com/rdap/
134,BB-Online UK Limited,Accredited,https://rdap.bb-online.com/
1316,"Xiamen 35.Com Technology Co., Ltd.",Accredited,https://rdap.35.com/rdap/
1448,Blacknight Internet Solutions Ltd.,Accredited,https://rdap.blacknight.com/
1463,"Global Domains International, Inc. DBA DomainCostClub.com",Accredited,\
https://rdap.domaincostclub.com/
1556,"Chengdu West Dimension Digital Technology Co., Ltd.",Accredited,\
https://rdap.west.cn/rdap/
2288,Metaregistrar BV,Accredited,https://rdap.metaregistrar.com/
4000,Gname 031 Inc,Accredited,
9999,Reserved for non-billable transactions where Registry Operator acts as\
Registrar,Reserved,
""";
@RegisterExtension
public JpaIntegrationTestExtension jpa =
@@ -94,7 +93,7 @@ public final class UpdateRegistrarRdapBaseUrlsActionTest {
}
private static void persistRegistrar(
String registrarId, Long ianaId, RegistrarBase.Type type, String... rdapBaseUrls) {
String registrarId, Long ianaId, Registrar.Type type, String... rdapBaseUrls) {
persistSimpleResource(
new Registrar.Builder()
.setRegistrarId(registrarId)
@@ -22,8 +22,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import com.google.common.collect.ImmutableList;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.testing.FakeClock;
@@ -38,7 +38,7 @@ import google.registry.model.console.GlobalRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTestExtensions.JpaIntegrationTestExtension;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
@@ -24,12 +24,8 @@ import google.registry.model.billing.BillingBaseTest;
import google.registry.model.common.CursorTest;
import google.registry.model.common.DnsRefreshRequestTest;
import google.registry.model.common.FeatureFlagTest;
import google.registry.model.console.ConsoleEppActionHistoryTest;
import google.registry.model.console.RegistrarPocUpdateHistoryTest;
import google.registry.model.console.RegistrarUpdateHistoryTest;
import google.registry.model.console.SimpleConsoleUpdateHistoryTest;
import google.registry.model.console.ConsoleUpdateHistoryTest;
import google.registry.model.console.UserTest;
import google.registry.model.console.UserUpdateHistoryTest;
import google.registry.model.contact.ContactTest;
import google.registry.model.domain.DomainSqlTest;
import google.registry.model.domain.token.AllocationTokenTest;
@@ -98,7 +94,7 @@ import org.junit.runner.RunWith;
BsaUnblockableDomainTest.class,
BulkPricingPackageTest.class,
ClaimsListDaoTest.class,
ConsoleEppActionHistoryTest.class,
ConsoleUpdateHistoryTest.class,
ContactHistoryTest.class,
ContactTest.class,
CursorTest.class,
@@ -112,18 +108,14 @@ import org.junit.runner.RunWith;
PremiumListDaoTest.class,
RdeRevisionTest.class,
RegistrarDaoTest.class,
RegistrarPocUpdateHistoryTest.class,
RegistrarUpdateHistoryTest.class,
ReservedListDaoTest.class,
RegistryLockDaoTest.class,
ServerSecretTest.class,
SimpleConsoleUpdateHistoryTest.class,
SignedMarkRevocationListDaoTest.class,
Spec11ThreatMatchTest.class,
TldTest.class,
TmchCrlTest.class,
UserTest.class,
UserUpdateHistoryTest.class,
// AfterSuiteTest must be the last entry. See class javadoc for details.
AfterSuiteTest.class
})
@@ -15,7 +15,7 @@
package google.registry.schema.registrar;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.insertInDb;
import static google.registry.testing.DatabaseHelper.loadByEntity;
@@ -26,8 +26,12 @@ import static google.registry.testing.DatabaseHelper.persistResource;
import static org.joda.money.CurrencyUnit.USD;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import google.registry.model.OteStatsTestHelper;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.contact.Contact;
import google.registry.model.contact.ContactAddress;
import google.registry.model.contact.PostalInfo;
@@ -166,6 +170,30 @@ public enum Fixture {
.asBuilder()
.setAllowedTlds(ImmutableSet.of("example", "xn--q9jyb4c"))
.build());
persistResource(
new User.Builder()
.setEmailAddress("primary@registry.example")
.setRegistryLockEmailAddress("primary@theregistrar.com")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT))
.build())
.setRegistryLockPassword("registryLockPassword")
.build());
persistResource(
new User.Builder()
.setEmailAddress("accountmanager@registry.example")
.setRegistryLockEmailAddress("accountmanager@theregistrar.com")
.setUserRoles(
new UserRoles.Builder()
.setRegistrarRoles(
ImmutableMap.of(
"TheRegistrar", RegistrarRole.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK))
.build())
.setRegistryLockPassword("registryLockPassword")
.build());
}
};
@@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
import google.registry.module.backend.BackendServlet;
import google.registry.module.frontend.FrontendServlet;
import google.registry.module.frontend.FrontendTestServlet;
import java.net.URL;
import java.nio.file.Path;
@@ -49,7 +50,7 @@ public final class RegistryTestServer {
route("/whois/*", FrontendServlet.class),
route("/rdap/*", FrontendServlet.class),
route("/check", FrontendServlet.class),
route("/console-api/*", FrontendServlet.class),
route("/console-api/*", FrontendTestServlet.class),
// Proxy Services
route("/_dr/epp", FrontendServlet.class),
@@ -26,6 +26,7 @@ import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.OidcTokenAuthenticationMechanism;
import google.registry.testing.DatabaseHelper;
import google.registry.tools.params.HostAndPortParameter;
import google.registry.ui.ConsoleDebug;
import java.util.List;
@@ -106,47 +107,48 @@ public final class RegistryTestServerMain {
System.out.printf(
"""
CHARLESTON ROAD REGISTRY SHARED REGISTRATION SYSTEM
ICANN-GTLD-AGB-20120604
CHARLESTON ROAD REGISTRY SHARED REGISTRATION SYSTEM
ICANN-GTLD-AGB-20120604
%s
%s
%s( )%s
""",
%s
%s
%s( )%s
""",
LIGHT_PURPLE, ORANGE, PINK, RESET);
final RegistryTestServer server = new RegistryTestServer(address);
System.out.printf("%sLoading SQL fixtures setting User for authentication...%s\n", BLUE, RESET);
new JpaTestExtensions.Builder().buildIntegrationTestExtension().beforeEach(null);
JpaTransactionManagerExtension.loadInitialData();
UserRoles userRoles =
new UserRoles.Builder().setIsAdmin(loginIsAdmin).setGlobalRole(GlobalRole.FTE).build();
User user =
new User.Builder()
.setEmailAddress(loginEmail)
.setUserRoles(userRoles)
.setRegistryLockPassword("registryLockPassword")
.build();
DatabaseHelper.persistResource(
new User.Builder()
.setEmailAddress(loginEmail)
.setUserRoles(userRoles)
.setRegistryLockPassword("registryLockPassword")
.build());
OidcTokenAuthenticationMechanism.setAuthResultForTesting(AuthResult.createUser(user));
new JpaTestExtensions.Builder().buildIntegrationTestExtension().beforeEach(null);
JpaTransactionManagerExtension.loadInitialData();
System.out.printf("%sLoading fixtures...%s\n", BLUE, RESET);
for (Fixture fixture : fixtures) {
fixture.load();
@@ -153,9 +153,9 @@ public final class TestServer {
private ServletContextHandler createHandler(
Map<String, Path> runfiles, ImmutableList<Route> routes) {
ServletContextHandler context = new ServletContextHandler(CONTEXT_PATH, WebAppContext.SESSIONS);
ServletHolder holder;
context.setContextPath(CONTEXT_PATH);
context.addServlet(HealthzServlet.class, "/healthz");
ServletHolder holder;
for (Map.Entry<String, Path> runfile : runfiles.entrySet()) {
holder = context.addServlet(StaticResourceServlet.class, runfile.getKey());
StaticResourceServlet.configureServletHolder(holder, runfile.getKey(), runfile.getValue());
@@ -93,9 +93,8 @@ import google.registry.model.host.Host;
import google.registry.model.poll.PollMessage;
import google.registry.model.pricing.StaticPremiumListPricingEngine;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.reporting.HistoryEntry;
import google.registry.model.reporting.HistoryEntryDao;
import google.registry.model.tld.Tld;
@@ -761,7 +760,7 @@ public final class DatabaseHelper {
public static Registrar persistNewRegistrar(
String registrarId,
String registrarName,
RegistrarBase.Type type,
Registrar.Type type,
@Nullable Long ianaIdentifier) {
return persistSimpleResource(
new Registrar.Builder()
@@ -38,9 +38,7 @@ import google.registry.model.eppcommon.Trid;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarBase;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.registrar.RegistrarPocBase;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.util.Idn;
@@ -54,12 +52,12 @@ import org.joda.time.DateTime;
public final class FullFieldsTestEntityHelper {
public static Registrar makeRegistrar(
String registrarId, String registrarName, RegistrarBase.State state) {
String registrarId, String registrarName, Registrar.State state) {
return makeRegistrar(registrarId, registrarName, state, 1L);
}
public static Registrar makeRegistrar(
String registrarId, String registrarName, RegistrarBase.State state, Long ianaIdentifier) {
String registrarId, String registrarName, Registrar.State state, Long ianaIdentifier) {
return new Registrar.Builder()
.setRegistrarId(registrarId)
.setRegistrarName(registrarName)
@@ -101,7 +99,7 @@ public final class FullFieldsTestEntityHelper {
.setEmailAddress("johndoe@example.com")
.setPhoneNumber("+1.2125551213")
.setFaxNumber("+1.2125551213")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.ADMIN))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
// Purposely flip the internal/external admin/tech
// distinction to make sure we're not relying on it. Sigh.
.setVisibleInWhoisAsAdmin(false)
@@ -113,7 +111,7 @@ public final class FullFieldsTestEntityHelper {
.setEmailAddress("janedoe@example.com")
.setPhoneNumber("+1.2125551215")
.setFaxNumber("+1.2125551216")
.setTypes(ImmutableSet.of(RegistrarPocBase.Type.TECH))
.setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
// Purposely flip the internal/external admin/tech
// distinction to make sure we're not relying on it. Sigh.
.setVisibleInWhoisAsAdmin(true)
@@ -18,7 +18,7 @@ import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.Type;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -18,7 +18,7 @@ import static google.registry.testing.DatabaseHelper.persistNewRegistrar;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.beust.jcommander.ParameterException;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.Type;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -26,7 +26,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableList;
import google.registry.model.domain.Domain;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.Type;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DeterministicStringGenerator;
@@ -15,10 +15,10 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.registrar.RegistrarPocBase.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPocBase.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPocBase.Type.TECH;
import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS;
import static google.registry.model.registrar.RegistrarPoc.Type.ABUSE;
import static google.registry.model.registrar.RegistrarPoc.Type.ADMIN;
import static google.registry.model.registrar.RegistrarPoc.Type.TECH;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -17,7 +17,7 @@ package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.OteAccountBuilderTest.verifyUser;
import static google.registry.model.console.User.IAP_SECURED_WEB_APP_USER_ROLE;
import static google.registry.model.registrar.RegistrarBase.State.ACTIVE;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.model.tld.Tld.TldState.GENERAL_AVAILABILITY;
import static google.registry.model.tld.Tld.TldState.START_DATE_SUNRISE;
import static google.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
@@ -29,7 +29,7 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import google.registry.model.domain.Domain;
import google.registry.model.domain.RegistryLock;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.Type;
import google.registry.testing.CloudTasksHelper;
import google.registry.testing.DatabaseHelper;
import google.registry.testing.DeterministicStringGenerator;
@@ -37,8 +37,8 @@ import com.google.common.collect.ImmutableSortedMap;
import google.registry.flows.certs.CertificateChecker;
import google.registry.flows.certs.CertificateChecker.InsecureCertificateException;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.RegistrarBase.Type;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.Registrar.Type;
import google.registry.persistence.transaction.JpaTransactionManagerExtension;
import google.registry.util.CidrAddressBlock;
import java.math.BigDecimal;
@@ -15,7 +15,7 @@
package google.registry.tools;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.registrar.RegistrarBase.State.ACTIVE;
import static google.registry.model.registrar.Registrar.State.ACTIVE;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.loadRegistrar;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -32,7 +32,7 @@ import google.registry.flows.EppException;
import google.registry.flows.TransportCredentials.BadRegistrarPasswordException;
import google.registry.flows.certs.CertificateChecker;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase.State;
import google.registry.model.registrar.Registrar.State;
import google.registry.testing.CertificateSamples;
import google.registry.util.CidrAddressBlock;
import java.nio.file.Files;
@@ -34,7 +34,6 @@ import com.google.gson.Gson;
import google.registry.flows.PasswordOnlyTransportCredentials;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
@@ -140,7 +139,7 @@ class ConsoleEppPasswordActionTest {
action.run();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
assertDoesNotThrow(() -> credentials.validate(loadRegistrar("TheRegistrar"), "randomPassword"));
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.EPP_PASSWORD_UPDATE);
assertThat(history.getDescription()).hasValue("TheRegistrar");
}
@@ -15,7 +15,7 @@
package google.registry.ui.server.console;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.registrar.RegistrarPocBase.Type.WHOIS;
import static google.registry.model.registrar.RegistrarPoc.Type.WHOIS;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.loadSingleton;
import static google.registry.testing.DatabaseHelper.persistResource;
@@ -31,11 +31,9 @@ import com.google.common.collect.ImmutableSet;
import com.google.gson.Gson;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarBase;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.persistence.transaction.JpaTestExtensions;
import google.registry.request.Action;
@@ -83,7 +81,7 @@ class ConsoleUpdateRegistrarActionTest {
persistResource(
registrar
.asBuilder()
.setType(RegistrarBase.Type.REAL)
.setType(Registrar.Type.REAL)
.setAllowedTlds(ImmutableSet.of())
.setRegistryLockAllowed(false)
.build());
@@ -108,7 +106,7 @@ class ConsoleUpdateRegistrarActionTest {
assertThat(newRegistrar.getAllowedTlds()).containsExactly("app", "dev");
assertThat(newRegistrar.isRegistryLockAllowed()).isFalse();
assertThat(((FakeResponse) consoleApiParams.response()).getStatus()).isEqualTo(SC_OK);
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_UPDATE);
assertThat(history.getDescription()).hasValue("TheRegistrar");
}
@@ -32,7 +32,6 @@ import com.google.gson.Gson;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.registrar.Registrar;
@@ -186,7 +185,7 @@ class RegistrarsActionTest {
.findAny()
.isPresent())
.isTrue();
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.REGISTRAR_CREATE);
assertThat(history.getDescription()).hasValue("regIdTest");
}
@@ -42,7 +42,6 @@ import google.registry.model.common.FeatureFlag;
import google.registry.model.console.ConsoleUpdateHistory;
import google.registry.model.console.GlobalRole;
import google.registry.model.console.RegistrarRole;
import google.registry.model.console.SimpleConsoleUpdateHistory;
import google.registry.model.console.User;
import google.registry.model.console.UserRoles;
import google.registry.model.domain.Domain;
@@ -123,7 +122,7 @@ public class ConsoleBulkDomainActionTest {
{"example.tld":{"message":"Command completed successfully; action pending",\
"responseCode":1001}}""");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35));
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE);
assertThat(history.getDescription()).hasValue("example.tld");
}
@@ -151,7 +150,7 @@ public class ConsoleBulkDomainActionTest {
{"example.tld":{"message":"Command completed successfully","responseCode":1000}}""");
assertThat(loadByEntity(domain).getStatusValues())
.containsAtLeastElementsIn(serverSuspensionStatuses);
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_SUSPEND);
assertThat(history.getDescription()).hasValue("example.tld");
}
@@ -181,7 +180,7 @@ public class ConsoleBulkDomainActionTest {
"""
{"example.tld":{"message":"Command completed successfully","responseCode":1000}}""");
assertThat(loadByEntity(domain).getStatusValues()).containsNoneIn(serverSuspensionStatuses);
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_UNSUSPEND);
assertThat(history.getDescription()).hasValue("example.tld");
}
@@ -206,7 +205,7 @@ public class ConsoleBulkDomainActionTest {
"nonexistent.tld":{"message":"The domain with given ID (nonexistent.tld) doesn\\u0027t exist.",\
"responseCode":2303}}""");
assertThat(loadByEntity(domain).getDeletionTime()).isEqualTo(clock.nowUtc().plusDays(35));
SimpleConsoleUpdateHistory history = loadSingleton(SimpleConsoleUpdateHistory.class).get();
ConsoleUpdateHistory history = loadSingleton(ConsoleUpdateHistory.class).get();
assertThat(history.getType()).isEqualTo(ConsoleUpdateHistory.Type.DOMAIN_DELETE);
assertThat(history.getDescription()).hasValue("example.tld");
}

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