mirror of
https://github.com/google/nomulus
synced 2026-05-25 01:01:57 +00:00
Compare commits
4 Commits
nomulus-20
...
nomulus-20
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ce2f98f680 | ||
|
|
daaf231d39 | ||
|
|
955c3d9aeb | ||
|
|
d03cea2443 |
@@ -61,6 +61,11 @@
|
||||
<url-pattern>/registry-lock-get</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>frontend-servlet</servlet-name>
|
||||
<url-pattern>/registry-lock-verify</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Security config -->
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
|
||||
@@ -15,16 +15,22 @@
|
||||
package google.registry.model.eppcommon;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static com.google.common.base.Strings.nullToEmpty;
|
||||
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
|
||||
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.googlecode.objectify.annotation.Ignore;
|
||||
import com.googlecode.objectify.annotation.OnLoad;
|
||||
import google.registry.model.Buildable;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.JsonMapBuilder;
|
||||
import google.registry.model.Jsonifiable;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
import javax.persistence.Transient;
|
||||
import javax.xml.bind.annotation.XmlElement;
|
||||
import javax.xml.bind.annotation.XmlTransient;
|
||||
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
|
||||
@@ -42,12 +48,21 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
|
||||
* @see google.registry.model.registrar.RegistrarAddress
|
||||
*/
|
||||
@XmlTransient
|
||||
@Embeddable
|
||||
@MappedSuperclass
|
||||
public class Address extends ImmutableObject implements Jsonifiable {
|
||||
|
||||
/** The schema validation will enforce that this has 3 lines at most. */
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
@Transient
|
||||
List<String> street;
|
||||
|
||||
@Ignore String streetLine1;
|
||||
|
||||
@Ignore String streetLine2;
|
||||
|
||||
@Ignore String streetLine3;
|
||||
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
String city;
|
||||
|
||||
@@ -64,7 +79,23 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
String countryCode;
|
||||
|
||||
public ImmutableList<String> getStreet() {
|
||||
return nullToEmptyImmutableCopy(street);
|
||||
if (street == null && streetLine1 != null) {
|
||||
return ImmutableList.of(streetLine1, nullToEmpty(streetLine2), nullToEmpty(streetLine3));
|
||||
} else {
|
||||
return nullToEmptyImmutableCopy(street);
|
||||
}
|
||||
}
|
||||
|
||||
public String getStreetLine1() {
|
||||
return streetLine1;
|
||||
}
|
||||
|
||||
public String getStreetLine2() {
|
||||
return streetLine2;
|
||||
}
|
||||
|
||||
public String getStreetLine13() {
|
||||
return streetLine3;
|
||||
}
|
||||
|
||||
public String getCity() {
|
||||
@@ -139,4 +170,14 @@ public class Address extends ImmutableObject implements Jsonifiable {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
||||
@OnLoad
|
||||
void setStreetForCloudSql() {
|
||||
if (street == null || street.size() == 0) {
|
||||
return;
|
||||
}
|
||||
streetLine1 = street.get(0);
|
||||
streetLine2 = street.size() >= 2 ? street.get(1) : null;
|
||||
streetLine3 = street.size() >= 3 ? street.get(2) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +169,8 @@ public enum StatusValue implements EppEnum {
|
||||
/** Hibernate type for sets of {@link StatusValue}. */
|
||||
public static class StatusValueSetType extends EnumSetUserType<StatusValue> {
|
||||
@Override
|
||||
protected Object convertToElem(Object value) {
|
||||
return StatusValue.valueOf((String) value);
|
||||
protected StatusValue convertToElem(String value) {
|
||||
return StatusValue.valueOf(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,12 +85,27 @@ import java.util.function.Predicate;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.mail.internet.AddressException;
|
||||
import javax.mail.internet.InternetAddress;
|
||||
import javax.persistence.AttributeOverride;
|
||||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Information about a registrar. */
|
||||
@ReportedOn
|
||||
@Entity
|
||||
@javax.persistence.Entity
|
||||
@Table(
|
||||
indexes = {
|
||||
@javax.persistence.Index(columnList = "registrarName", name = "registrar_name_idx"),
|
||||
@javax.persistence.Index(
|
||||
columnList = "ianaIdentifier",
|
||||
name = "registrar_iana_identifier_idx"),
|
||||
})
|
||||
public class Registrar extends ImmutableObject implements Buildable, Jsonifiable {
|
||||
|
||||
/** Represents the type of a registrar entity. */
|
||||
@@ -208,14 +223,17 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
.doTransactionless(
|
||||
() -> Maps.uniqueIndex(loadAll(), Registrar::getClientId)));
|
||||
|
||||
@Parent
|
||||
Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
@Parent @Transient Key<EntityGroupRoot> parent = getCrossTldKey();
|
||||
|
||||
/**
|
||||
* Unique registrar client id. Must conform to "clIDType" as defined in RFC5730.
|
||||
*
|
||||
* @see <a href="http://tools.ietf.org/html/rfc5730#section-4.2">Shared Structure Schema</a>
|
||||
* <p>TODO(shicong): Rename this field to clientId
|
||||
*/
|
||||
@Id
|
||||
@javax.persistence.Id
|
||||
@Column(name = "client_id", nullable = false)
|
||||
String clientIdentifier;
|
||||
|
||||
/**
|
||||
@@ -229,21 +247,27 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
* @see <a href="http://www.icann.org/registrar-reports/accredited-list.html">ICANN-Accredited
|
||||
* Registrars</a>
|
||||
*/
|
||||
@Index String registrarName;
|
||||
@Index
|
||||
@Column(nullable = false)
|
||||
String registrarName;
|
||||
|
||||
/** The type of this registrar. */
|
||||
@Column(nullable = false)
|
||||
Type type;
|
||||
|
||||
/** The state of this registrar. */
|
||||
State state;
|
||||
|
||||
/** The set of TLDs which this registrar is allowed to access. */
|
||||
// TODO(b/147908600): Investigate how to automatically apply user type
|
||||
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
|
||||
Set<String> allowedTlds;
|
||||
|
||||
/** Host name of WHOIS server. */
|
||||
String whoisServer;
|
||||
|
||||
/** Base URLs for the registrar's RDAP servers. */
|
||||
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
|
||||
Set<String> rdapBaseUrls;
|
||||
|
||||
/**
|
||||
@@ -271,12 +295,14 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
String failoverClientCertificateHash;
|
||||
|
||||
/** A whitelist of netmasks (in CIDR notation) which the client is allowed to connect from. */
|
||||
@org.hibernate.annotations.Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
|
||||
List<CidrAddressBlock> ipAddressWhitelist;
|
||||
|
||||
/** A hashed password for EPP access. The hash is a base64 encoded SHA256 string. */
|
||||
String passwordHash;
|
||||
|
||||
/** Randomly generated hash salt. */
|
||||
@Column(name = "password_salt")
|
||||
String salt;
|
||||
|
||||
// The following fields may appear redundant to the above, but are
|
||||
@@ -287,6 +313,24 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
* unrestricted UTF-8.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(
|
||||
name = "streetLine1",
|
||||
column = @Column(name = "localized_address_street_line1")),
|
||||
@AttributeOverride(
|
||||
name = "streetLine2",
|
||||
column = @Column(name = "localized_address_street_line2")),
|
||||
@AttributeOverride(
|
||||
name = "streetLine3",
|
||||
column = @Column(name = "localized_address_street_line3")),
|
||||
@AttributeOverride(name = "city", column = @Column(name = "localized_address_city")),
|
||||
@AttributeOverride(name = "state", column = @Column(name = "localized_address_state")),
|
||||
@AttributeOverride(name = "zip", column = @Column(name = "localized_address_zip")),
|
||||
@AttributeOverride(
|
||||
name = "countryCode",
|
||||
column = @Column(name = "localized_address_country_code"))
|
||||
})
|
||||
RegistrarAddress localizedAddress;
|
||||
|
||||
/**
|
||||
@@ -294,6 +338,16 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
* representable in the 7-bit US-ASCII character set.
|
||||
*/
|
||||
@IgnoreSave(IfNull.class)
|
||||
@Embedded
|
||||
@AttributeOverrides({
|
||||
@AttributeOverride(name = "streetLine1", column = @Column(name = "i18n_address_street_line1")),
|
||||
@AttributeOverride(name = "streetLine2", column = @Column(name = "i18n_address_street_line2")),
|
||||
@AttributeOverride(name = "streetLine3", column = @Column(name = "i18n_address_street_line3")),
|
||||
@AttributeOverride(name = "city", column = @Column(name = "i18n_address_city")),
|
||||
@AttributeOverride(name = "state", column = @Column(name = "i18n_address_state")),
|
||||
@AttributeOverride(name = "zip", column = @Column(name = "i18n_address_zip")),
|
||||
@AttributeOverride(name = "countryCode", column = @Column(name = "i18n_address_country_code"))
|
||||
})
|
||||
RegistrarAddress internationalizedAddress;
|
||||
|
||||
/** Voice number. */
|
||||
@@ -309,16 +363,17 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
|
||||
/**
|
||||
* Registrar identifier used for reporting to ICANN.
|
||||
*
|
||||
* <ul>
|
||||
* <li>8 is used for Testing Registrar.
|
||||
* <li>9997 is used by ICAAN for SLA monitoring.
|
||||
* <li>9999 is used for cases when the registry operator acts as registrar.
|
||||
* </ul>
|
||||
* @see <a href="http://www.iana.org/assignments/registrar-ids/registrar-ids.txt">Registrar IDs</a>
|
||||
*
|
||||
* @see <a href="http://www.iana.org/assignments/registrar-ids/registrar-ids.txt">Registrar
|
||||
* IDs</a>
|
||||
*/
|
||||
@Index
|
||||
@Nullable
|
||||
Long ianaIdentifier;
|
||||
@Index @Nullable Long ianaIdentifier;
|
||||
|
||||
/** Identifier of registrar used in external billing system (e.g. Oracle). */
|
||||
@Nullable
|
||||
@@ -338,18 +393,19 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
*/
|
||||
@Nullable
|
||||
@Mapify(CurrencyMapper.class)
|
||||
@org.hibernate.annotations.Type(type = "google.registry.persistence.CurrencyToBillingMapUserType")
|
||||
Map<CurrencyUnit, BillingAccountEntry> billingAccountMap;
|
||||
|
||||
/** A billing account entry for this registrar, consisting of a currency and an account Id. */
|
||||
@Embed
|
||||
static class BillingAccountEntry extends ImmutableObject {
|
||||
public static class BillingAccountEntry extends ImmutableObject {
|
||||
|
||||
CurrencyUnit currency;
|
||||
String accountId;
|
||||
|
||||
BillingAccountEntry() {}
|
||||
|
||||
BillingAccountEntry(CurrencyUnit currency, String accountId) {
|
||||
public BillingAccountEntry(CurrencyUnit currency, String accountId) {
|
||||
this.accountId = accountId;
|
||||
this.currency = currency;
|
||||
}
|
||||
@@ -366,6 +422,11 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
return billingAccountEntry.currency;
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the account id of this entry. */
|
||||
public String getAccountId() {
|
||||
return accountId;
|
||||
}
|
||||
}
|
||||
|
||||
/** URL of registrar's website. */
|
||||
@@ -390,14 +451,10 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
|
||||
/** An automatically managed last-saved timestamp. */
|
||||
UpdateAutoTimestamp lastUpdateTime = UpdateAutoTimestamp.create(null);
|
||||
|
||||
/**
|
||||
* The time that the certificate was last updated.
|
||||
*/
|
||||
/** The time that the certificate was last updated. */
|
||||
DateTime lastCertificateUpdateTime;
|
||||
|
||||
/**
|
||||
* Telephone support passcode (5-digit numeric)
|
||||
*/
|
||||
/** Telephone support passcode (5-digit numeric) */
|
||||
String phonePasscode;
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@ import static google.registry.util.CollectionUtils.forceEmptyToNull;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.googlecode.objectify.annotation.Embed;
|
||||
import google.registry.model.eppcommon.Address;
|
||||
import javax.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
* Registrar Address
|
||||
@@ -29,6 +30,7 @@ import google.registry.model.eppcommon.Address;
|
||||
* classes.
|
||||
*/
|
||||
@Embed
|
||||
@Embeddable
|
||||
public class RegistrarAddress extends Address {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -31,6 +31,7 @@ import google.registry.ui.server.registrar.OteStatusAction;
|
||||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.registrar.RegistrarSettingsAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockVerifyAction;
|
||||
|
||||
/** Dagger component with per-request lifetime for "default" App Engine module. */
|
||||
@RequestScope
|
||||
@@ -53,6 +54,8 @@ interface FrontendRequestComponent {
|
||||
|
||||
RegistryLockGetAction registryLockGetAction();
|
||||
|
||||
RegistryLockVerifyAction registryLockVerifyAction();
|
||||
|
||||
@Subcomponent.Builder
|
||||
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
|
||||
@Override public abstract Builder requestModule(RequestModule requestModule);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Hibernate {@link org.hibernate.usertype.UserType} for storing/retrieving {@link
|
||||
* List<CidrAddressBlock>} objects.
|
||||
*/
|
||||
public class CidrAddressBlockListUserType extends StringListUserType<CidrAddressBlock> {
|
||||
|
||||
@Override
|
||||
protected CidrAddressBlock convertToElem(String columnValue) {
|
||||
return columnValue == null ? null : CidrAddressBlock.create(columnValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String convertToColumn(CidrAddressBlock elementValue) {
|
||||
return elementValue == null ? null : elementValue.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.collect.ImmutableMap.toImmutableMap;
|
||||
|
||||
import google.registry.model.registrar.Registrar.BillingAccountEntry;
|
||||
import java.util.Map;
|
||||
import org.hibernate.usertype.UserType;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
|
||||
/**
|
||||
* A custom {@link UserType} for storing/retrieving {@link Map<CurrencyUnit, BillingAccountEntry>}
|
||||
* objects.
|
||||
*/
|
||||
public class CurrencyToBillingMapUserType extends MapUserType {
|
||||
|
||||
@Override
|
||||
public Object toEntityTypeMap(Map<String, String> map) {
|
||||
return map.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> CurrencyUnit.of(entry.getKey()),
|
||||
entry ->
|
||||
new BillingAccountEntry(CurrencyUnit.of(entry.getKey()), entry.getValue())));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> toDbSupportedMap(Object map) {
|
||||
return ((Map<CurrencyUnit, BillingAccountEntry>) map)
|
||||
.entrySet().stream()
|
||||
.collect(
|
||||
toImmutableMap(
|
||||
entry -> entry.getKey().getCode(), entry -> entry.getValue().getAccountId()));
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,12 @@ import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/** Abstract Hibernate user type for storing/retrieving {@link Set<Enum<E>>}. */
|
||||
public class EnumSetUserType<E extends Enum<E>> extends GenericCollectionUserType<Set<Enum<E>>> {
|
||||
public class EnumSetUserType<E extends Enum<E>>
|
||||
extends GenericCollectionUserType<Set<E>, E, String> {
|
||||
|
||||
@Override
|
||||
Set<Enum<E>> getNewCollection() {
|
||||
return new HashSet<Enum<E>>();
|
||||
Set<E> getNewCollection() {
|
||||
return new HashSet<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import java.sql.Array;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
@@ -23,8 +24,15 @@ import java.util.Collection;
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/** Generic Hibernate user type to store/retrieve Java collection as an array in Cloud SQL. */
|
||||
public abstract class GenericCollectionUserType<T extends Collection> extends MutableUserType {
|
||||
/**
|
||||
* Generic Hibernate user type to store/retrieve Java collection as an array in Cloud SQL.
|
||||
*
|
||||
* @param <T> the concrete {@link Collection} type of the entity field
|
||||
* @param <E> the Java type of the element for the collection of the entity field
|
||||
* @param <C> the JDBC supported type of the element in the DB column array
|
||||
*/
|
||||
public abstract class GenericCollectionUserType<T extends Collection<E>, E, C>
|
||||
extends MutableUserType {
|
||||
|
||||
abstract T getNewCollection();
|
||||
|
||||
@@ -54,6 +62,11 @@ public abstract class GenericCollectionUserType<T extends Collection> extends Mu
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class returnedClass() {
|
||||
return new TypeInstantiator<T>(getClass()) {}.getExactType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] sqlTypes() {
|
||||
return new int[] {getColumnType().getTypeCode()};
|
||||
@@ -65,7 +78,7 @@ public abstract class GenericCollectionUserType<T extends Collection> extends Mu
|
||||
throws HibernateException, SQLException {
|
||||
if (rs.getArray(names[0]) != null) {
|
||||
T result = getNewCollection();
|
||||
for (Object element : (Object[]) rs.getArray(names[0]).getArray()) {
|
||||
for (C element : (C[]) rs.getArray(names[0]).getArray()) {
|
||||
result.add(convertToElem(element));
|
||||
}
|
||||
return result;
|
||||
@@ -81,8 +94,12 @@ public abstract class GenericCollectionUserType<T extends Collection> extends Mu
|
||||
st.setArray(index, null);
|
||||
return;
|
||||
}
|
||||
T list = (T) value;
|
||||
Array arr = st.getConnection().createArrayOf(getColumnType().getTypeName(), list.toArray());
|
||||
T collection = (T) value;
|
||||
Array arr =
|
||||
st.getConnection()
|
||||
.createArrayOf(
|
||||
getColumnType().getTypeName(),
|
||||
collection.stream().map(this::convertToColumn).toArray());
|
||||
st.setArray(index, arr);
|
||||
}
|
||||
|
||||
@@ -92,7 +109,11 @@ public abstract class GenericCollectionUserType<T extends Collection> extends Mu
|
||||
* <p>This method is useful when encoding a java type to one of the types that can be used as an
|
||||
* array element.
|
||||
*/
|
||||
protected Object convertToElem(Object columnValue) {
|
||||
return columnValue;
|
||||
protected E convertToElem(C columnValue) {
|
||||
return (E) columnValue;
|
||||
}
|
||||
|
||||
protected C convertToColumn(E elementValue) {
|
||||
return (C) elementValue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.util.TypeUtils.TypeInstantiator;
|
||||
import javax.persistence.AttributeConverter;
|
||||
|
||||
/** Generic converter for storing/retrieving {@link Enum} objects. */
|
||||
public class GenericEnumConverter<T extends Enum<T>> implements AttributeConverter<T, String> {
|
||||
|
||||
@Override
|
||||
public String convertToDatabaseColumn(T attribute) {
|
||||
return attribute == null ? null : attribute.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T convertToEntityAttribute(String dbData) {
|
||||
return dbData == null
|
||||
? null
|
||||
: Enum.valueOf(new TypeInstantiator<T>(getClass()) {}.getExactType(), dbData);
|
||||
}
|
||||
}
|
||||
@@ -45,13 +45,29 @@ public class MapUserType extends MutableUserType {
|
||||
public Object nullSafeGet(
|
||||
ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
|
||||
throws HibernateException, SQLException {
|
||||
return rs.getObject(names[0]);
|
||||
return toEntityTypeMap((Map<String, String>) rs.getObject(names[0]));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void nullSafeSet(
|
||||
PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
|
||||
throws HibernateException, SQLException {
|
||||
st.setObject(index, value);
|
||||
st.setObject(index, toDbSupportedMap(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass can override this method to convert the {@link Map<String, String>} to a {@link Map}
|
||||
* of specific type defined in the entity class.
|
||||
*/
|
||||
public Object toEntityTypeMap(Map<String, String> map) {
|
||||
return map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclass can override this method to convert the {@link Map} of specific type to a {@link
|
||||
* Map<String, String>} that can be stored in the hstore type column.
|
||||
*/
|
||||
public Map<String, String> toDbSupportedMap(Object map) {
|
||||
return (Map<String, String>) map;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA converter for storing/retrieving {@link Registrar.State} objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class RegistrarStateConverter extends GenericEnumConverter<Registrar.State> {}
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/** JPA converter for storing/retrieving {@link Registrar.Type} objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class RegistrarTypeConverter extends GenericEnumConverter<Registrar.Type> {}
|
||||
@@ -18,10 +18,10 @@ import com.google.common.collect.Lists;
|
||||
import java.util.List;
|
||||
|
||||
/** Abstract Hibernate user type for storing/retrieving {@link List<String>}. */
|
||||
public class StringListUserType extends GenericCollectionUserType<List<String>> {
|
||||
public class StringListUserType<E> extends GenericCollectionUserType<List<E>, E, String> {
|
||||
|
||||
@Override
|
||||
List<String> getNewCollection() {
|
||||
List<E> getNewCollection() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@@ -29,9 +29,4 @@ public class StringListUserType extends GenericCollectionUserType<List<String>>
|
||||
ArrayColumnType getColumnType() {
|
||||
return ArrayColumnType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class returnedClass() {
|
||||
return List.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,10 +18,10 @@ import com.google.common.collect.Sets;
|
||||
import java.util.Set;
|
||||
|
||||
/** Abstract Hibernate user type for storing/retrieving {@link Set<String>}. */
|
||||
public class StringSetUserType extends GenericCollectionUserType<Set<String>> {
|
||||
public class StringSetUserType<E> extends GenericCollectionUserType<Set<E>, E, String> {
|
||||
|
||||
@Override
|
||||
Set<String> getNewCollection() {
|
||||
Set<E> getNewCollection() {
|
||||
return Sets.newHashSet();
|
||||
}
|
||||
|
||||
@@ -29,9 +29,4 @@ public class StringSetUserType extends GenericCollectionUserType<Set<String>> {
|
||||
ArrayColumnType getColumnType() {
|
||||
return ArrayColumnType.STRING;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class returnedClass() {
|
||||
return Set.class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,7 +156,11 @@ public class PremiumListDao {
|
||||
RevisionIdAndLabel.create(premiumList.getRevisionId(), label);
|
||||
try {
|
||||
Optional<BigDecimal> price = PremiumListCache.cachePremiumEntries.get(revisionIdAndLabel);
|
||||
return price.map(p -> Money.of(premiumList.getCurrency(), p));
|
||||
return price.map(
|
||||
p ->
|
||||
Money.of(
|
||||
premiumList.getCurrency(),
|
||||
p.setScale(premiumList.getCurrency().getDecimalPlaces())));
|
||||
} catch (InvalidCacheLoadException | ExecutionException e) {
|
||||
throw new RuntimeException(
|
||||
String.format(
|
||||
|
||||
@@ -38,7 +38,7 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
static final ImmutableSet<StatusValue> REGISTRY_LOCK_STATUSES =
|
||||
public static final ImmutableSet<StatusValue> REGISTRY_LOCK_STATUSES =
|
||||
ImmutableSet.of(
|
||||
SERVER_DELETE_PROHIBITED, SERVER_TRANSFER_PROHIBITED, SERVER_UPDATE_PROHIBITED);
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
|
||||
|
||||
import static google.registry.request.RequestParameters.extractBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||
@@ -144,4 +144,16 @@ public final class RegistrarConsoleModule {
|
||||
static Optional<String> provideOptionalPasscode(HttpServletRequest req) {
|
||||
return extractOptionalParameter(req, "passcode");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("lockVerificationCode")
|
||||
static String provideLockVerificationCode(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "lockVerificationCode");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("isLock")
|
||||
static Boolean provideIsLock(HttpServletRequest req) {
|
||||
return extractBooleanParameter(req, "isLock");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
|
||||
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.template.soy.tofu.SoyTofu;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.SoyTemplateUtils;
|
||||
import google.registry.ui.soy.registrar.RegistryLockVerificationSoyInfo;
|
||||
import google.registry.util.Clock;
|
||||
import java.util.HashMap;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Action that allows for verification of registry lock / unlock requests */
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
path = RegistryLockVerifyAction.PATH,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public final class RegistryLockVerifyAction extends HtmlAction {
|
||||
|
||||
public static final String PATH = "/registry-lock-verify";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Supplier<SoyTofu> TOFU_SUPPLIER =
|
||||
SoyTemplateUtils.createTofuSupplier(
|
||||
google.registry.ui.soy.ConsoleSoyInfo.getInstance(),
|
||||
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
|
||||
google.registry.ui.soy.registrar.RegistryLockVerificationSoyInfo.getInstance());
|
||||
|
||||
private final Clock clock;
|
||||
private final String lockVerificationCode;
|
||||
private final Boolean isLock;
|
||||
|
||||
@Inject
|
||||
public RegistryLockVerifyAction(
|
||||
Clock clock,
|
||||
@Parameter("lockVerificationCode") String lockVerificationCode,
|
||||
@Parameter("isLock") Boolean isLock) {
|
||||
this.clock = clock;
|
||||
this.lockVerificationCode = lockVerificationCode;
|
||||
this.isLock = isLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAfterLogin(HashMap<String, Object> data) {
|
||||
try {
|
||||
boolean isAdmin = authResult.userAuthInfo().get().isUserAdmin();
|
||||
final RegistryLock resultLock;
|
||||
if (isLock) {
|
||||
resultLock = DomainLockUtils.verifyAndApplyLock(lockVerificationCode, isAdmin, clock);
|
||||
} else {
|
||||
resultLock = DomainLockUtils.verifyAndApplyUnlock(lockVerificationCode, isAdmin, clock);
|
||||
}
|
||||
data.put("isLock", isLock);
|
||||
data.put("success", true);
|
||||
data.put("fullyQualifiedDomainName", resultLock.getDomainName());
|
||||
} catch (Throwable t) {
|
||||
logger.atWarning().withCause(t).log(
|
||||
"Error when verifying verification code %s", lockVerificationCode);
|
||||
data.put("success", false);
|
||||
data.put("errorMessage", Throwables.getRootCause(t).getMessage());
|
||||
}
|
||||
response.setPayload(
|
||||
TOFU_SUPPLIER
|
||||
.get()
|
||||
.newRenderer(RegistryLockVerificationSoyInfo.VERIFICATION_PAGE)
|
||||
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
|
||||
.setData(data)
|
||||
.render());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return PATH;
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@
|
||||
* Use Hibernate's ServiceRegistry for bootstrapping (not JPA-compliant)
|
||||
-->
|
||||
<class>google.registry.model.domain.DomainBase</class>
|
||||
<class>google.registry.model.registrar.Registrar</class>
|
||||
<class>google.registry.schema.domain.RegistryLock</class>
|
||||
<class>google.registry.schema.tmch.ClaimsList</class>
|
||||
<class>google.registry.schema.cursor.Cursor</class>
|
||||
@@ -40,6 +41,8 @@
|
||||
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.CurrencyUnitConverter</class>
|
||||
<class>google.registry.persistence.DateTimeConverter</class>
|
||||
<class>google.registry.persistence.RegistrarStateConverter</class>
|
||||
<class>google.registry.persistence.RegistrarTypeConverter</class>
|
||||
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.ZonedDateTimeConverter</class>
|
||||
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
{namespace registry.soy.registrar.registrylock.verification}
|
||||
|
||||
|
||||
/**
|
||||
* Results page for a registry lock/unlock verification.
|
||||
*/
|
||||
{template .verificationPage}
|
||||
{@param username: string} /** Arbitrary username to display. */
|
||||
{@param analyticsConfig: [googleAnalyticsId: string|null]}
|
||||
{@param success: bool}
|
||||
{@param? errorMessage: string}
|
||||
{@param? isLock: bool}
|
||||
{@param? fullyQualifiedDomainName: string}
|
||||
{call registry.soy.console.header}
|
||||
{param app: 'registrar' /}
|
||||
{param subtitle: 'Verify Registry Lock' /}
|
||||
{param analyticsConfig: $analyticsConfig /}
|
||||
{/call}
|
||||
{call registry.soy.console.googlebar data="all" /}
|
||||
<div id="reg-content-and-footer">
|
||||
<div id="reg-content">
|
||||
<h1>Registry Lock Verification</h1>
|
||||
{if $success}
|
||||
{call .success data="all" /}
|
||||
{else}
|
||||
{call .failure data="all" /}
|
||||
{/if}
|
||||
<h3><a href="/registrar">Return to Registrar Console</a></h3>
|
||||
</div>
|
||||
{call registry.soy.console.footer /}
|
||||
</div>
|
||||
{/template}
|
||||
|
||||
/**
|
||||
* Result page for failure, e.g. the UUID was invalid
|
||||
*/
|
||||
{template .failure}
|
||||
{@param? errorMessage: string}
|
||||
<h2 class="{css('kd-errormessage')}">Failed: {if isNonnull($errorMessage)}
|
||||
{$errorMessage}
|
||||
{else}
|
||||
Undefined error message
|
||||
{/if}
|
||||
</h2>
|
||||
{/template}
|
||||
|
||||
/**
|
||||
* Result page for a successful lock / unlock.
|
||||
*/
|
||||
{template .success}
|
||||
{@param? isLock: bool}
|
||||
{@param? fullyQualifiedDomainName: string}
|
||||
<h3>
|
||||
Success: {if $isLock}lock{else}unlock{/if} has been applied to {$fullyQualifiedDomainName}
|
||||
</h3>
|
||||
{/template}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import google.registry.util.CidrAddressBlock;
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CidrAddressBlockListUserType}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CidrAddressBlockListUserTypeTest {
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
@Test
|
||||
public void roundTripConversion_returnsSameCidrAddressBlock() {
|
||||
List<CidrAddressBlock> addresses =
|
||||
ImmutableList.of(
|
||||
CidrAddressBlock.create("0.0.0.0/32"),
|
||||
CidrAddressBlock.create("255.255.255.254/31"),
|
||||
CidrAddressBlock.create("::"),
|
||||
CidrAddressBlock.create("8000::/1"),
|
||||
CidrAddressBlock.create("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128"));
|
||||
TestEntity testEntity = new TestEntity(addresses);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.addresses).isEqualTo(addresses);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
@Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
|
||||
List<CidrAddressBlock> addresses;
|
||||
|
||||
private TestEntity() {}
|
||||
|
||||
private TestEntity(List<CidrAddressBlock> addresses) {
|
||||
this.addresses = addresses;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.registrar.Registrar.BillingAccountEntry;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.hibernate.annotations.Type;
|
||||
import org.joda.money.CurrencyUnit;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link CurrencyToBillingMapUserType}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class CurrencyToBillingMapUserTypeTest {
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder()
|
||||
.withInitScript("sql/flyway/V14__load_extension_for_hstore.sql")
|
||||
.withEntityClass(TestEntity.class)
|
||||
.buildUnitTestRule();
|
||||
|
||||
@Test
|
||||
public void roundTripConversion_returnsSameCurrencyToBillingMap() {
|
||||
ImmutableMap<CurrencyUnit, BillingAccountEntry> currencyToBilling =
|
||||
ImmutableMap.of(
|
||||
CurrencyUnit.of("USD"),
|
||||
new BillingAccountEntry(CurrencyUnit.of("USD"), "accountId1"),
|
||||
CurrencyUnit.of("CNY"),
|
||||
new BillingAccountEntry(CurrencyUnit.of("CNY"), "accountId2"));
|
||||
TestEntity testEntity = new TestEntity(currencyToBilling);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.currencyToBilling).containsExactlyEntriesIn(currencyToBilling);
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
@Type(type = "google.registry.persistence.CurrencyToBillingMapUserType")
|
||||
Map<CurrencyUnit, BillingAccountEntry> currencyToBilling;
|
||||
|
||||
private TestEntity() {}
|
||||
|
||||
private TestEntity(Map<CurrencyUnit, BillingAccountEntry> currencyToBilling) {
|
||||
this.currencyToBilling = currencyToBilling;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -56,8 +56,8 @@ public class EnumSetUserTypeTest {
|
||||
|
||||
public static class TestEnumType extends EnumSetUserType<TestEnum> {
|
||||
@Override
|
||||
protected Object convertToElem(Object value) {
|
||||
return TestEnum.valueOf((String) value);
|
||||
protected TestEnum convertToElem(String value) {
|
||||
return TestEnum.valueOf(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistrarStateConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistrarStateConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
@Test
|
||||
public void roundTripConversion_returnsSameEnum() {
|
||||
TestEntity testEntity = new TestEntity(State.ACTIVE);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.state).isEqualTo(State.ACTIVE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativeQuery_succeeds() {
|
||||
TestEntity testEntity = new TestEntity(State.DISABLED);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery("SELECT state FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getSingleResult()))
|
||||
.isEqualTo("DISABLED");
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
State state;
|
||||
|
||||
private TestEntity() {}
|
||||
|
||||
private TestEntity(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.persistence;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.registrar.Registrar.Type;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RegistrarTypeConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistrarTypeConverterTest {
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
@Test
|
||||
public void roundTripConversion_returnsSameEnum() {
|
||||
TestEntity testEntity = new TestEntity(Type.MONITORING);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.type).isEqualTo(Type.MONITORING);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNativeQuery_succeeds() {
|
||||
TestEntity testEntity = new TestEntity(Type.MONITORING);
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
|
||||
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery("SELECT type FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getSingleResult()))
|
||||
.isEqualTo("MONITORING");
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
private static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
Type type;
|
||||
|
||||
private TestEntity() {}
|
||||
|
||||
private TestEntity(Type type) {
|
||||
this.type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,7 @@ import google.registry.tools.UpdateReservedListCommandTest;
|
||||
import google.registry.tools.server.CreatePremiumListActionTest;
|
||||
import google.registry.tools.server.UpdatePremiumListActionTest;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
|
||||
import google.registry.ui.server.registrar.RegistryLockVerifyActionTest;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
@@ -60,6 +61,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
||||
PremiumListDaoTest.class,
|
||||
RegistryLockDaoTest.class,
|
||||
RegistryLockGetActionTest.class,
|
||||
RegistryLockVerifyActionTest.class,
|
||||
ReservedListDaoTest.class,
|
||||
UnlockDomainCommandTest.class,
|
||||
UpdatePremiumListActionTest.class,
|
||||
|
||||
@@ -202,4 +202,38 @@ public class PremiumListDaoTest {
|
||||
() -> PremiumListDao.getPremiumPrice("foobar", Registry.get("tld")));
|
||||
assertThat(thrown).hasMessageThat().isEqualTo("Could not load premium list 'tld'");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPremiumPrice_worksForJPY() {
|
||||
persistResource(
|
||||
newRegistry("foobar", "FOOBAR")
|
||||
.asBuilder()
|
||||
.setPremiumListKey(
|
||||
Key.create(
|
||||
getCrossTldKey(),
|
||||
google.registry.model.registry.label.PremiumList.class,
|
||||
"premlist"))
|
||||
.build());
|
||||
PremiumListDao.saveNew(
|
||||
PremiumList.create(
|
||||
"premlist",
|
||||
JPY,
|
||||
ImmutableMap.of(
|
||||
"silver",
|
||||
BigDecimal.valueOf(10.00),
|
||||
"gold",
|
||||
BigDecimal.valueOf(1000.0),
|
||||
"palladium",
|
||||
BigDecimal.valueOf(15000))));
|
||||
assertThat(PremiumListDao.getPremiumPrice("silver", Registry.get("foobar")))
|
||||
.hasValue(moneyOf(JPY, 10));
|
||||
assertThat(PremiumListDao.getPremiumPrice("gold", Registry.get("foobar")))
|
||||
.hasValue(moneyOf(JPY, 1000));
|
||||
assertThat(PremiumListDao.getPremiumPrice("palladium", Registry.get("foobar")))
|
||||
.hasValue(moneyOf(JPY, 15000));
|
||||
}
|
||||
|
||||
private static Money moneyOf(CurrencyUnit unit, double amount) {
|
||||
return Money.of(unit, BigDecimal.valueOf(amount).setScale(unit.getDecimalPlaces()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,8 @@ public final class RegistryTestServer {
|
||||
route("/registrar-ote-setup", FrontendServlet.class),
|
||||
route("/registrar-ote-status", FrontendServlet.class),
|
||||
route("/registrar-settings", FrontendServlet.class),
|
||||
route("/registry-lock-get", FrontendServlet.class));
|
||||
route("/registry-lock-get", FrontendServlet.class),
|
||||
route("/registry-lock-verify", FrontendServlet.class));
|
||||
|
||||
private static final ImmutableList<Class<? extends Filter>> FILTERS = ImmutableList.of(
|
||||
ObjectifyFilter.class,
|
||||
|
||||
@@ -0,0 +1,345 @@
|
||||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.RegistryLockDao;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.DatastoreHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.UserInfo;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public final class RegistryLockVerifyActionTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
@Rule public final InjectRule inject = new InjectRule();
|
||||
|
||||
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
private final UserService userService = UserServiceFactory.getUserService();
|
||||
private final User user = new User("marla.singer@example.com", "gmail.com", "12345");
|
||||
private final String lockId = "f1be78a2-2d61-458c-80f0-9dd8f2f8625f";
|
||||
|
||||
private FakeResponse response;
|
||||
private DomainBase domain;
|
||||
private AuthResult authResult;
|
||||
private RegistryLockVerifyAction action;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createTlds("tld", "net");
|
||||
HostResource host = persistActiveHost("ns1.example.net");
|
||||
domain = persistResource(newDomainBase("example.tld", host));
|
||||
when(request.getRequestURI()).thenReturn("https://registry.example/registry-lock-verification");
|
||||
action = createAction(lockId, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_lockDomain() {
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(reloadDomain().getStatusValues()).containsExactlyElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isTrue();
|
||||
assertThat(historyEntry.getBySuperuser()).isFalse();
|
||||
assertThat(historyEntry.getReason())
|
||||
.isEqualTo("Lock or unlock of a domain through a RegistryLock operation");
|
||||
assertBillingEvent(historyEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_unlockDomain() {
|
||||
action = createAction(lockId, false);
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setUnlockRequestTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
assertThat(reloadDomain().getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isTrue();
|
||||
assertThat(historyEntry.getBySuperuser()).isFalse();
|
||||
assertThat(historyEntry.getReason())
|
||||
.isEqualTo("Lock or unlock of a domain through a RegistryLock operation");
|
||||
assertBillingEvent(historyEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_adminLock_createsOnlyHistoryEntry() {
|
||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, true));
|
||||
RegistryLockDao.save(createLock().asBuilder().isSuperuser(true).build());
|
||||
|
||||
action.run();
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isFalse();
|
||||
assertThat(historyEntry.getBySuperuser()).isTrue();
|
||||
DatastoreHelper.assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badVerificationCode() {
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setVerificationCode(UUID.randomUUID().toString()).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Invalid verification code");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyVerified() {
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setLockCompletionTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_expired() {
|
||||
RegistryLockDao.save(createLock());
|
||||
fakeClock.advanceBy(Duration.standardHours(2));
|
||||
action.run();
|
||||
assertThat(response.getPayload())
|
||||
.contains("Failed: The pending lock has expired; please try again");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAdmin_verifyingAdminLock() {
|
||||
RegistryLockDao.save(createLock().asBuilder().isSuperuser(true).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Non-admin user cannot complete admin lock");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyUnlocked() {
|
||||
action = createAction(lockId, false);
|
||||
RegistryLockDao.save(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyLocked() {
|
||||
RegistryLockDao.save(createLock());
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notLoggedIn() {
|
||||
action.authResult = AuthResult.NOT_AUTHENTICATED;
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_MOVED_TEMPORARILY);
|
||||
assertThat(response.getHeaders()).containsKey("Location");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doesNotChangeLockObject() {
|
||||
// A failure when performing Datastore actions means that no actions should be taken in the
|
||||
// Cloud SQL RegistryLock object
|
||||
RegistryLock lock = createLock();
|
||||
RegistryLockDao.save(lock);
|
||||
// reload the lock to pick up creation time
|
||||
lock = RegistryLockDao.getByVerificationCode(lock.getVerificationCode()).get();
|
||||
fakeClock.advanceOneMilli();
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
action.run();
|
||||
// we would have failed during the Datastore segment of the action
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
|
||||
// verify that the changes to the SQL object were rolled back
|
||||
RegistryLock afterAction =
|
||||
RegistryLockDao.getByVerificationCode(lock.getVerificationCode()).get();
|
||||
assertThat(afterAction).isEqualTo(lock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_isLockTrue_shouldBeFalse() {
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_isLockFalse_shouldBeTrue() {
|
||||
action = createAction(lockId, false);
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_lock_unlock_lockAgain() {
|
||||
RegistryLock lock = RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
String unlockVerificationCode = "some-unlock-code";
|
||||
RegistryLockDao.save(
|
||||
lock.asBuilder()
|
||||
.setVerificationCode(unlockVerificationCode)
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action = createAction(unlockVerificationCode, false);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
action = createAction(lockId, true);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Invalid verification code");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_lock_lockAgain() {
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
action = createAction(lockId, true);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unlock_unlockAgain() {
|
||||
action = createAction(lockId, false);
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setUnlockRequestTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
action = createAction(lockId, false);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
}
|
||||
|
||||
private RegistryLock createLock() {
|
||||
return new RegistryLock.Builder()
|
||||
.setDomainName("example.tld")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setRepoId("repoId")
|
||||
.setRegistrarPocId("marla.singer@example.com")
|
||||
.isSuperuser(false)
|
||||
.setVerificationCode(lockId)
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainBase reloadDomain() {
|
||||
return ofy().load().entity(domain).now();
|
||||
}
|
||||
|
||||
private void assertNoDomainChanges() {
|
||||
assertThat(reloadDomain()).isEqualTo(domain);
|
||||
}
|
||||
|
||||
private void assertBillingEvent(HistoryEntry historyEntry) {
|
||||
DatastoreHelper.assertBillingEvents(
|
||||
new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.SERVER_STATUS)
|
||||
.setTargetId(domain.getForeignKey())
|
||||
.setClientId(domain.getCurrentSponsorClientId())
|
||||
.setCost(Registry.get(domain.getTld()).getServerStatusChangeCost())
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.setBillingTime(fakeClock.nowUtc())
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
}
|
||||
|
||||
private RegistryLockVerifyAction createAction(String lockVerificationCode, Boolean isLock) {
|
||||
response = new FakeResponse();
|
||||
RegistryLockVerifyAction action =
|
||||
new RegistryLockVerifyAction(fakeClock, lockVerificationCode, isLock);
|
||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
||||
action.req = request;
|
||||
action.response = response;
|
||||
action.authResult = authResult;
|
||||
action.userService = userService;
|
||||
action.logoFilename = "logo.png";
|
||||
action.productName = "Nomulus";
|
||||
action.analyticsConfig = ImmutableMap.of("googleAnalyticsId", "sampleId");
|
||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||
return action;
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ import static google.registry.server.Fixture.BASIC;
|
||||
import static google.registry.server.Route.route;
|
||||
import static google.registry.testing.AppEngineRule.makeRegistrar2;
|
||||
import static google.registry.testing.AppEngineRule.makeRegistrarContact2;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
@@ -26,7 +28,9 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.googlecode.objectify.ObjectifyFilter;
|
||||
import google.registry.model.ofy.OfyFilter;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.model.registry.RegistryLockDao;
|
||||
import google.registry.module.frontend.FrontendServlet;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.server.RegistryTestServer;
|
||||
import google.registry.testing.CertificateSamples;
|
||||
import org.junit.Rule;
|
||||
@@ -46,7 +50,8 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
||||
.setRoutes(
|
||||
route("/registrar", FrontendServlet.class),
|
||||
route("/registrar-ote-status", FrontendServlet.class),
|
||||
route("/registrar-settings", FrontendServlet.class))
|
||||
route("/registrar-settings", FrontendServlet.class),
|
||||
route("/registry-lock-verify", FrontendServlet.class))
|
||||
.setFilters(ObjectifyFilter.class, OfyFilter.class)
|
||||
.setFixtures(BASIC)
|
||||
.setEmail("Marla.Singer@google.com")
|
||||
@@ -370,4 +375,36 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
||||
Thread.sleep(500);
|
||||
driver.diffPage("page");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registryLockVerify_success() throws Throwable {
|
||||
String lockVerificationCode = "f1be78a2-2d61-458c-80f0-9dd8f2f8625f";
|
||||
server.runInAppEngineEnvironment(
|
||||
() -> {
|
||||
createTld("tld");
|
||||
persistResource(newDomainBase("example.tld"));
|
||||
RegistryLockDao.save(
|
||||
new RegistryLock.Builder()
|
||||
.setRegistrarPocId("johndoe@theregistrar.com")
|
||||
.setRepoId("repoId")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setVerificationCode("f1be78a2-2d61-458c-80f0-9dd8f2f8625f")
|
||||
.isSuperuser(false)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
return null;
|
||||
});
|
||||
driver.get(
|
||||
server.getUrl(
|
||||
"/registry-lock-verify?isLock=true&lockVerificationCode=" + lockVerificationCode));
|
||||
driver.waitForElement(By.id("reg-content"));
|
||||
driver.diffPage("page");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registryLockVerify_unknownLock() throws Throwable {
|
||||
driver.get(server.getUrl("/registry-lock-verify?isLock=true&lockVerificationCode=asdfasdf"));
|
||||
driver.waitForElement(By.id("reg-content"));
|
||||
driver.diffPage("page");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,3 +6,4 @@ PATH CLASS METHODS OK AUTH_METHODS
|
||||
/registrar-ote-status OteStatusAction POST n API,LEGACY USER PUBLIC
|
||||
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
|
||||
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
|
||||
/registry-lock-verify RegistryLockVerifyAction GET n API,LEGACY USER PUBLIC
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
65
db/src/main/resources/sql/flyway/V16__create_registrar.sql
Normal file
65
db/src/main/resources/sql/flyway/V16__create_registrar.sql
Normal file
@@ -0,0 +1,65 @@
|
||||
-- Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
--
|
||||
-- Licensed under the Apache License, Version 2.0 (the "License");
|
||||
-- you may not use this file except in compliance with the License.
|
||||
-- You may obtain a copy of the License at
|
||||
--
|
||||
-- http://www.apache.org/licenses/LICENSE-2.0
|
||||
--
|
||||
-- Unless required by applicable law or agreed to in writing, software
|
||||
-- distributed under the License is distributed on an "AS IS" BASIS,
|
||||
-- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
-- See the License for the specific language governing permissions and
|
||||
-- limitations under the License.
|
||||
|
||||
create table "Registrar" (
|
||||
client_id text not null,
|
||||
allowed_tlds text[],
|
||||
billing_account_map hstore,
|
||||
billing_identifier int8,
|
||||
block_premium_names boolean not null,
|
||||
client_certificate text,
|
||||
client_certificate_hash text,
|
||||
contacts_require_syncing boolean not null,
|
||||
creation_time timestamptz,
|
||||
drive_folder_id text,
|
||||
email_address text,
|
||||
failover_client_certificate text,
|
||||
failover_client_certificate_hash text,
|
||||
fax_number text,
|
||||
iana_identifier int8,
|
||||
icann_referral_email text,
|
||||
i18n_address_city text,
|
||||
i18n_address_country_code text,
|
||||
i18n_address_state text,
|
||||
i18n_address_street_line1 text,
|
||||
i18n_address_street_line2 text,
|
||||
i18n_address_street_line3 text,
|
||||
i18n_address_zip text,
|
||||
ip_address_whitelist text[],
|
||||
last_certificate_update_time timestamptz,
|
||||
last_update_time timestamptz,
|
||||
localized_address_city text,
|
||||
localized_address_country_code text,
|
||||
localized_address_state text,
|
||||
localized_address_street_line1 text,
|
||||
localized_address_street_line2 text,
|
||||
localized_address_street_line3 text,
|
||||
localized_address_zip text,
|
||||
password_hash text,
|
||||
phone_number text,
|
||||
phone_passcode text,
|
||||
po_number text,
|
||||
rdap_base_urls text[],
|
||||
registrar_name text not null,
|
||||
registry_lock_allowed boolean not null,
|
||||
password_salt text,
|
||||
state text,
|
||||
type text not null,
|
||||
url text,
|
||||
whois_server text,
|
||||
primary key (client_id)
|
||||
);
|
||||
|
||||
create index registrar_name_idx on "Registrar" (registrar_name);
|
||||
create index registrar_iana_identifier_idx on "Registrar" (iana_identifier);
|
||||
@@ -93,6 +93,55 @@
|
||||
primary key (revision_id)
|
||||
);
|
||||
|
||||
create table "Registrar" (
|
||||
client_id text not null,
|
||||
allowed_tlds text[],
|
||||
billing_account_map hstore,
|
||||
billing_identifier int8,
|
||||
block_premium_names boolean not null,
|
||||
client_certificate text,
|
||||
client_certificate_hash text,
|
||||
contacts_require_syncing boolean not null,
|
||||
creation_time timestamptz,
|
||||
drive_folder_id text,
|
||||
email_address text,
|
||||
failover_client_certificate text,
|
||||
failover_client_certificate_hash text,
|
||||
fax_number text,
|
||||
iana_identifier int8,
|
||||
icann_referral_email text,
|
||||
i18n_address_city text,
|
||||
i18n_address_country_code text,
|
||||
i18n_address_state text,
|
||||
i18n_address_street_line1 text,
|
||||
i18n_address_street_line2 text,
|
||||
i18n_address_street_line3 text,
|
||||
i18n_address_zip text,
|
||||
ip_address_whitelist text[],
|
||||
last_certificate_update_time timestamptz,
|
||||
last_update_time timestamptz,
|
||||
localized_address_city text,
|
||||
localized_address_country_code text,
|
||||
localized_address_state text,
|
||||
localized_address_street_line1 text,
|
||||
localized_address_street_line2 text,
|
||||
localized_address_street_line3 text,
|
||||
localized_address_zip text,
|
||||
password_hash text,
|
||||
phone_number text,
|
||||
phone_passcode text,
|
||||
po_number text,
|
||||
rdap_base_urls text[],
|
||||
registrar_name text not null,
|
||||
registry_lock_allowed boolean not null,
|
||||
password_salt text,
|
||||
state text,
|
||||
type text not null,
|
||||
url text,
|
||||
whois_server text,
|
||||
primary key (client_id)
|
||||
);
|
||||
|
||||
create table "RegistryLock" (
|
||||
revision_id bigserial not null,
|
||||
domain_name text not null,
|
||||
@@ -130,6 +179,8 @@ create index IDX5mnf0wn20tno4b9do88j61klr on "Domain" (deletion_time);
|
||||
create index IDX1rcgkdd777bpvj0r94sltwd5y on "Domain" (fully_qualified_domain_name);
|
||||
create index IDXrwl38wwkli1j7gkvtywi9jokq on "Domain" (tld);
|
||||
create index premiumlist_name_idx on "PremiumList" (name);
|
||||
create index registrar_name_idx on "Registrar" (registrar_name);
|
||||
create index registrar_iana_identifier_idx on "Registrar" (iana_identifier);
|
||||
create index idx_registry_lock_verification_code on "RegistryLock" (verification_code);
|
||||
create index idx_registry_lock_registrar_id on "RegistryLock" (registrar_id);
|
||||
|
||||
|
||||
@@ -159,6 +159,59 @@ CREATE SEQUENCE public."PremiumList_revision_id_seq"
|
||||
ALTER SEQUENCE public."PremiumList_revision_id_seq" OWNED BY public."PremiumList".revision_id;
|
||||
|
||||
|
||||
--
|
||||
-- Name: Registrar; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE TABLE public."Registrar" (
|
||||
client_id text NOT NULL,
|
||||
allowed_tlds text[],
|
||||
billing_account_map public.hstore,
|
||||
billing_identifier bigint,
|
||||
block_premium_names boolean NOT NULL,
|
||||
client_certificate text,
|
||||
client_certificate_hash text,
|
||||
contacts_require_syncing boolean NOT NULL,
|
||||
creation_time timestamp with time zone,
|
||||
drive_folder_id text,
|
||||
email_address text,
|
||||
failover_client_certificate text,
|
||||
failover_client_certificate_hash text,
|
||||
fax_number text,
|
||||
iana_identifier bigint,
|
||||
icann_referral_email text,
|
||||
i18n_address_city text,
|
||||
i18n_address_country_code text,
|
||||
i18n_address_state text,
|
||||
i18n_address_street_line1 text,
|
||||
i18n_address_street_line2 text,
|
||||
i18n_address_street_line3 text,
|
||||
i18n_address_zip text,
|
||||
ip_address_whitelist text[],
|
||||
last_certificate_update_time timestamp with time zone,
|
||||
last_update_time timestamp with time zone,
|
||||
localized_address_city text,
|
||||
localized_address_country_code text,
|
||||
localized_address_state text,
|
||||
localized_address_street_line1 text,
|
||||
localized_address_street_line2 text,
|
||||
localized_address_street_line3 text,
|
||||
localized_address_zip text,
|
||||
password_hash text,
|
||||
phone_number text,
|
||||
phone_passcode text,
|
||||
po_number text,
|
||||
rdap_base_urls text[],
|
||||
registrar_name text NOT NULL,
|
||||
registry_lock_allowed boolean NOT NULL,
|
||||
password_salt text,
|
||||
state text,
|
||||
type text NOT NULL,
|
||||
url text,
|
||||
whois_server text
|
||||
);
|
||||
|
||||
|
||||
--
|
||||
-- Name: RegistryLock; Type: TABLE; Schema: public; Owner: -
|
||||
--
|
||||
@@ -317,6 +370,14 @@ ALTER TABLE ONLY public."PremiumList"
|
||||
ADD CONSTRAINT "PremiumList_pkey" PRIMARY KEY (revision_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: Registrar Registrar_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."Registrar"
|
||||
ADD CONSTRAINT "Registrar_pkey" PRIMARY KEY (client_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: RegistryLock RegistryLock_pkey; Type: CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
@@ -405,6 +466,20 @@ CREATE INDEX idxrwl38wwkli1j7gkvtywi9jokq ON public."Domain" USING btree (tld);
|
||||
CREATE INDEX premiumlist_name_idx ON public."PremiumList" USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- Name: registrar_iana_identifier_idx; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX registrar_iana_identifier_idx ON public."Registrar" USING btree (iana_identifier);
|
||||
|
||||
|
||||
--
|
||||
-- Name: registrar_name_idx; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
CREATE INDEX registrar_name_idx ON public."Registrar" USING btree (registrar_name);
|
||||
|
||||
|
||||
--
|
||||
-- Name: reservedlist_name_idx; Type: INDEX; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -12,16 +12,23 @@
|
||||
#
|
||||
# To trigger a build automatically, follow the instructions below and add a trigger:
|
||||
# https://cloud.google.com/cloud-build/docs/running-builds/automate-builds
|
||||
#
|
||||
# Note: to work around issue in Spinnaker's 'Deployment Manifest' stage,
|
||||
# variable references must avoid the ${var} format. Valid formats include
|
||||
# $var or ${"${var}"}. This file use the former. Since TAG_NAME and _ENV are
|
||||
# expanded in the copies sent to Spinnaker, we preserve the brackets around
|
||||
# them for safe pattern matching during release.
|
||||
# See https://github.com/spinnaker/spinnaker/issues/3028 for more information.
|
||||
steps:
|
||||
# Pull the credential for nomulus tool.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
args:
|
||||
- gsutil
|
||||
- cp
|
||||
- gs://${PROJECT_ID}-deploy/secrets/tool-credential.json.enc
|
||||
- gs://$PROJECT_ID-deploy/secrets/tool-credential.json.enc
|
||||
- .
|
||||
# Decrypt the credential.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
args:
|
||||
- -c
|
||||
@@ -31,7 +38,7 @@ steps:
|
||||
--ciphertext-file=- --plaintext-file=tool-credential.json \
|
||||
--location=global --keyring=nomulus-tool-keyring --key=nomulus-tool-key
|
||||
# Deploy the Spec11 pipeline to GCS.
|
||||
- name: 'gcr.io/${PROJECT_ID}/nomulus-tool:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/nomulus-tool:latest'
|
||||
args:
|
||||
- -e
|
||||
- ${_ENV}
|
||||
@@ -39,7 +46,7 @@ steps:
|
||||
- tool-credential.json
|
||||
- deploy_spec11_pipeline
|
||||
# Deploy the invoicing pipeline to GCS.
|
||||
- name: 'gcr.io/${PROJECT_ID}/nomulus-tool:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/nomulus-tool:latest'
|
||||
args:
|
||||
- -e
|
||||
- ${_ENV}
|
||||
@@ -49,18 +56,18 @@ steps:
|
||||
# Save the deployed tag for the current environment on GCS. Because of b/137891685
|
||||
# which causes the for-loop in the next step to fail, this may not be the last step.
|
||||
# TODO(weiminyu): do this in last step.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
echo ${TAG_NAME} | \
|
||||
gsutil cp - gs://${PROJECT_ID}-deployed-tags/nomulus.${_ENV}.tag
|
||||
gsutil cp - gs://$PROJECT_ID-deployed-tags/nomulus.${_ENV}.tag
|
||||
# Deploy the GAE config files.
|
||||
# First authorize the gcloud tool to use the credential json file, then
|
||||
# download and unzip the tarball that contains the relevant config files
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
args:
|
||||
- -c
|
||||
@@ -72,13 +79,13 @@ steps:
|
||||
else
|
||||
project_id="domain-registry-${_ENV}"
|
||||
fi
|
||||
gsutil cp gs://${PROJECT_ID}-deploy/${TAG_NAME}/${_ENV}.tar .
|
||||
gsutil cp gs://$PROJECT_ID-deploy/${TAG_NAME}/${_ENV}.tar .
|
||||
tar -xvf ${_ENV}.tar
|
||||
# Note that this currently does not work for google.com projects that
|
||||
# we use due to b/137891685. External projects are likely to work.
|
||||
for filename in cron dispatch dos index queue; do
|
||||
gcloud -q --project ${project_id} app deploy \
|
||||
default/WEB-INF/appengine-generated/${filename}.yaml
|
||||
gcloud -q --project $project_id app deploy \
|
||||
default/WEB-INF/appengine-generated/$filename.yaml
|
||||
done
|
||||
|
||||
timeout: 3600s
|
||||
|
||||
@@ -15,14 +15,22 @@
|
||||
#
|
||||
# Note that the release process hardens the tags and variables in this file:
|
||||
# - The 'latest' tag on docker images will be replaced by their image digests.
|
||||
# - The ${TAG_NAME} pattern will be replaced by the acutal release tag.
|
||||
# - The ${TAG_NAME} pattern will be replaced by the actual release tag.
|
||||
# - The ${_ENV} pattern will be replaced by the actual environment name.
|
||||
# Please refer to ./cloudbuild-release.yaml for more details.
|
||||
|
||||
# Note 2: to work around issue in Spinnaker's 'Deployment Manifest' stage,
|
||||
# variable references must avoid the ${var} format. Valid formats include
|
||||
# $var or ${"${var}"}. This file use the former. Since TAG_NAME and _ENV are
|
||||
# expanded in the copies sent to Spinnaker, we preserve the brackets around
|
||||
# them for safe pattern matching during release.
|
||||
# See https://github.com/spinnaker/spinnaker/issues/3028 for more information.
|
||||
steps:
|
||||
# Download and decrypt the nomulus tool credential, which has the privilege to
|
||||
# start Cloud SQL proxy to all environments.
|
||||
# Also download and decrypt the admin_credential file, which has the cloud
|
||||
# instance name and database login name and password.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
volumes:
|
||||
- name: 'secrets'
|
||||
path: '/secrets'
|
||||
@@ -31,13 +39,13 @@ steps:
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
gsutil cp gs://${PROJECT_ID}-deploy/secrets/tool-credential.json.enc - \
|
||||
gsutil cp gs://$PROJECT_ID-deploy/secrets/tool-credential.json.enc - \
|
||||
| base64 -d \
|
||||
| gcloud kms decrypt \
|
||||
--ciphertext-file=- \
|
||||
--plaintext-file=/secrets/cloud_sql_credential.json \
|
||||
--location=global --keyring=nomulus-tool-keyring --key=nomulus-tool-key
|
||||
gsutil cp gs://${PROJECT_ID}-deploy/cloudsql-credentials/${_ENV}/admin_credential.enc - \
|
||||
gsutil cp gs://$PROJECT_ID-deploy/cloudsql-credentials/${_ENV}/admin_credential.enc - \
|
||||
| base64 -d \
|
||||
| gcloud kms decrypt \
|
||||
--ciphertext-file=- \
|
||||
@@ -45,7 +53,7 @@ steps:
|
||||
--location global --keyring=nomulus-tool-keyring \
|
||||
--key=nomulus-tool-key
|
||||
# Download the schema jar to be deployed.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
volumes:
|
||||
- name: 'flyway'
|
||||
path: '/flyway/jars'
|
||||
@@ -54,10 +62,10 @@ steps:
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
gsutil cp gs://domain-registry-dev-deploy/${TAG_NAME}/schema.jar \
|
||||
gsutil cp gs://$PROJECT_ID-deploy/${TAG_NAME}/schema.jar \
|
||||
/flyway/jars
|
||||
# Deploy SQL schema
|
||||
- name: 'gcr.io/${PROJECT_ID}/schema_deployer:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/schema_deployer:latest'
|
||||
volumes:
|
||||
- name: 'secrets'
|
||||
path: '/secrets'
|
||||
@@ -68,14 +76,14 @@ steps:
|
||||
# location. Do not use the 'artifacts' section for this since it will
|
||||
# upload an extra metadata file every time and pollute the folder.
|
||||
# TODO(weiminyu): modify this step so that TAG_NAME may be 'live'.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
entrypoint: /bin/bash
|
||||
args:
|
||||
- -c
|
||||
- |
|
||||
set -e
|
||||
echo ${TAG_NAME} | \
|
||||
gsutil cp - gs://${PROJECT_ID}-deployed-tags/sql.${_ENV}.tag\
|
||||
gsutil cp - gs://$PROJECT_ID-deployed-tags/sql.${_ENV}.tag\
|
||||
timeout: 3600s
|
||||
options:
|
||||
machineType: 'N1_HIGHCPU_8'
|
||||
|
||||
@@ -9,16 +9,23 @@
|
||||
#
|
||||
# To trigger a build automatically, follow the instructions below and add a trigger:
|
||||
# https://cloud.google.com/cloud-build/docs/running-builds/automate-builds
|
||||
#
|
||||
# Note: to work around issue in Spinnaker's 'Deployment Manifest' stage,
|
||||
# variable references must avoid the ${var} format. Valid formats include
|
||||
# $var or ${"${var}"}. This file use the former. Since TAG_NAME is
|
||||
# expanded in the copies sent to Spinnaker, we preserve the brackets around
|
||||
# them for safe pattern matching during release.
|
||||
# See https://github.com/spinnaker/spinnaker/issues/3028 for more information.
|
||||
steps:
|
||||
# Rsync the folder.
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
args:
|
||||
- gsutil
|
||||
- -m
|
||||
- rsync
|
||||
- -d
|
||||
- gs://${PROJECT_ID}-deploy/${TAG_NAME}
|
||||
- gs://${PROJECT_ID}-deploy/live
|
||||
- gs://$PROJECT_ID-deploy/${TAG_NAME}
|
||||
- gs://$PROJECT_ID-deploy/live
|
||||
timeout: 3600s
|
||||
options:
|
||||
machineType: 'N1_HIGHCPU_8'
|
||||
|
||||
@@ -11,15 +11,22 @@
|
||||
#
|
||||
# To trigger a build automatically, follow the instructions below and add a trigger:
|
||||
# https://cloud.google.com/cloud-build/docs/running-builds/automate-builds
|
||||
#
|
||||
# Note: to work around issue in Spinnaker's 'Deployment Manifest' stage,
|
||||
# variable references must avoid the ${var} format. Valid formats include
|
||||
# $var or ${"${var}"}. This file use the former. Since TAG_NAME is
|
||||
# expanded in the copies sent to Spinnaker, we preserve the brackets around
|
||||
# them for safe pattern matching during release.
|
||||
# See https://github.com/spinnaker/spinnaker/issues/3028 for more information.
|
||||
steps:
|
||||
- name: 'gcr.io/${PROJECT_ID}/builder:latest'
|
||||
- name: 'gcr.io/$PROJECT_ID/builder:latest'
|
||||
args:
|
||||
- gcloud
|
||||
- container
|
||||
- images
|
||||
- add-tag
|
||||
- gcr.io/${PROJECT_ID}/${_IMAGE}:${TAG_NAME}
|
||||
- gcr.io/${PROJECT_ID}/${_IMAGE}:live
|
||||
- gcr.io/$PROJECT_ID/${_IMAGE}:${TAG_NAME}
|
||||
- gcr.io/$PROJECT_ID/${_IMAGE}:live
|
||||
timeout: 3600s
|
||||
options:
|
||||
machineType: 'N1_HIGHCPU_8'
|
||||
|
||||
Reference in New Issue
Block a user