Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fa9400ebc5 | |||
| 519a85af85 | |||
| b2df127dc4 | |||
| b21042bda9 | |||
| 36378f6b10 | |||
| d01f1f7604 | |||
| e9610636e4 |
@@ -197,7 +197,8 @@ dependencies {
|
||||
compile deps['com.google.appengine:appengine-remote-api']
|
||||
compile deps['com.google.auth:google-auth-library-credentials']
|
||||
compile deps['com.google.auth:google-auth-library-oauth2-http']
|
||||
compile deps['com.google.cloud.sql:postgres-socket-factory']
|
||||
compile deps['com.google.cloud.sql:jdbc-socket-factory-core']
|
||||
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
|
||||
compile deps['com.google.code.gson:gson']
|
||||
compile deps['com.google.auto.value:auto-value-annotations']
|
||||
compile deps['com.google.code.findbugs:jsr305']
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -75,7 +75,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -76,7 +76,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -76,7 +76,6 @@ com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
|
||||
@@ -44,7 +44,9 @@ import google.registry.model.Jsonifiable;
|
||||
import google.registry.model.annotations.ReportedOn;
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
@@ -112,6 +114,9 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
||||
@Column(nullable = false)
|
||||
String emailAddress;
|
||||
|
||||
/** External email address of this contact used for registry lock confirmations. */
|
||||
String registryLockEmailAddress;
|
||||
|
||||
/** The voice number of the contact. */
|
||||
String phoneNumber;
|
||||
|
||||
@@ -212,6 +217,10 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
||||
return emailAddress;
|
||||
}
|
||||
|
||||
public Optional<String> getRegistryLockEmailAddress() {
|
||||
return Optional.ofNullable(registryLockEmailAddress);
|
||||
}
|
||||
|
||||
public String getPhoneNumber() {
|
||||
return phoneNumber;
|
||||
}
|
||||
@@ -318,6 +327,7 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
||||
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(",")))
|
||||
@@ -352,6 +362,14 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
||||
public RegistrarContact build() {
|
||||
checkNotNull(getInstance().parent, "Registrar parent 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());
|
||||
}
|
||||
|
||||
@@ -365,6 +383,11 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRegistryLockEmailAddress(@Nullable String registryLockEmailAddress) {
|
||||
getInstance().registryLockEmailAddress = registryLockEmailAddress;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setPhoneNumber(String phoneNumber) {
|
||||
getInstance().phoneNumber = phoneNumber;
|
||||
return this;
|
||||
|
||||
@@ -52,8 +52,10 @@ public final class RegistryLockDao {
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT lock FROM RegistryLock lock WHERE lock.registrarId = :registrarId"
|
||||
+ " AND lock.unlockCompletionTimestamp IS NULL",
|
||||
"SELECT lock FROM RegistryLock lock"
|
||||
+ " WHERE lock.registrarId = :registrarId"
|
||||
+ " AND lock.unlockCompletionTimestamp IS NULL"
|
||||
+ " ORDER BY lock.domainName ASC",
|
||||
RegistryLock.class)
|
||||
.setParameter("registrarId", registrarId)
|
||||
.getResultList());
|
||||
|
||||
@@ -78,6 +78,18 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
/** When the lock can be considered implicitly released. */
|
||||
DateTime expirationTime;
|
||||
|
||||
public String getRequestLogId() {
|
||||
return requestLogId;
|
||||
}
|
||||
|
||||
public DateTime getExpirationTime() {
|
||||
return expirationTime;
|
||||
}
|
||||
|
||||
public DateTime getAcquiredTime() {
|
||||
return acquiredTime;
|
||||
}
|
||||
|
||||
/** When was the lock acquired. Used for logging. */
|
||||
DateTime acquiredTime;
|
||||
|
||||
@@ -89,10 +101,10 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
String tld;
|
||||
|
||||
/**
|
||||
* Create a new {@link Lock} for the given resource name in the specified tld (which can be
|
||||
* null for cross-tld locks).
|
||||
* Create a new {@link Lock} for the given resource name in the specified tld (which can be null
|
||||
* for cross-tld locks).
|
||||
*/
|
||||
private static Lock create(
|
||||
public static Lock create(
|
||||
String resourceName,
|
||||
@Nullable String tld,
|
||||
String requestLogId,
|
||||
@@ -185,6 +197,18 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
|
||||
// Checking if an unexpired lock still exists - if so, the lock can't be acquired.
|
||||
Lock lock = ofy().load().type(Lock.class).id(lockId).now();
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional =
|
||||
LockDao.load(resourceName, tld);
|
||||
LockDao.compare(Optional.ofNullable(lock), cloudSqlLockOptional);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Issue loading and comparing lock from Cloud SQL");
|
||||
}
|
||||
if (lock != null) {
|
||||
logger.atInfo().log(
|
||||
"Loaded existing lock: %s for request: %s", lock.lockId, lock.requestLogId);
|
||||
@@ -221,12 +245,7 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
requestStatusChecker.getLogId(),
|
||||
now,
|
||||
leaseLength);
|
||||
// cloudSqlLock should not already exist in Cloud SQL, but call delete
|
||||
// just in case
|
||||
// TODO: Remove this delete once dual read is added
|
||||
LockDao.delete(
|
||||
resourceName, Optional.ofNullable(tld).orElse("GLOBAL"));
|
||||
LockDao.saveNew(cloudSqlLock);
|
||||
LockDao.save(cloudSqlLock);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
@@ -251,6 +270,18 @@ public class Lock extends ImmutableObject implements Serializable {
|
||||
// this can happen if release() is called around the expiration time and the lock
|
||||
// expires underneath us.
|
||||
Lock loadedLock = ofy().load().type(Lock.class).id(lockId).now();
|
||||
try {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
Optional<google.registry.schema.server.Lock> cloudSqlLockOptional =
|
||||
LockDao.load(resourceName, tld);
|
||||
LockDao.compare(Optional.ofNullable(loadedLock), cloudSqlLockOptional);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
logger.atSevere().withCause(e).log(
|
||||
"Issue loading and comparing lock from Cloud SQL");
|
||||
}
|
||||
if (Lock.this.equals(loadedLock)) {
|
||||
// Use noBackupOfy() so that we don't create a commit log entry for deleting the
|
||||
// lock.
|
||||
|
||||
@@ -19,7 +19,6 @@ import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.persistence.PersistenceModule.AppEngineJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.util.UtilsModule;
|
||||
import javax.inject.Singleton;
|
||||
@@ -39,7 +38,4 @@ public interface PersistenceComponent {
|
||||
|
||||
@AppEngineJpaTm
|
||||
JpaTransactionManager appEngineJpaTransactionManager();
|
||||
|
||||
@NomulusToolJpaTm
|
||||
JpaTransactionManager nomulusToolJpaTransactionManager();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static google.registry.config.RegistryConfig.getHibernateHikariMaximumPoo
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariMinimumIdle;
|
||||
import static google.registry.config.RegistryConfig.getHibernateLogSqlQueries;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -29,8 +30,10 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.kms.KmsKeyring;
|
||||
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
||||
import google.registry.tools.AuthModule.CloudSqlClientCredential;
|
||||
import google.registry.util.Clock;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.util.HashMap;
|
||||
@@ -118,7 +121,9 @@ public class PersistenceModule {
|
||||
@Config("toolsCloudSqlUsername") String username,
|
||||
KmsKeyring kmsKeyring,
|
||||
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
|
||||
@CloudSqlClientCredential Credential credential,
|
||||
Clock clock) {
|
||||
CloudSqlCredentialSupplier.setupCredentialSupplier(credential);
|
||||
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
|
||||
overrides.put(Environment.USER, username);
|
||||
overrides.put(Environment.PASS, kmsKeyring.getToolsCloudSqlPassword());
|
||||
@@ -158,7 +163,7 @@ public class PersistenceModule {
|
||||
/** Dagger qualifier for {@link JpaTransactionManager} used for Nomulus tool. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
@interface NomulusToolJpaTm {}
|
||||
public @interface NomulusToolJpaTm {}
|
||||
|
||||
/** Dagger qualifier for the partial Cloud SQL configs. */
|
||||
@Qualifier
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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.converter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** JPA converter to for storing/retrieving {@link org.joda.time.DateTime} objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class DurationConverter implements AttributeConverter<Duration, Long> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Long convertToDatabaseColumn(@Nullable Duration duration) {
|
||||
return duration == null ? null : duration.getMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Duration convertToEntityAttribute(@Nullable Long dbData) {
|
||||
return dbData == null ? null : new Duration(dbData);
|
||||
}
|
||||
}
|
||||
@@ -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.transaction;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.cloud.sql.CredentialFactory;
|
||||
|
||||
/** Supplier class to provide {@link Credential} for Cloud SQL library. */
|
||||
public class CloudSqlCredentialSupplier implements CredentialFactory {
|
||||
private static Credential credential;
|
||||
|
||||
/** Initialize the supplier with given credential json and scopes. */
|
||||
public static void setupCredentialSupplier(Credential credential) {
|
||||
System.setProperty(
|
||||
CredentialFactory.CREDENTIAL_FACTORY_PROPERTY, CloudSqlCredentialSupplier.class.getName());
|
||||
CloudSqlCredentialSupplier.credential = credential;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential create() {
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,9 @@ package google.registry.persistence.transaction;
|
||||
|
||||
import com.google.appengine.api.utils.SystemProperty;
|
||||
import com.google.appengine.api.utils.SystemProperty.Environment.Value;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Suppliers;
|
||||
import google.registry.model.ofy.DatastoreTransactionManager;
|
||||
import google.registry.persistence.DaggerPersistenceComponent;
|
||||
import google.registry.tools.RegistryToolEnvironment;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -38,11 +36,10 @@ public class TransactionManagerFactory {
|
||||
private TransactionManagerFactory() {}
|
||||
|
||||
private static JpaTransactionManager createJpaTransactionManager() {
|
||||
// If we are running a nomulus command, jpaTm will be injected in RegistryCli.java
|
||||
// by calling setJpaTm().
|
||||
if (isInAppEngine()) {
|
||||
return DaggerPersistenceComponent.create().appEngineJpaTransactionManager();
|
||||
} else if (RegistryToolEnvironment.isInRegistryTool()
|
||||
&& RegistryToolEnvironment.isJpaTmEnabled()) {
|
||||
return DaggerPersistenceComponent.create().nomulusToolJpaTransactionManager();
|
||||
} else {
|
||||
return DummyJpaTransactionManager.create();
|
||||
}
|
||||
@@ -78,8 +75,8 @@ public class TransactionManagerFactory {
|
||||
return jpaTm.get();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void setJpaTmForTesting(JpaTransactionManager newJpaTm) {
|
||||
/** Sets the return of {@link #jpaTm()} to the given instance of {@link JpaTransactionManager}. */
|
||||
public static void setJpaTm(JpaTransactionManager newJpaTm) {
|
||||
jpaTm = Suppliers.ofInstance(newJpaTm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,6 +26,7 @@ import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
@@ -37,6 +38,7 @@ import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Represents a registry lock/unlock object, meaning that the domain is locked on the registry
|
||||
@@ -131,6 +133,9 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
@JoinColumn(name = "relockRevisionId", referencedColumnName = "revisionId")
|
||||
private RegistryLock relock;
|
||||
|
||||
/** The duration after which we will re-lock this domain after it is unlocked. */
|
||||
private Duration relockDuration;
|
||||
|
||||
/** Time that this entity was last updated. */
|
||||
private UpdateAutoTimestamp lastUpdateTimestamp;
|
||||
|
||||
@@ -197,6 +202,11 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
return relock;
|
||||
}
|
||||
|
||||
/** The duration after which we will re-lock this domain after it is unlocked. */
|
||||
public Optional<Duration> getRelockDuration() {
|
||||
return Optional.ofNullable(relockDuration);
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return lockCompletionTimestamp != null && unlockCompletionTimestamp == null;
|
||||
}
|
||||
@@ -289,5 +299,10 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
getInstance().relock = relock;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRelockDuration(@Nullable Duration relockDuration) {
|
||||
getInstance().relockDuration = relockDuration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,18 +18,22 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
import static google.registry.schema.server.Lock.GLOBAL;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import google.registry.schema.server.Lock.LockId;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.util.Optional;
|
||||
|
||||
/** Data access object class for {@link Lock}. */
|
||||
public class LockDao {
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
/** Saves the {@link Lock} object to Cloud SQL. */
|
||||
public static void saveNew(Lock lock) {
|
||||
public static void save(Lock lock) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
jpaTm().getEntityManager().persist(lock);
|
||||
jpaTm().getEntityManager().merge(lock);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,4 +80,57 @@ public class LockDao {
|
||||
public static void delete(String resourceName) {
|
||||
delete(resourceName, GLOBAL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares a {@link google.registry.model.server.Lock} object with a {@link Lock} object, logging
|
||||
* a warning if there are any differences.
|
||||
*/
|
||||
public static void compare(
|
||||
Optional<google.registry.model.server.Lock> datastoreLockOptional,
|
||||
Optional<Lock> cloudSqlLockOptional) {
|
||||
if (!datastoreLockOptional.isPresent()) {
|
||||
cloudSqlLockOptional.ifPresent(
|
||||
value ->
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Cloud SQL lock for %s with tld %s should be null",
|
||||
value.resourceName, value.tld)));
|
||||
return;
|
||||
}
|
||||
google.registry.schema.server.Lock cloudSqlLock;
|
||||
google.registry.model.server.Lock datastoreLock = datastoreLockOptional.get();
|
||||
if (cloudSqlLockOptional.isPresent()) {
|
||||
cloudSqlLock = cloudSqlLockOptional.get();
|
||||
if (!datastoreLock.getRequestLogId().equals(cloudSqlLock.requestLogId)) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Datastore lock requestLogId of %s does not equal Cloud SQL lock requestLogId of"
|
||||
+ " %s",
|
||||
datastoreLock.getRequestLogId(), cloudSqlLock.requestLogId));
|
||||
}
|
||||
if (!datastoreLock
|
||||
.getAcquiredTime()
|
||||
.equals(DateTimeUtils.toJodaDateTime(cloudSqlLock.acquiredTime))) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Datastore lock acquiredTime of %s does not equal Cloud SQL lock acquiredTime of"
|
||||
+ " %s",
|
||||
datastoreLock.getAcquiredTime(),
|
||||
DateTimeUtils.toJodaDateTime(cloudSqlLock.acquiredTime)));
|
||||
}
|
||||
if (!datastoreLock
|
||||
.getExpirationTime()
|
||||
.equals(DateTimeUtils.toJodaDateTime(cloudSqlLock.expirationTime))) {
|
||||
logger.atWarning().log(
|
||||
String.format(
|
||||
"Datastore lock expirationTime of %s does not equal Cloud SQL lock expirationTime"
|
||||
+ " of %s",
|
||||
datastoreLock.getExpirationTime(),
|
||||
DateTimeUtils.toJodaDateTime(cloudSqlLock.expirationTime)));
|
||||
}
|
||||
} else {
|
||||
logger.atWarning().log(
|
||||
String.format("Datastore lock: %s was not found in Cloud SQL", datastoreLock));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.Details;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.util.store.AbstractDataStoreFactory;
|
||||
@@ -42,6 +43,7 @@ import google.registry.util.GoogleCredentialsBundle;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -92,6 +94,26 @@ public class AuthModule {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/138195359): Deprecate this credential once Cloud SQL socket library uses the new auth
|
||||
// library.
|
||||
@Provides
|
||||
@CloudSqlClientCredential
|
||||
public static Credential providesLocalCredentialForCloudSqlClient(
|
||||
@LocalCredentialJson String credentialJson,
|
||||
@Config("localCredentialOauthScopes") ImmutableList<String> credentialScopes) {
|
||||
try {
|
||||
GoogleCredential credential =
|
||||
GoogleCredential.fromStream(new ByteArrayInputStream(credentialJson.getBytes(UTF_8)));
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(credentialScopes);
|
||||
}
|
||||
return credential;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(
|
||||
"Error occurred while creating a GoogleCredential for Cloud SQL client", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
public static GoogleAuthorizationCodeFlow provideAuthorizationCodeFlow(
|
||||
JsonFactory jsonFactory,
|
||||
@@ -184,6 +206,11 @@ public class AuthModule {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface StoredCredential {}
|
||||
|
||||
/** Dagger qualifier for {@link Credential} used by the Cloud SQL client in the nomulus tool. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
public @interface CloudSqlClientCredential {}
|
||||
|
||||
/** Dagger qualifier for the credential qualifier consisting of client and scopes. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
|
||||
@@ -78,11 +78,15 @@ final class RegistrarContactCommand extends MutatingCommand {
|
||||
private List<String> contactTypeNames;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--email",
|
||||
description = "Contact email address.")
|
||||
@Parameter(names = "--email", description = "Contact email address.")
|
||||
String email;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--registry_lock_email",
|
||||
description = "Email address used for registry lock confirmation emails")
|
||||
String registryLockEmail;
|
||||
|
||||
@Nullable
|
||||
@Parameter(
|
||||
names = "--phone",
|
||||
@@ -247,6 +251,9 @@ final class RegistrarContactCommand extends MutatingCommand {
|
||||
builder.setParent(registrar);
|
||||
builder.setName(name);
|
||||
builder.setEmailAddress(email);
|
||||
if (!isNullOrEmpty(registryLockEmail)) {
|
||||
builder.setRegistryLockEmailAddress(registryLockEmail);
|
||||
}
|
||||
if (phone != null) {
|
||||
builder.setPhoneNumber(phone.orElse(null));
|
||||
}
|
||||
@@ -277,14 +284,14 @@ final class RegistrarContactCommand extends MutatingCommand {
|
||||
|
||||
private RegistrarContact updateContact(RegistrarContact contact, Registrar registrar) {
|
||||
checkNotNull(registrar);
|
||||
checkNotNull(email, "--email is required when --mode=UPDATE");
|
||||
RegistrarContact.Builder builder = contact.asBuilder();
|
||||
builder.setParent(registrar);
|
||||
checkArgument(!isNullOrEmpty(email), "--email is required when --mode=UPDATE");
|
||||
RegistrarContact.Builder builder =
|
||||
contact.asBuilder().setEmailAddress(email).setParent(registrar);
|
||||
if (!isNullOrEmpty(name)) {
|
||||
builder.setName(name);
|
||||
}
|
||||
if (!isNullOrEmpty(email)) {
|
||||
builder.setEmailAddress(email);
|
||||
if (!isNullOrEmpty(registryLockEmail)) {
|
||||
builder.setRegistryLockEmailAddress(registryLockEmail);
|
||||
}
|
||||
if (phone != null) {
|
||||
builder.setPhoneNumber(phone.orElse(null));
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
import google.registry.tools.AuthModule.LoginRequiredException;
|
||||
import google.registry.tools.params.ParameterFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -237,7 +238,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
// Enable Cloud SQL for command that needs remote API as they will very likely use
|
||||
// Cloud SQL after the database migration. Note that the DB password is stored in Datastore
|
||||
// and it is already initialized above.
|
||||
RegistryToolEnvironment.enableJpaTm();
|
||||
TransactionManagerFactory.setJpaTm(component.nomulusToolJpaTransactionManager());
|
||||
}
|
||||
|
||||
command.run();
|
||||
|
||||
@@ -27,6 +27,9 @@ import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.rde.RdeModule;
|
||||
import google.registry.request.Modules.DatastoreServiceModule;
|
||||
import google.registry.request.Modules.Jackson2Module;
|
||||
@@ -63,6 +66,7 @@ import javax.inject.Singleton;
|
||||
KeyringModule.class,
|
||||
KmsModule.class,
|
||||
LocalCredentialModule.class,
|
||||
PersistenceModule.class,
|
||||
RdeModule.class,
|
||||
RequestFactoryModule.class,
|
||||
URLFetchServiceModule.class,
|
||||
@@ -70,7 +74,7 @@ import javax.inject.Singleton;
|
||||
UserServiceModule.class,
|
||||
UtilsModule.class,
|
||||
VoidDnsWriterModule.class,
|
||||
WhoisModule.class,
|
||||
WhoisModule.class
|
||||
})
|
||||
interface RegistryToolComponent {
|
||||
void inject(AckPollMessagesCommand command);
|
||||
@@ -117,6 +121,9 @@ interface RegistryToolComponent {
|
||||
@LocalCredentialJson
|
||||
String googleCredentialJson();
|
||||
|
||||
@NomulusToolJpaTm
|
||||
JpaTransactionManager nomulusToolJpaTransactionManager();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.config.SystemPropertySetter;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
|
||||
/** Enum of production environments, used for the {@code --environment} flag. */
|
||||
public enum RegistryToolEnvironment {
|
||||
@@ -40,7 +39,6 @@ public enum RegistryToolEnvironment {
|
||||
|
||||
private static final ImmutableList<String> FLAGS = ImmutableList.of("-e", "--environment");
|
||||
private static RegistryToolEnvironment instance;
|
||||
private static boolean isJpaTmEnabled = false;
|
||||
private final RegistryEnvironment actualEnvironment;
|
||||
private final ImmutableMap<String, String> extraProperties;
|
||||
|
||||
@@ -100,26 +98,6 @@ public enum RegistryToolEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the RegistryToolEnvironment is set up. */
|
||||
public static boolean isInRegistryTool() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to indicate that the running command needs JpaTransactionManager to be enabled.
|
||||
*/
|
||||
public static void enableJpaTm() {
|
||||
isJpaTmEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the JpaTransactionManager is enabled. Note that JpaTm is actually enabled in
|
||||
* {@link TransactionManagerFactory} by reading this flag.
|
||||
*/
|
||||
public static boolean isJpaTmEnabled() {
|
||||
return isJpaTmEnabled;
|
||||
}
|
||||
|
||||
/** Extracts value from command-line arguments associated with any {@code flags}. */
|
||||
private static String getFlagValue(String[] args, Iterable<String> flags) {
|
||||
for (String flag : flags) {
|
||||
|
||||
@@ -184,6 +184,11 @@ public final class RegistrarFormFields {
|
||||
.required()
|
||||
.build();
|
||||
|
||||
public static final FormField<String, String> REGISTRY_LOCK_EMAIL_ADDRESS_FIELD =
|
||||
FormFields.EMAIL
|
||||
.asBuilderNamed("registryLockEmailAddress")
|
||||
.build();
|
||||
|
||||
public static final FormField<Boolean, Boolean> CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD =
|
||||
FormField.named("visibleInWhoisAsAdmin", Boolean.class)
|
||||
.build();
|
||||
@@ -377,6 +382,8 @@ public final class RegistrarFormFields {
|
||||
RegistrarContact.Builder builder, Map<String, ?> args) {
|
||||
builder.setName(CONTACT_NAME_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setEmailAddress(CONTACT_EMAIL_ADDRESS_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setRegistryLockEmailAddress(
|
||||
REGISTRY_LOCK_EMAIL_ADDRESS_FIELD.extractUntyped(args).orElse(null));
|
||||
builder.setVisibleInWhoisAsAdmin(
|
||||
CONTACT_VISIBLE_IN_WHOIS_AS_ADMIN_FIELD.extractUntyped(args).orElse(false));
|
||||
builder.setVisibleInWhoisAsTech(
|
||||
|
||||
@@ -157,9 +157,11 @@ public final class RegistryLockGetAction implements JsonGetAction {
|
||||
Optional<RegistrarContact> contactOptional = getContactMatchingLogin(user, registrar);
|
||||
boolean isRegistryLockAllowed =
|
||||
isAdmin || contactOptional.map(RegistrarContact::isRegistryLockAllowed).orElse(false);
|
||||
// Use the contact email if it's present, else use the login email
|
||||
// Use the contact's registry lock email if it's present, else use the login email (for admins)
|
||||
String relevantEmail =
|
||||
contactOptional.map(RegistrarContact::getEmailAddress).orElse(user.getEmail());
|
||||
contactOptional
|
||||
.map(contact -> contact.getRegistryLockEmailAddress().get())
|
||||
.orElse(user.getEmail());
|
||||
return ImmutableMap.of(
|
||||
LOCK_ENABLED_FOR_CONTACT_PARAM,
|
||||
isRegistryLockAllowed,
|
||||
|
||||
@@ -202,7 +202,14 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
checkArgument(
|
||||
registrarContact.verifyRegistryLockPassword(postInput.password),
|
||||
"Incorrect registry lock password for contact");
|
||||
return registrarContact.getEmailAddress();
|
||||
return registrarContact
|
||||
.getRegistryLockEmailAddress()
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalStateException(
|
||||
String.format(
|
||||
"Contact %s had no registry lock email address",
|
||||
registrarContact.getEmailAddress())));
|
||||
}
|
||||
|
||||
/** Value class that represents the expected input body from the UI request. */
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<class>google.registry.persistence.converter.CreateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyUnitConverter</class>
|
||||
<class>google.registry.persistence.converter.DateTimeConverter</class>
|
||||
<class>google.registry.persistence.converter.DurationConverter</class>
|
||||
<class>google.registry.persistence.converter.RegistrarPocSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StatusValueSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StringListConverter</class>
|
||||
|
||||
@@ -30,6 +30,7 @@ import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -88,12 +89,14 @@ public final class RegistryLockDaoTest {
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setRelockDuration(Duration.standardHours(6))
|
||||
.build());
|
||||
RegistryLock fromDatabase = getRegistryLockByVerificationCode(lock.getVerificationCode()).get();
|
||||
assertThat(fromDatabase.getUnlockRequestTimestamp()).isEqualTo(Optional.of(fakeClock.nowUtc()));
|
||||
assertThat(fromDatabase.getUnlockCompletionTimestamp())
|
||||
.isEqualTo(Optional.of(fakeClock.nowUtc()));
|
||||
assertThat(fromDatabase.isLocked()).isFalse();
|
||||
assertThat(fromDatabase.getRelockDuration().get()).isEqualTo(Duration.standardHours(6));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
// 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.converter;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// 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.converter;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import java.math.BigInteger;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link DurationConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DurationConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
private final DurationConverter converter = new DurationConverter();
|
||||
|
||||
@Test
|
||||
public void testNulls() {
|
||||
assertThat(converter.convertToDatabaseColumn(null)).isNull();
|
||||
assertThat(converter.convertToEntityAttribute(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundTrip() {
|
||||
TestEntity entity = new TestEntity(Duration.standardDays(6));
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"SELECT duration FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList()))
|
||||
.containsExactly(BigInteger.valueOf(Duration.standardDays(6).getMillis()));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.duration).isEqualTo(Duration.standardDays(6));
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
public static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
Duration duration;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
TestEntity(Duration duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,12 +133,12 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
|
||||
extraEntityClasses);
|
||||
JpaTransactionManagerImpl txnManager = new JpaTransactionManagerImpl(emf, clock);
|
||||
cachedTm = TransactionManagerFactory.jpaTm();
|
||||
TransactionManagerFactory.setJpaTmForTesting(txnManager);
|
||||
TransactionManagerFactory.setJpaTm(txnManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after() {
|
||||
TransactionManagerFactory.setJpaTmForTesting(cachedTm);
|
||||
TransactionManagerFactory.setJpaTm(cachedTm);
|
||||
if (emf != null) {
|
||||
emf.close();
|
||||
emf = null;
|
||||
|
||||
@@ -15,13 +15,15 @@
|
||||
package google.registry.schema.server;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||
|
||||
import com.google.common.testing.TestLogHandler;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import javax.persistence.RollbackException;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@@ -33,6 +35,8 @@ import org.junit.runners.JUnit4;
|
||||
public class LockDaoTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
private final TestLogHandler logHandler = new TestLogHandler();
|
||||
private final Logger loggerToIntercept = Logger.getLogger(LockDao.class.getCanonicalName());
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
@@ -42,29 +46,28 @@ public class LockDaoTest {
|
||||
public void save_worksSuccessfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save_failsWhenLockAlreadyExists() {
|
||||
public void save_succeedsWhenLockAlreadyExists() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Lock lock2 =
|
||||
Lock.create("testResource", "tld", "testLogId2", fakeClock.nowUtc(), Duration.millis(4));
|
||||
RollbackException thrown = assertThrows(RollbackException.class, () -> LockDao.saveNew(lock2));
|
||||
assertThat(thrown.getCause().getCause().getCause().getMessage())
|
||||
.contains("duplicate key value violates unique constraint");
|
||||
LockDao.save(lock2);
|
||||
assertThat(LockDao.load("testResource", "tld").get().requestLogId).isEqualTo("testLogId2");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void save_worksSuccesfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
@@ -74,7 +77,7 @@ public class LockDaoTest {
|
||||
public void load_worksSuccessfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
@@ -84,7 +87,7 @@ public class LockDaoTest {
|
||||
public void load_worksSuccessfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
|
||||
@@ -100,7 +103,7 @@ public class LockDaoTest {
|
||||
public void delete_worksSuccesfully() {
|
||||
Lock lock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
LockDao.delete("testResource", "tld");
|
||||
@@ -112,7 +115,7 @@ public class LockDaoTest {
|
||||
public void delete_worksSuccessfullyGlobalLock() {
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.saveNew(lock);
|
||||
LockDao.save(lock);
|
||||
Optional<Lock> returnedLock = LockDao.load("testResource");
|
||||
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
|
||||
LockDao.delete("testResource");
|
||||
@@ -124,4 +127,63 @@ public class LockDaoTest {
|
||||
public void delete_succeedsLockDoesntExist() {
|
||||
LockDao.delete("testResource");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_logsWarningWhenCloudSqlLockMissing() {
|
||||
loggerToIntercept.addHandler(logHandler);
|
||||
google.registry.model.server.Lock datastoreLock =
|
||||
google.registry.model.server.Lock.create(
|
||||
"resourceName", "tld", "id", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.compare(Optional.of(datastoreLock), Optional.empty());
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.WARNING,
|
||||
String.format("Datastore lock: %s was not found in Cloud SQL", datastoreLock));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_logsWarningWhenCloudSqlLockExistsWhenItShouldNot() {
|
||||
loggerToIntercept.addHandler(logHandler);
|
||||
Lock lock =
|
||||
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
LockDao.compare(Optional.ofNullable(null), Optional.of(lock));
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.WARNING,
|
||||
String.format("Cloud SQL lock for testResource with tld GLOBAL should be null"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void compare_logsWarningWhenLocksDontMatch() {
|
||||
loggerToIntercept.addHandler(logHandler);
|
||||
Lock cloudSqlLock =
|
||||
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
|
||||
google.registry.model.server.Lock datastoreLock =
|
||||
google.registry.model.server.Lock.create(
|
||||
"testResource", "tld", "wrong", fakeClock.nowUtc().minusDays(1), Duration.millis(3));
|
||||
LockDao.compare(Optional.of(datastoreLock), Optional.of(cloudSqlLock));
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.WARNING,
|
||||
String.format(
|
||||
"Datastore lock requestLogId of wrong does not equal Cloud SQL lock requestLogId"
|
||||
+ " of testLogId"));
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.WARNING,
|
||||
String.format(
|
||||
"Datastore lock acquiredTime of 1969-12-31T00:00:00.000Z does not equal Cloud SQL"
|
||||
+ " lock acquiredTime of 1970-01-01T00:00:00.000Z"));
|
||||
assertAboutLogs()
|
||||
.that(logHandler)
|
||||
.hasLogAtLevelWithMessage(
|
||||
Level.WARNING,
|
||||
String.format(
|
||||
"Datastore lock expirationTime of 1969-12-31T00:00:00.003Z does not equal Cloud"
|
||||
+ " SQL lock expirationTime of 1970-01-01T00:00:00.002Z"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import com.beust.jcommander.Parameter;
|
||||
import com.beust.jcommander.Parameters;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.net.HostAndPort;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.tools.params.HostAndPortParameter;
|
||||
@@ -156,23 +155,18 @@ public final class RegistryTestServerMain {
|
||||
}
|
||||
};
|
||||
|
||||
Statement withAppEngine =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withUrlFetch()
|
||||
.withTaskQueue()
|
||||
.withLocalModules()
|
||||
.withUserService(
|
||||
loginIsAdmin
|
||||
? UserInfo.createAdmin(loginEmail, loginUserId)
|
||||
: UserInfo.create(loginEmail, loginUserId))
|
||||
.build()
|
||||
.apply(runner, Description.EMPTY);
|
||||
|
||||
System.out.printf("%sLoading SQL fixtures and AppEngineRule...%s\n", BLUE, RESET);
|
||||
new JpaTestRules.Builder()
|
||||
.buildIntegrationTestRule()
|
||||
.apply(withAppEngine, Description.EMPTY)
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withUrlFetch()
|
||||
.withTaskQueue()
|
||||
.withLocalModules()
|
||||
.withUserService(
|
||||
loginIsAdmin
|
||||
? UserInfo.createAdmin(loginEmail, loginUserId)
|
||||
: UserInfo.create(loginEmail, loginUserId))
|
||||
.build()
|
||||
.apply(runner, Description.EMPTY)
|
||||
.evaluate();
|
||||
}
|
||||
|
||||
|
||||
@@ -247,6 +247,7 @@ public final class AppEngineRule extends ExternalResource {
|
||||
.setParent(makeRegistrar2())
|
||||
.setName("Marla Singer")
|
||||
.setEmailAddress("Marla.Singer@crr.com")
|
||||
.setRegistryLockEmailAddress("Marla.Singer.RegistryLock@crr.com")
|
||||
.setPhoneNumber("+1.2128675309")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
|
||||
.setGaeUserId("12345")
|
||||
|
||||
@@ -89,6 +89,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
"--mode=UPDATE",
|
||||
"--name=Judith Registrar",
|
||||
"--email=judith.doe@example.com",
|
||||
"--registry_lock_email=judith.doe@external.com",
|
||||
"--phone=+1.2125650000",
|
||||
"--fax=+1.2125650001",
|
||||
"--contact_type=WHOIS",
|
||||
@@ -102,6 +103,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
.setParent(registrar)
|
||||
.setName("Judith Registrar")
|
||||
.setEmailAddress("judith.doe@example.com")
|
||||
.setRegistryLockEmailAddress("judith.doe@external.com")
|
||||
.setPhoneNumber("+1.2125650000")
|
||||
.setFaxNumber("+1.2125650001")
|
||||
.setTypes(ImmutableSet.of(WHOIS))
|
||||
@@ -292,6 +294,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
"--mode=CREATE",
|
||||
"--name=Jim Doe",
|
||||
"--email=jim.doe@example.com",
|
||||
"--registry_lock_email=jim.doe@external.com",
|
||||
"--contact_type=ADMIN,ABUSE",
|
||||
"--visible_in_whois_as_admin=true",
|
||||
"--visible_in_whois_as_tech=false",
|
||||
@@ -303,6 +306,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
.setParent(registrar)
|
||||
.setName("Jim Doe")
|
||||
.setEmailAddress("jim.doe@example.com")
|
||||
.setRegistryLockEmailAddress("jim.doe@external.com")
|
||||
.setTypes(ImmutableSet.of(ADMIN, ABUSE))
|
||||
.setVisibleInWhoisAsAdmin(true)
|
||||
.setVisibleInWhoisAsTech(false)
|
||||
@@ -374,6 +378,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
"--mode=CREATE",
|
||||
"--name=Jim Doe",
|
||||
"--email=jim.doe@example.com",
|
||||
"--registry_lock_email=jim.doe.registry.lock@example.com",
|
||||
"--allowed_to_set_registry_lock_password=true",
|
||||
"NewRegistrar");
|
||||
RegistrarContact registrarContact = loadRegistrar("NewRegistrar").getContacts().asList().get(1);
|
||||
@@ -392,12 +397,30 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
.setEmailAddress("jim.doe@example.com")
|
||||
.build());
|
||||
assertThat(registrarContact.isAllowedToSetRegistryLockPassword()).isFalse();
|
||||
|
||||
// First, try (and fail) to set the password directly
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> registrarContact.asBuilder().setRegistryLockPassword("foo"));
|
||||
|
||||
// Next, try (and fail) to allow registry lock without a registry lock email
|
||||
assertThat(
|
||||
assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() ->
|
||||
runCommandForced(
|
||||
"--mode=UPDATE",
|
||||
"--email=jim.doe@example.com",
|
||||
"--allowed_to_set_registry_lock_password=true",
|
||||
"NewRegistrar")))
|
||||
.hasMessageThat()
|
||||
.isEqualTo("Registry lock email must not be null if allowing registry lock access");
|
||||
|
||||
// Next, include the email and it should succeed
|
||||
runCommandForced(
|
||||
"--mode=UPDATE",
|
||||
"--email=jim.doe@example.com",
|
||||
"--registry_lock_email=jim.doe.registry.lock@example.com",
|
||||
"--allowed_to_set_registry_lock_password=true",
|
||||
"NewRegistrar");
|
||||
RegistrarContact newContact = reloadResource(registrarContact);
|
||||
@@ -415,6 +438,7 @@ public class RegistrarContactCommandTest extends CommandTestCase<RegistrarContac
|
||||
.setParent(registrar)
|
||||
.setName("Jim Doe")
|
||||
.setEmailAddress("jim.doe@example.com")
|
||||
.setRegistryLockEmailAddress("jim.doe.registry.lock@example.com")
|
||||
.setAllowedToSetRegistryLockPassword(true)
|
||||
.setRegistryLockPassword("hi")
|
||||
.build());
|
||||
|
||||
@@ -237,6 +237,7 @@ public class ContactSettingsTest extends RegistrarSettingsActionTestCase {
|
||||
AppEngineRule.makeRegistrarContact2()
|
||||
.asBuilder()
|
||||
.setEmailAddress("someotheremail@example.com")
|
||||
.setRegistryLockEmailAddress("someotherexample@example.com")
|
||||
.setAllowedToSetRegistryLockPassword(true)
|
||||
.build()
|
||||
.toJsonMap(),
|
||||
|
||||
@@ -100,6 +100,7 @@ public abstract class RegistrarSettingsActionTestCase {
|
||||
.setParent(loadRegistrar(CLIENT_ID))
|
||||
.setName("Jian-Yang")
|
||||
.setEmailAddress("jyang@bachman.accelerator")
|
||||
.setRegistryLockEmailAddress("jyang.registrylock@bachman.accelerator")
|
||||
.setPhoneNumber("+1.1234567890")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
|
||||
.build());
|
||||
|
||||
@@ -182,16 +182,16 @@ public final class RegistryLockGetActionTest {
|
||||
"lockEnabledForContact",
|
||||
true,
|
||||
"email",
|
||||
"Marla.Singer@crr.com",
|
||||
"Marla.Singer.RegistryLock@crr.com",
|
||||
"clientId",
|
||||
"TheRegistrar",
|
||||
"locks",
|
||||
ImmutableList.of(
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "expiredunlock.test")
|
||||
.put("lockedTime", "2000-06-08T22:00:00.000Z")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("fullyQualifiedDomainName", "adminexample.test")
|
||||
.put("lockedTime", "2000-06-09T22:00:00.001Z")
|
||||
.put("lockedBy", "admin")
|
||||
.put("userCanUnlock", false)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
@@ -204,19 +204,11 @@ public final class RegistryLockGetActionTest {
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "adminexample.test")
|
||||
.put("lockedTime", "2000-06-09T22:00:00.001Z")
|
||||
.put("lockedBy", "admin")
|
||||
.put("userCanUnlock", false)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "pending.test")
|
||||
.put("lockedTime", "")
|
||||
.put("fullyQualifiedDomainName", "expiredunlock.test")
|
||||
.put("lockedTime", "2000-06-08T22:00:00.000Z")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", true)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
@@ -226,6 +218,14 @@ public final class RegistryLockGetActionTest {
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", true)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "pending.test")
|
||||
.put("lockedTime", "")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", true)
|
||||
.put("isUnlockPending", false)
|
||||
.build()))));
|
||||
}
|
||||
|
||||
@@ -276,7 +276,7 @@ public final class RegistryLockGetActionTest {
|
||||
"lockEnabledForContact",
|
||||
false,
|
||||
"email",
|
||||
"Marla.Singer@crr.com",
|
||||
"Marla.Singer.RegistryLock@crr.com",
|
||||
"clientId",
|
||||
"TheRegistrar",
|
||||
"locks",
|
||||
@@ -304,7 +304,7 @@ public final class RegistryLockGetActionTest {
|
||||
"lockEnabledForContact",
|
||||
true,
|
||||
"email",
|
||||
"Marla.Singer@crr.com",
|
||||
"Marla.Singer.RegistryLock@crr.com",
|
||||
"clientId",
|
||||
"TheRegistrar",
|
||||
"locks",
|
||||
@@ -327,7 +327,7 @@ public final class RegistryLockGetActionTest {
|
||||
"lockEnabledForContact",
|
||||
true,
|
||||
"email",
|
||||
"Marla.Singer@crr.com",
|
||||
"Marla.Singer.RegistryLock@crr.com",
|
||||
"clientId",
|
||||
"TheRegistrar",
|
||||
"locks",
|
||||
|
||||
@@ -105,7 +105,7 @@ public final class RegistryLockPostActionTest {
|
||||
@Test
|
||||
public void testSuccess_lock() throws Exception {
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertSuccess(response, "lock", "Marla.Singer@crr.com");
|
||||
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -113,7 +113,7 @@ public final class RegistryLockPostActionTest {
|
||||
saveRegistryLock(createLock().asBuilder().setLockCompletionTimestamp(clock.nowUtc()).build());
|
||||
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
|
||||
assertSuccess(response, "unlock", "Marla.Singer@crr.com");
|
||||
assertSuccess(response, "unlock", "Marla.Singer.RegistryLock@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -142,7 +142,7 @@ public final class RegistryLockPostActionTest {
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false)));
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertSuccess(response, "lock", "Marla.Singer@crr.com");
|
||||
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -309,7 +309,7 @@ public final class RegistryLockPostActionTest {
|
||||
.build());
|
||||
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertSuccess(response, "lock", "Marla.Singer@crr.com");
|
||||
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -319,7 +319,7 @@ public final class RegistryLockPostActionTest {
|
||||
previousLock = getRegistryLockByVerificationCode(verificationCode).get();
|
||||
clock.setTo(previousLock.getLockRequestTimestamp().plusHours(2));
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertSuccess(response, "lock", "Marla.Singer@crr.com");
|
||||
assertSuccess(response, "lock", "Marla.Singer.RegistryLock@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -153,6 +153,7 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
||||
persistResource(
|
||||
makeRegistrarContact2()
|
||||
.asBuilder()
|
||||
.setRegistryLockEmailAddress("johndoe.registrylock@example.com")
|
||||
.setAllowedToSetRegistryLockPassword(true)
|
||||
.build());
|
||||
persistResource(makeRegistrar2().asBuilder().setRegistryLockAllowed(true).build());
|
||||
|
||||
@@ -477,6 +477,7 @@ class google.registry.model.registrar.RegistrarContact {
|
||||
java.lang.String gaeUserId;
|
||||
java.lang.String name;
|
||||
java.lang.String phoneNumber;
|
||||
java.lang.String registryLockEmailAddress;
|
||||
java.lang.String registryLockPasswordHash;
|
||||
java.lang.String registryLockPasswordSalt;
|
||||
java.util.Set<google.registry.model.registrar.RegistrarContact$Type> types;
|
||||
|
||||
@@ -11,10 +11,10 @@ emailAddress: the.registrar@example.com -> thase@the.registrar
|
||||
url: http://my.fake.url -> http://my.new.url
|
||||
contacts:
|
||||
ADDED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, registryLockEmailAddress=null, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
REMOVED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=12345, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Jian-Yang, emailAddress=jyang@bachman.accelerator, phoneNumber=+1.1234567890, faxNumber=null, types=[TECH], gaeUserId=null, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, registryLockEmailAddress=Marla.Singer.RegistryLock@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=12345, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, registryLockEmailAddress=null, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Jian-Yang, emailAddress=jyang@bachman.accelerator, registryLockEmailAddress=jyang.registrylock@bachman.accelerator, phoneNumber=+1.1234567890, faxNumber=null, types=[TECH], gaeUserId=null, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
FINAL CONTENTS:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, registryLockEmailAddress=null, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
|
||||
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 50 KiB |
|
Before Width: | Height: | Size: 50 KiB After Width: | Height: | Size: 51 KiB |
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 70 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
@@ -0,0 +1,15 @@
|
||||
-- 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.
|
||||
|
||||
ALTER TABLE "RegistryLock" ADD COLUMN relock_duration bigint;
|
||||
@@ -0,0 +1,15 @@
|
||||
-- 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.
|
||||
|
||||
ALTER TABLE "RegistrarPoc" ADD COLUMN registry_lock_email_address text;
|
||||
@@ -158,6 +158,7 @@
|
||||
gae_user_id text,
|
||||
name text,
|
||||
phone_number text,
|
||||
registry_lock_email_address text,
|
||||
registry_lock_password_hash text,
|
||||
registry_lock_password_salt text,
|
||||
types text[],
|
||||
@@ -176,6 +177,7 @@
|
||||
lock_request_timestamp timestamptz not null,
|
||||
registrar_id text not null,
|
||||
registrar_poc_id text,
|
||||
relock_duration int8,
|
||||
repo_id text not null,
|
||||
unlock_completion_timestamp timestamptz,
|
||||
unlock_request_timestamp timestamptz,
|
||||
|
||||
@@ -241,7 +241,8 @@ CREATE TABLE public."RegistrarPoc" (
|
||||
types text[],
|
||||
visible_in_domain_whois_as_abuse boolean NOT NULL,
|
||||
visible_in_whois_as_admin boolean NOT NULL,
|
||||
visible_in_whois_as_tech boolean NOT NULL
|
||||
visible_in_whois_as_tech boolean NOT NULL,
|
||||
registry_lock_email_address text
|
||||
);
|
||||
|
||||
|
||||
@@ -262,7 +263,8 @@ CREATE TABLE public."RegistryLock" (
|
||||
unlock_request_timestamp timestamp with time zone,
|
||||
unlock_completion_timestamp timestamp with time zone,
|
||||
last_update_timestamp timestamp with time zone,
|
||||
relock_revision_id bigint
|
||||
relock_revision_id bigint,
|
||||
relock_duration bigint
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -43,6 +43,7 @@ ext {
|
||||
'com.google.auto.value:auto-value-annotations:1.6.3',
|
||||
'com.google.auto.value:auto-value:1.6.3',
|
||||
'com.google.closure-stylesheets:closure-stylesheets:1.5.0',
|
||||
'com.google.cloud.sql:jdbc-socket-factory-core:1.0.12',
|
||||
'com.google.cloud.sql:postgres-socket-factory:1.0.12',
|
||||
'com.google.cloud:google-cloud-core:1.59.0',
|
||||
'com.google.cloud:google-cloud-storage:1.59.0',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-6.2.2-all.zip
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
|
||||
@@ -29,6 +29,9 @@ if "%DIRNAME%" == "" set DIRNAME=.
|
||||
set APP_BASE_NAME=%~n0
|
||||
set APP_HOME=%DIRNAME%
|
||||
|
||||
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
|
||||
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
|
||||
|
||||
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
|
||||
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"mime-types": "~2.1.24",
|
||||
"mime-types": "2.1.24",
|
||||
"negotiator": "0.6.2"
|
||||
}
|
||||
},
|
||||
@@ -26,7 +26,7 @@
|
||||
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promisify": "^5.0.0"
|
||||
"es6-promisify": "5.0.0"
|
||||
}
|
||||
},
|
||||
"anymatch": {
|
||||
@@ -35,8 +35,8 @@
|
||||
"integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
"normalize-path": "3.0.0",
|
||||
"picomatch": "2.1.1"
|
||||
}
|
||||
},
|
||||
"arraybuffer.slice": {
|
||||
@@ -51,7 +51,7 @@
|
||||
"integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash": "^4.17.14"
|
||||
"lodash": "4.17.15"
|
||||
}
|
||||
},
|
||||
"async-limiter": {
|
||||
@@ -118,15 +118,15 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bytes": "3.1.0",
|
||||
"content-type": "~1.0.4",
|
||||
"content-type": "1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "~1.1.2",
|
||||
"depd": "1.1.2",
|
||||
"http-errors": "1.7.2",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "~2.3.0",
|
||||
"on-finished": "2.3.0",
|
||||
"qs": "6.7.0",
|
||||
"raw-body": "2.4.0",
|
||||
"type-is": "~1.6.17"
|
||||
"type-is": "1.6.18"
|
||||
}
|
||||
},
|
||||
"brace-expansion": {
|
||||
@@ -135,7 +135,7 @@
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"balanced-match": "1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
@@ -145,7 +145,7 @@
|
||||
"integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fill-range": "^7.0.1"
|
||||
"fill-range": "7.0.1"
|
||||
}
|
||||
},
|
||||
"buffer-alloc": {
|
||||
@@ -154,8 +154,8 @@
|
||||
"integrity": "sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-alloc-unsafe": "^1.1.0",
|
||||
"buffer-fill": "^1.0.0"
|
||||
"buffer-alloc-unsafe": "1.1.0",
|
||||
"buffer-fill": "1.0.0"
|
||||
}
|
||||
},
|
||||
"buffer-alloc-unsafe": {
|
||||
@@ -194,14 +194,14 @@
|
||||
"integrity": "sha512-dGmKLDdT3Gdl7fBUe8XK+gAtGmzy5Fn0XkkWQuYxGIgWVPPse2CxFA5mtrlD0TOHaHjEUqkWNyP1XdHoJES/4A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.1",
|
||||
"braces": "~3.0.2",
|
||||
"fsevents": "~2.1.1",
|
||||
"glob-parent": "~5.1.0",
|
||||
"is-binary-path": "~2.1.0",
|
||||
"is-glob": "~4.0.1",
|
||||
"normalize-path": "~3.0.0",
|
||||
"readdirp": "~3.2.0"
|
||||
"anymatch": "3.1.1",
|
||||
"braces": "3.0.2",
|
||||
"fsevents": "2.1.2",
|
||||
"glob-parent": "5.1.0",
|
||||
"is-binary-path": "2.1.0",
|
||||
"is-glob": "4.0.1",
|
||||
"normalize-path": "3.0.0",
|
||||
"readdirp": "3.2.0"
|
||||
}
|
||||
},
|
||||
"colors": {
|
||||
@@ -240,10 +240,10 @@
|
||||
"integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-from": "^1.0.0",
|
||||
"inherits": "^2.0.3",
|
||||
"readable-stream": "^2.2.2",
|
||||
"typedarray": "^0.0.6"
|
||||
"buffer-from": "1.1.1",
|
||||
"inherits": "2.0.3",
|
||||
"readable-stream": "2.3.6",
|
||||
"typedarray": "0.0.6"
|
||||
}
|
||||
},
|
||||
"connect": {
|
||||
@@ -254,7 +254,7 @@
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"finalhandler": "1.1.2",
|
||||
"parseurl": "~1.3.3",
|
||||
"parseurl": "1.3.3",
|
||||
"utils-merge": "1.0.1"
|
||||
}
|
||||
},
|
||||
@@ -315,10 +315,10 @@
|
||||
"integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"custom-event": "~1.0.0",
|
||||
"ent": "~2.2.0",
|
||||
"extend": "^3.0.0",
|
||||
"void-elements": "^2.0.0"
|
||||
"custom-event": "1.0.1",
|
||||
"ent": "2.2.0",
|
||||
"extend": "3.0.2",
|
||||
"void-elements": "2.0.1"
|
||||
}
|
||||
},
|
||||
"ee-first": {
|
||||
@@ -339,12 +339,12 @@
|
||||
"integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"accepts": "~1.3.4",
|
||||
"accepts": "1.3.7",
|
||||
"base64id": "1.0.0",
|
||||
"cookie": "0.3.1",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-parser": "~2.1.0",
|
||||
"ws": "~3.3.1"
|
||||
"debug": "3.1.0",
|
||||
"engine.io-parser": "2.1.3",
|
||||
"ws": "3.3.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -366,14 +366,14 @@
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"component-inherit": "0.0.3",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-parser": "~2.1.1",
|
||||
"debug": "3.1.0",
|
||||
"engine.io-parser": "2.1.3",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"ws": "~3.3.1",
|
||||
"xmlhttprequest-ssl": "~1.5.4",
|
||||
"ws": "3.3.3",
|
||||
"xmlhttprequest-ssl": "1.5.5",
|
||||
"yeast": "0.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -395,10 +395,10 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"after": "0.8.2",
|
||||
"arraybuffer.slice": "~0.0.7",
|
||||
"arraybuffer.slice": "0.0.7",
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"blob": "0.0.5",
|
||||
"has-binary2": "~1.0.2"
|
||||
"has-binary2": "1.0.3"
|
||||
}
|
||||
},
|
||||
"ent": {
|
||||
@@ -419,7 +419,7 @@
|
||||
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"es6-promise": "^4.0.3"
|
||||
"es6-promise": "4.2.8"
|
||||
}
|
||||
},
|
||||
"escape-html": {
|
||||
@@ -458,7 +458,7 @@
|
||||
"integrity": "sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pend": "~1.2.0"
|
||||
"pend": "1.2.0"
|
||||
}
|
||||
},
|
||||
"fill-range": {
|
||||
@@ -467,7 +467,7 @@
|
||||
"integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
"to-regex-range": "5.0.1"
|
||||
}
|
||||
},
|
||||
"finalhandler": {
|
||||
@@ -477,12 +477,12 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "~2.3.0",
|
||||
"parseurl": "~1.3.3",
|
||||
"statuses": "~1.5.0",
|
||||
"unpipe": "~1.0.0"
|
||||
"encodeurl": "1.0.2",
|
||||
"escape-html": "1.0.3",
|
||||
"on-finished": "2.3.0",
|
||||
"parseurl": "1.3.3",
|
||||
"statuses": "1.5.0",
|
||||
"unpipe": "1.0.0"
|
||||
}
|
||||
},
|
||||
"flatted": {
|
||||
@@ -497,7 +497,7 @@
|
||||
"integrity": "sha512-CRcPzsSIbXyVDl0QI01muNDu69S8trU4jArW9LpOt2WtC6LyUJetcIrmfHsRBx7/Jb6GHJUiuqyYxPooFfNt6A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^3.0.0"
|
||||
"debug": "3.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -506,7 +506,7 @@
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -523,7 +523,7 @@
|
||||
"integrity": "sha1-1qh/JiJxzv6+wwxVNAf7mV2od3o=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"null-check": "^1.0.0"
|
||||
"null-check": "1.0.0"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
@@ -532,9 +532,9 @@
|
||||
"integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.2",
|
||||
"jsonfile": "^4.0.0",
|
||||
"universalify": "^0.1.0"
|
||||
"graceful-fs": "4.2.3",
|
||||
"jsonfile": "4.0.0",
|
||||
"universalify": "0.1.2"
|
||||
}
|
||||
},
|
||||
"fs.realpath": {
|
||||
@@ -556,12 +556,12 @@
|
||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.0.4",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
"fs.realpath": "1.0.0",
|
||||
"inflight": "1.0.6",
|
||||
"inherits": "2.0.3",
|
||||
"minimatch": "3.0.4",
|
||||
"once": "1.4.0",
|
||||
"path-is-absolute": "1.0.1"
|
||||
}
|
||||
},
|
||||
"glob-parent": {
|
||||
@@ -570,7 +570,7 @@
|
||||
"integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
"is-glob": "4.0.1"
|
||||
}
|
||||
},
|
||||
"google-closure-library": {
|
||||
@@ -605,10 +605,10 @@
|
||||
"integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"depd": "~1.1.2",
|
||||
"depd": "1.1.2",
|
||||
"inherits": "2.0.3",
|
||||
"setprototypeof": "1.1.1",
|
||||
"statuses": ">= 1.5.0 < 2",
|
||||
"statuses": "1.5.0",
|
||||
"toidentifier": "1.0.0"
|
||||
}
|
||||
},
|
||||
@@ -618,9 +618,9 @@
|
||||
"integrity": "sha512-84I2iJM/n1d4Hdgc6y2+qY5mDaz2PUVjlg9znE9byl+q0uC3DeByqBGReQu5tpLK0TAqTIXScRUV+dg7+bUPpQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"eventemitter3": "^4.0.0",
|
||||
"follow-redirects": "^1.0.0",
|
||||
"requires-port": "^1.0.0"
|
||||
"eventemitter3": "4.0.0",
|
||||
"follow-redirects": "1.9.0",
|
||||
"requires-port": "1.0.0"
|
||||
}
|
||||
},
|
||||
"https-proxy-agent": {
|
||||
@@ -629,8 +629,8 @@
|
||||
"integrity": "sha512-+ML2Rbh6DAuee7d07tYGEKOEi2voWPUGan+ExdPbPW6Z3svq+JCqr0v8WmKPOkz1vOVykPCBSuobe7G8GJUtVg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"agent-base": "^4.3.0",
|
||||
"debug": "^3.1.0"
|
||||
"agent-base": "4.3.0",
|
||||
"debug": "3.2.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -639,7 +639,7 @@
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -656,7 +656,7 @@
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
"safer-buffer": "2.1.2"
|
||||
}
|
||||
},
|
||||
"indexof": {
|
||||
@@ -671,8 +671,8 @@
|
||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"once": "^1.3.0",
|
||||
"wrappy": "1"
|
||||
"once": "1.4.0",
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"inherits": {
|
||||
@@ -687,7 +687,7 @@
|
||||
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"binary-extensions": "^2.0.0"
|
||||
"binary-extensions": "2.0.0"
|
||||
}
|
||||
},
|
||||
"is-extglob": {
|
||||
@@ -702,7 +702,7 @@
|
||||
"integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-extglob": "^2.1.1"
|
||||
"is-extglob": "2.1.1"
|
||||
}
|
||||
},
|
||||
"is-number": {
|
||||
@@ -723,7 +723,7 @@
|
||||
"integrity": "sha512-8cJBL5tTd2OS0dM4jz07wQd5g0dCCqIhUxPIGtZfa5L6hWlvV5MHTITy/DBAsF+Oe2LS1X3krBUhNwaGUWpWxw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"buffer-alloc": "^1.2.0"
|
||||
"buffer-alloc": "1.2.0"
|
||||
}
|
||||
},
|
||||
"isexe": {
|
||||
@@ -744,7 +744,7 @@
|
||||
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6"
|
||||
"graceful-fs": "4.2.3"
|
||||
}
|
||||
},
|
||||
"karma": {
|
||||
@@ -753,30 +753,30 @@
|
||||
"integrity": "sha512-L5SIaXEYqzrh6b1wqYC42tNsFMx2PWuxky84pK9coK09MvmL7mxii3G3bZBh/0rvD27lqDd0le9jyhzvwif73A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"bluebird": "^3.3.0",
|
||||
"body-parser": "^1.16.1",
|
||||
"braces": "^3.0.2",
|
||||
"chokidar": "^3.0.0",
|
||||
"colors": "^1.1.0",
|
||||
"connect": "^3.6.0",
|
||||
"di": "^0.0.1",
|
||||
"dom-serialize": "^2.2.0",
|
||||
"flatted": "^2.0.0",
|
||||
"glob": "^7.1.1",
|
||||
"graceful-fs": "^4.1.2",
|
||||
"http-proxy": "^1.13.0",
|
||||
"isbinaryfile": "^3.0.0",
|
||||
"lodash": "^4.17.14",
|
||||
"log4js": "^4.0.0",
|
||||
"mime": "^2.3.1",
|
||||
"minimatch": "^3.0.2",
|
||||
"optimist": "^0.6.1",
|
||||
"qjobs": "^1.1.4",
|
||||
"range-parser": "^1.2.0",
|
||||
"rimraf": "^2.6.0",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"bluebird": "3.7.1",
|
||||
"body-parser": "1.19.0",
|
||||
"braces": "3.0.2",
|
||||
"chokidar": "3.3.0",
|
||||
"colors": "1.4.0",
|
||||
"connect": "3.7.0",
|
||||
"di": "0.0.1",
|
||||
"dom-serialize": "2.2.1",
|
||||
"flatted": "2.0.1",
|
||||
"glob": "7.1.6",
|
||||
"graceful-fs": "4.2.3",
|
||||
"http-proxy": "1.18.0",
|
||||
"isbinaryfile": "3.0.3",
|
||||
"lodash": "4.17.15",
|
||||
"log4js": "4.5.1",
|
||||
"mime": "2.4.4",
|
||||
"minimatch": "3.0.4",
|
||||
"optimist": "0.6.1",
|
||||
"qjobs": "1.2.0",
|
||||
"range-parser": "1.2.1",
|
||||
"rimraf": "2.7.1",
|
||||
"safe-buffer": "5.2.0",
|
||||
"socket.io": "2.1.1",
|
||||
"source-map": "^0.6.1",
|
||||
"source-map": "0.6.1",
|
||||
"tmp": "0.0.33",
|
||||
"useragent": "2.3.0"
|
||||
}
|
||||
@@ -787,8 +787,8 @@
|
||||
"integrity": "sha512-uf/ZVpAabDBPvdPdveyk1EPgbnloPvFFGgmRhYLTDH7gEB4nZdSBk8yTU47w1g/drLSx5uMOkjKk7IWKfWg/+w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fs-access": "^1.0.0",
|
||||
"which": "^1.2.1"
|
||||
"fs-access": "1.0.1",
|
||||
"which": "1.3.1"
|
||||
}
|
||||
},
|
||||
"karma-closure": {
|
||||
@@ -803,7 +803,7 @@
|
||||
"integrity": "sha512-iuC0hmr9b+SNn1DaUD2QEYtUxkS1J+bSJSn7ejdEexs7P8EYvA1CWkEdrDQ+8jVH3AgWlCNwjYsT1chjcNW9lA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"jasmine-core": "^3.3"
|
||||
"jasmine-core": "3.4.0"
|
||||
}
|
||||
},
|
||||
"lodash": {
|
||||
@@ -818,11 +818,11 @@
|
||||
"integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"date-format": "^2.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"flatted": "^2.0.0",
|
||||
"rfdc": "^1.1.4",
|
||||
"streamroller": "^1.0.6"
|
||||
"date-format": "2.1.0",
|
||||
"debug": "4.1.1",
|
||||
"flatted": "2.0.1",
|
||||
"rfdc": "1.1.4",
|
||||
"streamroller": "1.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -831,7 +831,7 @@
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -848,8 +848,8 @@
|
||||
"integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"pseudomap": "^1.0.2",
|
||||
"yallist": "^2.1.2"
|
||||
"pseudomap": "1.0.2",
|
||||
"yallist": "2.1.2"
|
||||
}
|
||||
},
|
||||
"media-typer": {
|
||||
@@ -885,7 +885,7 @@
|
||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
"brace-expansion": "1.1.11"
|
||||
}
|
||||
},
|
||||
"minimist": {
|
||||
@@ -956,7 +956,7 @@
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
"wrappy": "1.0.2"
|
||||
}
|
||||
},
|
||||
"optimist": {
|
||||
@@ -965,8 +965,8 @@
|
||||
"integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"minimist": "~0.0.1",
|
||||
"wordwrap": "~0.0.2"
|
||||
"minimist": "0.0.10",
|
||||
"wordwrap": "0.0.3"
|
||||
}
|
||||
},
|
||||
"os-tmpdir": {
|
||||
@@ -981,7 +981,7 @@
|
||||
"integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"better-assert": "~1.0.0"
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
},
|
||||
"parseuri": {
|
||||
@@ -990,7 +990,7 @@
|
||||
"integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"better-assert": "~1.0.0"
|
||||
"better-assert": "1.0.2"
|
||||
}
|
||||
},
|
||||
"parseurl": {
|
||||
@@ -1047,14 +1047,14 @@
|
||||
"integrity": "sha512-t3MmTWzQxPRP71teU6l0jX47PHXlc4Z52sQv4LJQSZLq1ttkKS2yGM3gaI57uQwZkNaoGd0+HPPMELZkcyhlqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "^4.1.0",
|
||||
"extract-zip": "^1.6.6",
|
||||
"https-proxy-agent": "^3.0.0",
|
||||
"mime": "^2.0.3",
|
||||
"progress": "^2.0.1",
|
||||
"proxy-from-env": "^1.0.0",
|
||||
"rimraf": "^2.6.1",
|
||||
"ws": "^6.1.0"
|
||||
"debug": "4.1.1",
|
||||
"extract-zip": "1.6.7",
|
||||
"https-proxy-agent": "3.0.1",
|
||||
"mime": "2.4.4",
|
||||
"progress": "2.0.3",
|
||||
"proxy-from-env": "1.0.0",
|
||||
"rimraf": "2.7.1",
|
||||
"ws": "6.2.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -1063,7 +1063,7 @@
|
||||
"integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -1078,7 +1078,7 @@
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
"async-limiter": "1.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1119,13 +1119,13 @@
|
||||
"integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
"core-util-is": "1.0.2",
|
||||
"inherits": "2.0.3",
|
||||
"isarray": "1.0.0",
|
||||
"process-nextick-args": "2.0.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"string_decoder": "1.1.1",
|
||||
"util-deprecate": "1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"isarray": {
|
||||
@@ -1148,7 +1148,7 @@
|
||||
"integrity": "sha512-crk4Qu3pmXwgxdSgGhgA/eXiJAPQiX4GMOZZMXnqKxHX7TaoL+3gQVo/WeuAiogr07DpnfjIMpXXa+PAIvwPGQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.0.4"
|
||||
"picomatch": "2.1.1"
|
||||
}
|
||||
},
|
||||
"requires-port": {
|
||||
@@ -1169,7 +1169,7 @@
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
"glob": "7.1.6"
|
||||
}
|
||||
},
|
||||
"safe-buffer": {
|
||||
@@ -1196,12 +1196,12 @@
|
||||
"integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"debug": "~3.1.0",
|
||||
"engine.io": "~3.2.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"socket.io-adapter": "~1.1.0",
|
||||
"debug": "3.1.0",
|
||||
"engine.io": "3.2.1",
|
||||
"has-binary2": "1.0.3",
|
||||
"socket.io-adapter": "1.1.1",
|
||||
"socket.io-client": "2.1.1",
|
||||
"socket.io-parser": "~3.2.0"
|
||||
"socket.io-parser": "3.2.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -1231,15 +1231,15 @@
|
||||
"base64-arraybuffer": "0.1.5",
|
||||
"component-bind": "1.0.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~3.1.0",
|
||||
"engine.io-client": "~3.2.0",
|
||||
"has-binary2": "~1.0.2",
|
||||
"debug": "3.1.0",
|
||||
"engine.io-client": "3.2.1",
|
||||
"has-binary2": "1.0.3",
|
||||
"has-cors": "1.1.0",
|
||||
"indexof": "0.0.1",
|
||||
"object-component": "0.0.3",
|
||||
"parseqs": "0.0.5",
|
||||
"parseuri": "0.0.5",
|
||||
"socket.io-parser": "~3.2.0",
|
||||
"socket.io-parser": "3.2.0",
|
||||
"to-array": "0.1.4"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -1261,7 +1261,7 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"component-emitter": "1.2.1",
|
||||
"debug": "~3.1.0",
|
||||
"debug": "3.1.0",
|
||||
"isarray": "2.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -1294,11 +1294,11 @@
|
||||
"integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async": "^2.6.2",
|
||||
"date-format": "^2.0.0",
|
||||
"debug": "^3.2.6",
|
||||
"fs-extra": "^7.0.1",
|
||||
"lodash": "^4.17.14"
|
||||
"async": "2.6.3",
|
||||
"date-format": "2.1.0",
|
||||
"debug": "3.2.6",
|
||||
"fs-extra": "7.0.1",
|
||||
"lodash": "4.17.15"
|
||||
},
|
||||
"dependencies": {
|
||||
"debug": {
|
||||
@@ -1307,7 +1307,7 @@
|
||||
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ms": "^2.1.1"
|
||||
"ms": "2.1.2"
|
||||
}
|
||||
},
|
||||
"ms": {
|
||||
@@ -1324,7 +1324,7 @@
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
"safe-buffer": "5.1.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
@@ -1341,7 +1341,7 @@
|
||||
"integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"os-tmpdir": "~1.0.2"
|
||||
"os-tmpdir": "1.0.2"
|
||||
}
|
||||
},
|
||||
"to-array": {
|
||||
@@ -1356,7 +1356,7 @@
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-number": "^7.0.0"
|
||||
"is-number": "7.0.0"
|
||||
}
|
||||
},
|
||||
"toidentifier": {
|
||||
@@ -1372,7 +1372,7 @@
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
"mime-types": "2.1.24"
|
||||
}
|
||||
},
|
||||
"typedarray": {
|
||||
@@ -1405,8 +1405,8 @@
|
||||
"integrity": "sha512-4AoH4pxuSvHCjqLO04sU6U/uE65BYza8l/KKBS0b0hnUPWi+cQ2BpeTEwejCSx9SPV5/U03nniDTrWx5NrmKdw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lru-cache": "4.1.x",
|
||||
"tmp": "0.0.x"
|
||||
"lru-cache": "4.1.5",
|
||||
"tmp": "0.0.33"
|
||||
}
|
||||
},
|
||||
"util-deprecate": {
|
||||
@@ -1433,7 +1433,7 @@
|
||||
"integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
"isexe": "2.0.0"
|
||||
}
|
||||
},
|
||||
"wordwrap": {
|
||||
@@ -1454,9 +1454,9 @@
|
||||
"integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0",
|
||||
"safe-buffer": "~5.1.0",
|
||||
"ultron": "~1.1.0"
|
||||
"async-limiter": "1.0.1",
|
||||
"safe-buffer": "5.1.2",
|
||||
"ultron": "1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"safe-buffer": {
|
||||
@@ -1485,7 +1485,7 @@
|
||||
"integrity": "sha1-lSj0QtqxsihOWLQ3m7GU4i4MQAU=",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"fd-slicer": "~1.0.1"
|
||||
"fd-slicer": "1.0.1"
|
||||
}
|
||||
},
|
||||
"yeast": {
|
||||
|
||||