diff --git a/at_client/src/main/java/org/atsign/client/api/AtKeyNames.java b/at_client/src/main/java/org/atsign/client/api/AtKeyNames.java
new file mode 100644
index 00000000..eee0d3ab
--- /dev/null
+++ b/at_client/src/main/java/org/atsign/client/api/AtKeyNames.java
@@ -0,0 +1,57 @@
+package org.atsign.client.api;
+
+import org.atsign.common.AtSign;
+
+/**
+ * Constants and Utility methods for "well known" standard keys
+ */
+public class AtKeyNames {
+
+ /**
+ * Key name for an Atsign's public encryption key
+ */
+ public static final String PUBLIC_ENCRYPT = "publickey";
+
+ /**
+ * Key name used during activation of Atsign server with CRAM authentication
+ */
+ public static final String PRIVATE_AT_SECRET = "privatekey:at_secret";
+
+ /**
+ * Key name used to store a shared encryption key between two {@link AtSign}s
+ */
+ public static final String SHARED_KEY = "shared_key";
+
+ /**
+ * Key name used during enrollment completion, this is used to obtain the self encryption
+ * for an {@link AtSign}
+ */
+ public static final String SELF_ENCRYPTION_KEY = "default_self_enc_key";
+
+ /**
+ * Key name used during enrollment completion, this is used to obtain the private encryption
+ * key for an {@link AtSign}
+ */
+ public static final String ENCRYPT_PRIVATE_KEY = "default_enc_private_key";
+
+ /**
+ * Returns the key name used to store the shared encryption key encrypted with
+ * the sharedBy {@link AtSign}'s public key
+ *
+ * @param sharedWith the sharedWith (recipient) {@link AtSign}
+ * @return the fully qualified key name
+ */
+ public static String toSharedByMeKeyName(AtSign sharedWith) {
+ return String.format("%s.%s", SHARED_KEY, sharedWith.withoutPrefix());
+ }
+
+
+ /**
+ *
+ * @return the key used to shared
+ */
+ public static String toSharedWithMeKeyName(AtSign sharedBy, AtSign sharedWith) {
+ return String.format("%s:%s%s", SHARED_KEY, sharedWith, sharedBy);
+ }
+
+}
diff --git a/at_client/src/main/java/org/atsign/client/api/AtKeys.java b/at_client/src/main/java/org/atsign/client/api/AtKeys.java
index 9af38c4d..3b5171d2 100644
--- a/at_client/src/main/java/org/atsign/client/api/AtKeys.java
+++ b/at_client/src/main/java/org/atsign/client/api/AtKeys.java
@@ -1,8 +1,7 @@
package org.atsign.client.api;
+import java.security.Key;
import java.security.KeyPair;
-import java.security.PrivateKey;
-import java.security.PublicKey;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
@@ -10,50 +9,64 @@
import org.atsign.client.util.EnrollmentId;
+import lombok.Builder;
+import lombok.Value;
+
/**
- * Data class used to hold an {@link org.atsign.client.api.AtClient}s keys
+ * An immutable class used to hold an {@link org.atsign.client.api.AtClient}s keys.
+ *
+ * Examples:
+ *
+ *
+ * AtKeys keys = AtKeys.builder()
+ * .selfEncryptKey(generateAESKeyBase64())
+ * .apkamKeyPair(generateRSAKeyPair())
+ * .apkamSymmetricKey(generateAESKeyBase64())
+ * .build();
+ *
+ * keys = keys.toBuilder().enrollmentId(enrollmentId).build();
+ *
*/
+@Value
+@Builder(toBuilder = true)
public class AtKeys {
/**
* unique id which is assigned by the at_server at enrollment time, this is associated with a
- * specific
- * application and device and therefore a specific the apkam key pair
+ * specific application and device and therefore a specific the apkam key pair
*/
- private EnrollmentId enrollmentId;
+ EnrollmentId enrollmentId;
/**
* Public Key used for Authentication Management, once this is stored in the at_server then an
* {@link org.atsign.client.api.AtClient} is able to authenticate using the corresponding private
* key.
*/
- private String apkamPublicKey;
+ String apkamPublicKey;
/**
* Private Key used for Authentication Management, this is used to sign the challenge during
* authentication with the at_server.
*/
- private String apkamPrivateKey;
+ String apkamPrivateKey;
/**
* Encryption Key used during enrollment. This key is sent as part of the enrollment request
- * (encrypted
- * with the atsigns public encryption key). The process that approves the enrollment request uses
- * this
- * key to encrypt the {@link #selfEncryptKey} and {@link #encryptPrivateKey} in the response that it
- * sends.
+ * (encrypted with the atsigns public encryption key). The process that approves the enrollment
+ * request uses this key to encrypt the {@link #selfEncryptKey} and {@link #encryptPrivateKey}
+ * in the response that it sends.
* The process which requested the enrollment can then decrypt and store those keys.
* This ensures that all {@link AtKeys} got and {@link org.atsign.common.AtSign} share the same
* {@link #selfEncryptKey} and {@link #encryptPrivateKey}
*/
- private String apkamSymmetricKey;
+ String apkamSymmetricKey;
/**
* Encryption Key used to encrypt {@link org.atsign.common.Keys.SelfKey}s and the pkam and
* encryption key pairs
* when they are externalised as JSON
*/
- private String selfEncryptKey;
+ String selfEncryptKey;
/**
* This is used to encrypt the symmetric keys that are used to encrypt
@@ -61,136 +74,78 @@ public class AtKeys {
* where the shared with {@link org.atsign.common.AtSign} is this {@link org.atsign.common.AtSign}
*/
- private String encryptPublicKey;
+ String encryptPublicKey;
/**
* This is used to decrypt the symmetric keys that are used to encrypt
* {@link org.atsign.common.Keys.SharedKey}s
* where the shared with {@link org.atsign.common.AtSign} is this {@link org.atsign.common.AtSign}
*/
- private String encryptPrivateKey;
+ String encryptPrivateKey;
/**
* Transient cache of other keys
*/
- private Map cache = new ConcurrentHashMap<>();
+ Map cache = new ConcurrentHashMap<>();
+ /**
+ * @return true if these {link @AtKeys} have enrollment id
+ */
public boolean hasEnrollmentId() {
return enrollmentId != null;
}
- public EnrollmentId getEnrollmentId() {
- return enrollmentId;
- }
-
- public AtKeys setEnrollmentId(EnrollmentId enrollmentId) {
- this.enrollmentId = enrollmentId;
- return this;
- }
-
- public String getSelfEncryptKey() {
- return selfEncryptKey;
- }
-
- public AtKeys setSelfEncryptKey(String key) {
- this.selfEncryptKey = key;
- return this;
- }
-
- public String getApkamPublicKey() {
- return apkamPublicKey;
- }
-
- public AtKeys setApkamPublicKey(String key) {
- this.apkamPublicKey = key;
- return this;
- }
-
- public AtKeys setApkamPublicKey(PublicKey key) {
- return setApkamPublicKey(createStringBase64(key));
- }
-
- public String getApkamPrivateKey() {
- return apkamPrivateKey;
- }
-
- public AtKeys setApkamPrivateKey(String key) {
- this.apkamPrivateKey = key;
- return this;
- }
-
- public AtKeys setApkamPrivateKey(PrivateKey key) {
- return setApkamPrivateKey(createStringBase64(key));
- }
-
- public AtKeys setApkamKeyPair(KeyPair keyPair) {
- setApkamPublicKey(keyPair.getPublic());
- setApkamPrivateKey(keyPair.getPrivate());
- return this;
- }
-
- public boolean hasPkamKeys() {
- return this.apkamPublicKey != null && this.apkamPrivateKey != null;
- }
-
- public AtKeys setEncryptKeyPair(KeyPair keyPair) {
- setEncryptPublicKey(keyPair.getPublic());
- setEncryptPrivateKey(keyPair.getPrivate());
- return this;
- }
-
- public String getEncryptPublicKey() {
- return encryptPublicKey;
- }
-
- public AtKeys setEncryptPublicKey(String key) {
- this.encryptPublicKey = key;
- return this;
- }
-
- public AtKeys setEncryptPublicKey(PublicKey key) {
- return setEncryptPublicKey(createStringBase64(key));
- }
-
- public String getEncryptPrivateKey() {
- return encryptPrivateKey;
- }
-
- public AtKeys setEncryptPrivateKey(String key) {
- this.encryptPrivateKey = key;
- return this;
- }
-
- public AtKeys setEncryptPrivateKey(PrivateKey key) {
- return setEncryptPrivateKey(createStringBase64(key));
- }
-
- public String getApkamSymmetricKey() {
- return apkamSymmetricKey;
- }
-
- public AtKeys setApkamSymmetricKey(String key) {
- this.apkamSymmetricKey = key;
- return this;
+ /**
+ * @return true if these {link @AtKeys} have APKAM private key set
+ */
+ public boolean hasPkamKey() {
+ return this.apkamPrivateKey != null;
}
+ /**
+ * Allows the retrieval of previously put key values from the transient cache.
+ *
+ * @param key for the cached value
+ * @return cached value or null if no entry
+ */
public String get(String key) {
return cache.get(key);
}
+ /**
+ * Allows the storage key values in the transient cache.
+ *
+ * @param key for the cached value
+ * @param value the cached value
+ */
public void put(String key, String value) {
cache.put(key, value);
}
+ /**
+ * @return an immutable map of all the transient cached values
+ */
public Map getCache() {
return Collections.unmodifiableMap(cache);
}
- private static String createStringBase64(PublicKey key) {
- return Base64.getEncoder().encodeToString(key.getEncoded());
+ /**
+ * Builder utility.
+ */
+ public static class AtKeysBuilder {
+
+ public AtKeysBuilder encryptKeyPair(KeyPair keyPair) {
+ return this.encryptPublicKey(createStringBase64(keyPair.getPublic()))
+ .encryptPrivateKey(createStringBase64(keyPair.getPrivate()));
+ }
+
+ public AtKeysBuilder apkamKeyPair(KeyPair keyPair) {
+ return this.apkamPublicKey(createStringBase64(keyPair.getPublic()))
+ .apkamPrivateKey(createStringBase64(keyPair.getPrivate()));
+ }
}
- private static String createStringBase64(PrivateKey key) {
+ private static String createStringBase64(Key key) {
return Base64.getEncoder().encodeToString(key.getEncoded());
}
diff --git a/at_client/src/main/java/org/atsign/client/api/impl/clients/AtClientImpl.java b/at_client/src/main/java/org/atsign/client/api/impl/clients/AtClientImpl.java
index d02c1441..0a97523f 100644
--- a/at_client/src/main/java/org/atsign/client/api/impl/clients/AtClientImpl.java
+++ b/at_client/src/main/java/org/atsign/client/api/impl/clients/AtClientImpl.java
@@ -1,27 +1,25 @@
package org.atsign.client.api.impl.clients;
import static org.atsign.client.api.AtEvents.AtEventType.decryptedUpdateNotification;
+import static org.atsign.client.api.AtKeyNames.toSharedByMeKeyName;
import static org.atsign.client.util.Preconditions.checkNotNull;
+import static org.atsign.common.VerbBuilders.*;
+import static org.atsign.common.VerbBuilders.LookupOperation.all;
+import static org.atsign.common.VerbBuilders.LookupOperation.meta;
import java.io.IOException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.NoSuchAlgorithmException;
-import java.security.NoSuchProviderException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.TimeUnit;
-import javax.crypto.BadPaddingException;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
import lombok.extern.slf4j.Slf4j;
import org.atsign.client.api.AtClient;
import org.atsign.client.api.AtEvents.AtEventBus;
import org.atsign.client.api.AtEvents.AtEventListener;
import org.atsign.client.api.AtEvents.AtEventType;
+import org.atsign.client.api.AtKeyNames;
import org.atsign.client.api.AtKeys;
import org.atsign.client.api.Secondary;
import org.atsign.client.util.EncryptionUtil;
@@ -30,13 +28,11 @@
import org.atsign.common.Keys.PublicKey;
import org.atsign.common.Keys.SelfKey;
import org.atsign.common.Keys.SharedKey;
-import org.atsign.common.VerbBuilders.*;
import org.atsign.common.exceptions.*;
import org.atsign.common.options.GetRequestOptions;
import org.atsign.common.response_models.LookupResponse;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Implementation of an {@link AtClient} which wraps a {@link Secondary}
@@ -45,7 +41,6 @@
@SuppressWarnings({"RedundantThrows", "unused"})
@Slf4j
public class AtClientImpl implements AtClient {
- static final ObjectMapper json = new ObjectMapper();
// Factory method - creates an AtClientImpl with a RemoteSecondary
@@ -142,7 +137,8 @@ public synchronized void handleEvent(AtEventType eventType, Map
try {
// decrypt it with the symmetric key that the other atSign shared with me
- String encryptionKeySharedByOther = getEncryptionKeySharedByOther(SharedKey.fromString(key));
+ SharedKey sk = Keys.sharedKeyBuilder().rawKey(key).build();
+ String encryptionKeySharedByOther = getEncryptionKeySharedByOther(sk);
String decryptedValue =
EncryptionUtil.aesDecryptFromBase64(encryptedValue, encryptionKeySharedByOther, ivNonce);
@@ -150,7 +146,7 @@ public synchronized void handleEvent(AtEventType eventType, Map
newEventData.put("decryptedValue", decryptedValue);
eventBus.publishEvent(decryptedUpdateNotification, newEventData);
} catch (Exception e) {
- log.error("caught exception {} while decrypting received data with key name [{}]", e, key);
+ log.error("caught exception while decrypting received data with key name [{}]", key, e);
}
}
break;
@@ -392,7 +388,7 @@ public void close() throws IOException {
// Synchronous methods which do the actual work
//
private String _get(SharedKey sharedKey) throws AtException {
- if (sharedKey.sharedBy.equals(atSign)) {
+ if (sharedKey.sharedBy().equals(atSign)) {
return _getSharedByMeWithOther(sharedKey);
} else {
return _getSharedByOtherWithMe(sharedKey);
@@ -402,13 +398,11 @@ private String _get(SharedKey sharedKey) throws AtException {
private String _getSharedByMeWithOther(SharedKey sharedKey) throws AtException {
String shareEncryptionKey = getEncryptionKeySharedByMe(sharedKey);
- // fetch local - e.g. if I'm @bob, I would first "llookup:@alice:some.key.name@bob"
- LlookupVerbBuilder commandBuilder = new LlookupVerbBuilder();
- commandBuilder.with(sharedKey, LlookupVerbBuilder.Type.ALL);
- LookupResponse response = getLookupResponse(commandBuilder.build());
+ String command = llookupCommandBuilder().key(sharedKey).operation(all).build();
+ LookupResponse response = getLookupResponse(command);
try {
- return EncryptionUtil.aesDecryptFromBase64(response.data, shareEncryptionKey, response.metaData.ivNonce);
+ return EncryptionUtil.aesDecryptFromBase64(response.data, shareEncryptionKey, response.metaData.ivNonce());
} catch (Exception e) {
throw new AtDecryptionException("Failed to decrypt value with shared encryption key", e);
}
@@ -418,22 +412,21 @@ private String _getSharedByOtherWithMe(SharedKey sharedKey) throws AtException {
String what;
String shareEncryptionKey = getEncryptionKeySharedByOther(sharedKey);
- LookupVerbBuilder commandBuilder = new LookupVerbBuilder();
- commandBuilder.with(sharedKey, LookupVerbBuilder.Type.ALL);
- LookupResponse response = getLookupResponse(commandBuilder.build());
+ String command = lookupCommandBuilder().key(sharedKey).operation(all).build();
+ LookupResponse response = getLookupResponse(command);
what = "decrypt value with shared encryption key";
try {
- return EncryptionUtil.aesDecryptFromBase64(response.data, shareEncryptionKey, response.metaData.ivNonce);
+ return EncryptionUtil.aesDecryptFromBase64(response.data, shareEncryptionKey, response.metaData.ivNonce());
} catch (Exception e) {
throw new AtDecryptionException("Failed to " + what, e);
}
}
private String _put(SharedKey sharedKey, String value) throws AtException {
- if (!this.atSign.equals(sharedKey.sharedBy)) {
+ if (!this.atSign.equals(sharedKey.sharedBy())) {
throw new AtIllegalArgumentException(
- "sharedBy is [" + sharedKey.sharedBy + "] but should be this client's atSign [" + atSign + "]");
+ "sharedBy is [" + sharedKey.sharedBy() + "] but should be this client's atSign [" + atSign + "]");
}
String what = "";
String cipherText;
@@ -443,13 +436,13 @@ private String _put(SharedKey sharedKey, String value) throws AtException {
what = "encrypt value with shared encryption key";
String iv = EncryptionUtil.generateRandomIvBase64(16);
- sharedKey.metadata.ivNonce = iv;
+ sharedKey.updateMissingMetadata(Metadata.builder().ivNonce(iv).build());
cipherText = EncryptionUtil.aesEncryptToBase64(value, shareToEncryptionKey, iv);
} catch (Exception e) {
throw new AtEncryptionException("Failed to " + what, e);
}
- String command = "update" + sharedKey.metadata.toString() + ":" + sharedKey + " " + cipherText;
+ String command = updateCommandBuilder().key(sharedKey).value(cipherText).build();
try {
return secondary.executeCommand(command, true).toString();
@@ -459,7 +452,7 @@ private String _put(SharedKey sharedKey, String value) throws AtException {
}
private String _delete(SharedKey sharedKey) throws AtException {
- String command = "delete:" + sharedKey;
+ String command = deleteCommandBuilder().key(sharedKey).build();
try {
return secondary.executeCommand(command, true).toString();
} catch (IOException e) {
@@ -469,10 +462,7 @@ private String _delete(SharedKey sharedKey) throws AtException {
private String _get(SelfKey key) throws AtException {
// 1. build command
- String command;
- LlookupVerbBuilder builder = new LlookupVerbBuilder();
- builder.with(key, LlookupVerbBuilder.Type.ALL);
- command = builder.build();
+ String command = llookupCommandBuilder().key(key).operation(all).build();
// 2. execute command
LookupResponse fetched = getLookupResponse(command);
@@ -481,37 +471,27 @@ private String _get(SelfKey key) throws AtException {
String decryptedValue;
String encryptedValue = fetched.data;
String selfEncryptionKey = keys.getSelfEncryptKey();
- String iv = fetched.metaData.ivNonce;
- try {
- decryptedValue = EncryptionUtil.aesDecryptFromBase64(encryptedValue, selfEncryptionKey, iv);
- } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException
- | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchProviderException e) {
- throw new AtDecryptionException("Failed to " + command, e);
- }
+ String iv = checkNotNull(fetched.metaData.ivNonce(), "ivNonce is null");
+ decryptedValue = EncryptionUtil.aesDecryptFromBase64(encryptedValue, selfEncryptionKey, iv);
// 4. update metadata. squash the fetchedMetadata with current key.metadata (fetchedMetadata has higher priority)
- key.metadata = Metadata.squash(fetched.metaData, key.metadata);
+ key.overwriteMetadata(fetched.metaData);
return decryptedValue;
}
private String _put(SelfKey selfKey, String value) throws AtException {
// 1. generate dataSignature
- selfKey.metadata.dataSignature = generateSignature(value);
- selfKey.metadata.ivNonce = EncryptionUtil.generateRandomIvBase64(16);
+ Metadata metadata = Metadata.builder()
+ .dataSignature(generateSignature(value))
+ .ivNonce(EncryptionUtil.generateRandomIvBase64(16))
+ .build();
+ selfKey.updateMissingMetadata(metadata);
// 2. encrypt data with self encryption key
- String cipherText;
- try {
- cipherText = EncryptionUtil.aesEncryptToBase64(value, keys.getSelfEncryptKey(), selfKey.metadata.ivNonce);
- } catch (NoSuchPaddingException | NoSuchAlgorithmException | InvalidAlgorithmParameterException
- | InvalidKeyException | IllegalBlockSizeException | BadPaddingException | NoSuchProviderException e) {
- throw new AtEncryptionException("Failed to encrypt value with self encryption key", e);
- }
+ String cipherText = EncryptionUtil.aesEncryptToBase64(value, keys.getSelfEncryptKey(), metadata.ivNonce());
// 3. update secondary
- UpdateVerbBuilder builder = new UpdateVerbBuilder();
- builder.with(selfKey, cipherText);
- String command = builder.build();
+ String command = updateCommandBuilder().key(selfKey).value(cipherText).build();
try {
return secondary.executeCommand(command, true).toString();
} catch (IOException e) {
@@ -521,9 +501,7 @@ private String _put(SelfKey selfKey, String value) throws AtException {
private String _delete(SelfKey key) throws AtException {
// 1. build delete command
- DeleteVerbBuilder builder = new DeleteVerbBuilder();
- builder.with(key);
- String command = builder.build();
+ String command = deleteCommandBuilder().key(key).build();
// 2. run command
try {
@@ -540,25 +518,19 @@ private String _get(PublicKey key) throws AtException {
private String _get(PublicKey key, GetRequestOptions getRequestOptions) throws AtException {
// 1. build command
String command;
- if (atSign.toString().equals(key.sharedBy.toString())) {
- // it's a public key created by this client => llookup
- LlookupVerbBuilder builder = new LlookupVerbBuilder();
- builder.with(key, LlookupVerbBuilder.Type.ALL);
- command = builder.build();
+ if (atSign.equals(key.sharedBy())) {
+ command = llookupCommandBuilder().key(key).operation(all).build();
} else {
- // it's a public key created by another => plookup
- PlookupVerbBuilder builder = new PlookupVerbBuilder();
- builder.with(key, PlookupVerbBuilder.Type.ALL);
- builder.setBypassCache(getRequestOptions != null && getRequestOptions.getBypassCache());
- command = builder.build();
+ boolean bypassCache = getRequestOptions != null && getRequestOptions.getBypassCache();
+ command = plookupCommandBuilder().key(key).bypassCache(bypassCache).operation(all).build();
}
// 2. run the command
LookupResponse fetched = getLookupResponse(command);
// 4. update key object metadata
- key.metadata = Metadata.squash(fetched.metaData, key.metadata);
- key.metadata.isCached = fetched.key.contains("cached:");
+ Metadata metadata = fetched.metaData.toBuilder().isCached(fetched.key.contains("cached:")).build();
+ key.overwriteMetadata(metadata);
// 5. return the AtValue
return fetched.data;
@@ -566,13 +538,11 @@ private String _get(PublicKey key, GetRequestOptions getRequestOptions) throws A
private String _put(PublicKey publicKey, String value) throws AtException {
// 1. generate dataSignature
- publicKey.metadata.dataSignature = generateSignature(value);
+ Metadata metadata = Metadata.builder().dataSignature(generateSignature(value)).build();
+ publicKey.updateMissingMetadata(metadata);
// 2. build command
- String command;
- UpdateVerbBuilder builder = new UpdateVerbBuilder();
- builder.with(publicKey, value);
- command = builder.build();
+ String command = updateCommandBuilder().key(publicKey).value(value).build();
// 3. run command
try {
@@ -584,10 +554,7 @@ private String _put(PublicKey publicKey, String value) throws AtException {
private String _delete(PublicKey key) throws AtException {
// 1. build command
- String command;
- DeleteVerbBuilder builder = new DeleteVerbBuilder();
- builder.with(key);
- command = builder.build();
+ String command = deleteCommandBuilder().key(key).build();
// 2. run command
try {
@@ -626,10 +593,7 @@ private String _put(PublicKey publicKey, byte[] value) throws AtException {
}
private List _getAtKeys(String regex, boolean fetchMetadata) throws AtException {
- ScanVerbBuilder scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setRegex(regex);
- scanVerbBuilder.setShowHidden(true);
- String scanCommand = scanVerbBuilder.build();
+ String scanCommand = scanCommandBuilder().regex(regex).showHidden(true).build();
Response scanRawResponse;
try {
scanRawResponse = executeCommand(scanCommand, true);
@@ -641,10 +605,10 @@ private List _getAtKeys(String regex, boolean fetchMetadata) throws AtExc
List rawArray = scanResponseTransformer.apply(scanRawResponse);
List atKeys = new ArrayList<>();
- for (String atKeyRaw : rawArray) { // eg atKeyRaw == @bob:phone@alice
- AtKey atKey = Keys.fromString(atKeyRaw);
+ for (String atKeyRaw : rawArray) {
+ AtKey atKey = Keys.keyBuilder().rawKey(atKeyRaw).build();
if (fetchMetadata) {
- String llookupCommand = "llookup:meta:" + atKeyRaw;
+ String llookupCommand = llookupCommandBuilder().operation(meta).rawKey(atKeyRaw).build();
Response llookupMetaResponse;
try {
llookupMetaResponse = secondary.executeCommand(llookupCommand, true);
@@ -652,7 +616,9 @@ private List _getAtKeys(String regex, boolean fetchMetadata) throws AtExc
throw new AtSecondaryConnectException("Failed to execute " + llookupCommand, e);
}
try {
- atKey.metadata = Metadata.squash(atKey.metadata, Metadata.fromJson(llookupMetaResponse.getRawDataResponse())); // atKey.metadata has priority over llookupMetaRaw.data
+ // atKey.metadata has priority over llookupMetaRaw.data
+ Metadata responseMetadata = Metadata.fromJson(llookupMetaResponse.getRawDataResponse());
+ atKey.updateMissingMetadata(responseMetadata);
} catch (JsonProcessingException e) {
throw new AtResponseHandlingException("Failed to parse JSON " + llookupMetaResponse.getRawDataResponse(), e);
}
@@ -681,7 +647,7 @@ private LookupResponse getLookupResponse(String command) throws AtException {
// 3. transform the data to a LlookupAllResponse object
LookupResponse fetched;
try {
- fetched = json.readValue(response.getRawDataResponse(), LookupResponse.class);
+ fetched = Json.MAPPER.readValue(response.getRawDataResponse(), LookupResponse.class);
} catch (JsonProcessingException e) {
throw new AtResponseHandlingException("Failed to parse JSON " + response.getRawDataResponse(), e);
}
@@ -689,11 +655,8 @@ private LookupResponse getLookupResponse(String command) throws AtException {
}
private String getEncryptionKeySharedByMe(SharedKey key) throws AtException {
- // llookup:shared_key.bob@alice
Secondary.Response rawResponse;
- String toLookup = "shared_key." + key.sharedWith.withoutPrefix() + atSign;
-
- String command = "llookup:" + toLookup;
+ String command = llookupCommandBuilder().keyName(toSharedByMeKeyName(key.sharedWith())).sharedBy(atSign).build();
try {
rawResponse = secondary.executeCommand(command, false);
} catch (IOException e) {
@@ -709,17 +672,14 @@ private String getEncryptionKeySharedByMe(SharedKey key) throws AtException {
}
}
- // When we stored it, we encrypted it with our encryption public key; so we need to decrypt it now with our encryption private key
- try {
- return EncryptionUtil.rsaDecryptFromBase64(rawResponse.getRawDataResponse(), keys.getEncryptPrivateKey());
- } catch (Exception e) {
- throw new AtDecryptionException("Failed to decrypt " + toLookup, e);
- }
+ // When we stored it, we encrypted it with our encryption public key; so we need to decrypt it now with our
+ // encryption private key
+ return EncryptionUtil.rsaDecryptFromBase64(rawResponse.getRawDataResponse(), keys.getEncryptPrivateKey());
}
private String getEncryptionKeySharedByOther(SharedKey sharedKey) throws AtException {
// Let's see if it's in our in-memory cache
- String sharedSharedKeyName = sharedKey.getSharedSharedKeyName();
+ String sharedSharedKeyName = AtKeyNames.toSharedWithMeKeyName(sharedKey.sharedBy(), sharedKey.sharedWith());
String sharedKeyValue = keys.get(sharedSharedKeyName);
if (sharedKeyValue != null) {
@@ -729,7 +689,7 @@ private String getEncryptionKeySharedByOther(SharedKey sharedKey) throws AtExcep
String what = "";
// Not in memory so now let's try to fetch from remote - e.g. if I'm @bob, lookup:shared_key@alice
- String lookupCommand = "lookup:" + "shared_key" + sharedKey.sharedBy;
+ String lookupCommand = lookupCommandBuilder().keyName(AtKeyNames.SHARED_KEY).sharedBy(sharedKey.sharedBy()).build();
Response rawResponse;
try {
rawResponse = secondary.executeCommand(lookupCommand, true);
@@ -751,9 +711,9 @@ private String getEncryptionKeySharedByOther(SharedKey sharedKey) throws AtExcep
private String createSharedEncryptionKey(SharedKey sharedKey) throws AtException {
// We need their public key
- String theirPublicEncryptionKey = getPublicEncryptionKey(sharedKey.sharedWith);
+ String theirPublicEncryptionKey = getPublicEncryptionKey(sharedKey.sharedWith());
if (theirPublicEncryptionKey == null) {
- throw new AtKeyNotFoundException(" public key " + sharedKey.sharedWith
+ throw new AtKeyNotFoundException(" public key " + sharedKey.sharedWith()
+ " not found but service is running - maybe that AtSign has not yet been onboarded");
}
@@ -762,7 +722,7 @@ private String createSharedEncryptionKey(SharedKey sharedKey) throws AtException
try {
aesKey = EncryptionUtil.generateAESKeyBase64();
} catch (Exception e) {
- throw new AtEncryptionException("Failed to generate AES key for sharing with " + sharedKey.sharedWith, e);
+ throw new AtEncryptionException("Failed to generate AES key for sharing with " + sharedKey.sharedWith(), e);
}
String what = "";
@@ -776,13 +736,22 @@ private String createSharedEncryptionKey(SharedKey sharedKey) throws AtException
String encryptedForUs = EncryptionUtil.rsaEncryptToBase64(aesKey, keys.getEncryptPublicKey());
what = "save encrypted shared key for us";
- secondary.executeCommand("update:" + "shared_key." + sharedKey.sharedWith.withoutPrefix() + sharedKey.sharedBy
- + " " + encryptedForUs, true);
+ String updateForUs = updateCommandBuilder()
+ .keyName(toSharedByMeKeyName(sharedKey.sharedWith()))
+ .sharedBy(sharedKey.sharedBy())
+ .value(encryptedForUs)
+ .build();
+ secondary.executeCommand(updateForUs, true);
what = "save encrypted shared key for them";
- long ttr = TimeUnit.HOURS.toMillis(24);
- secondary.executeCommand("update:ttr:" + ttr + ":" + sharedKey.sharedWith + ":shared_key" + sharedKey.sharedBy
- + " " + encryptedForOther, true);
+ String updateForOther = updateCommandBuilder()
+ .keyName(AtKeyNames.SHARED_KEY)
+ .sharedBy(sharedKey.sharedBy())
+ .sharedWith(sharedKey.sharedWith())
+ .ttr(TimeUnit.HOURS.toMillis(24))
+ .value(encryptedForOther)
+ .build();
+ secondary.executeCommand(updateForOther, true);
} catch (Exception e) {
throw new AtEncryptionException("Failed to " + what, e);
}
@@ -791,10 +760,9 @@ private String createSharedEncryptionKey(SharedKey sharedKey) throws AtException
}
private String getPublicEncryptionKey(AtSign sharedWith) throws AtException {
- // plookup:publickey@alice
Secondary.Response rawResponse;
- String command = "plookup:publickey" + sharedWith;
+ String command = plookupCommandBuilder().keyName(AtKeyNames.PUBLIC_ENCRYPT).sharedBy(sharedWith).build();
try {
rawResponse = secondary.executeCommand(command, false);
} catch (IOException e) {
diff --git a/at_client/src/main/java/org/atsign/client/api/impl/connections/AtMonitorConnection.java b/at_client/src/main/java/org/atsign/client/api/impl/connections/AtMonitorConnection.java
index 43575ffb..dc80d9a5 100644
--- a/at_client/src/main/java/org/atsign/client/api/impl/connections/AtMonitorConnection.java
+++ b/at_client/src/main/java/org/atsign/client/api/impl/connections/AtMonitorConnection.java
@@ -15,6 +15,7 @@
import org.atsign.common.AtSign;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.atsign.common.Json;
/**
* A {@link AtMonitorConnection} represents a connection to an AtServer which,
@@ -24,7 +25,8 @@
*/
@Slf4j
public class AtMonitorConnection extends AtSecondaryConnection implements Runnable {
- private static final ObjectMapper mapper = new ObjectMapper();
+
+ private static final ObjectMapper mapper = Json.MAPPER;
private long _lastReceivedTime = 0;
diff --git a/at_client/src/main/java/org/atsign/client/cli/AbstractCli.java b/at_client/src/main/java/org/atsign/client/cli/AbstractCli.java
index 4a1f6542..fa40866f 100644
--- a/at_client/src/main/java/org/atsign/client/cli/AbstractCli.java
+++ b/at_client/src/main/java/org/atsign/client/cli/AbstractCli.java
@@ -1,10 +1,10 @@
package org.atsign.client.cli;
import static org.atsign.client.util.Preconditions.checkNotNull;
+import static org.atsign.common.VerbBuilders.*;
import java.io.File;
import java.io.IOException;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
@@ -17,14 +17,12 @@
import org.atsign.client.api.impl.events.SimpleAtEventBus;
import org.atsign.client.util.AuthUtil;
import org.atsign.client.util.KeysUtil;
-import org.atsign.client.util.TypedString;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
+import org.atsign.common.Json;
import org.atsign.common.exceptions.AtSecondaryNotFoundException;
-import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
-import com.fasterxml.jackson.databind.ObjectMapper;
import picocli.CommandLine.ITypeConverter;
import picocli.CommandLine.Option;
@@ -118,15 +116,17 @@ protected static File getAtKeysFile(File keysFile, AtSign atSign) {
}
protected static void checkAtServerMatchesAtSign(AtSecondaryConnection connection, AtSign atSign) throws IOException {
- if (!matchDataJsonList(connection.executeCommand("scan")).contains("signing_publickey" + atSign)) {
+ String command = scanCommandBuilder().build();
+ if (!matchDataJsonList(connection.executeCommand(command)).contains("signing_publickey" + atSign)) {
// TODO: understand precisely what this means (observed in Dart SDK)
throw new IllegalStateException("TBC");
}
}
- protected static void deleteKey(AtSecondaryConnection connection, String key) {
+ protected static void deleteKey(AtSecondaryConnection connection, String rawKey) {
try {
- match(connection.executeCommand("delete:" + key), DATA_INT);
+ String command = deleteCommandBuilder().rawKey(rawKey).build();
+ match(connection.executeCommand(command), DATA_INT);
} catch (IOException e) {
throw new RuntimeException(e);
}
@@ -175,35 +175,9 @@ protected static String resolveSecondaryUrl(AtSign atSign, String rootUrl, int r
throw ex;
}
- protected static String encodeKeyValuesAsJson(Object... nameValuePairs) throws Exception {
- return encodeAsJson(toObjectMap(nameValuePairs));
- }
-
- protected static Map toObjectMap(Object... nameValuePairs) {
- if ((nameValuePairs.length % 2) != 0) {
- throw new IllegalArgumentException("odd number of parameters");
- }
- Map map = new HashMap<>();
- for (int i = 0; i < nameValuePairs.length; i++) {
- String key = nameValuePairs[i].toString();
- Object value = nameValuePairs[++i];
- if (value instanceof TypedString) {
- map.put(key, value.toString());
- } else {
- map.put(key, value);
- }
- }
- return map;
- }
-
- protected static String encodeAsJson(Map map) throws JsonProcessingException {
- ObjectMapper objectMapper = new ObjectMapper();
- return objectMapper.writeValueAsString(map);
- }
-
protected static Map decodeJsonMapOfStrings(String json) {
try {
- return new ObjectMapper().readValue(json, new TypeReference>() {});
+ return Json.MAPPER.readValue(json, new TypeReference>() {});
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -211,7 +185,7 @@ protected static Map decodeJsonMapOfStrings(String json) {
protected static Map decodeJsonMapOfObjects(String json) {
try {
- return new ObjectMapper().readValue(json, new TypeReference>() {});
+ return Json.MAPPER.readValue(json, new TypeReference>() {});
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -219,7 +193,7 @@ protected static Map decodeJsonMapOfObjects(String json) {
protected static List decodeJsonList(String json) {
try {
- return new ObjectMapper().readValue(json, new TypeReference>() {});
+ return Json.MAPPER.readValue(json, new TypeReference>() {});
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -227,7 +201,7 @@ protected static List decodeJsonList(String json) {
public static List decodeJsonListOfStrings(String json) {
try {
- return new ObjectMapper().readValue(json, new TypeReference>() {});
+ return Json.MAPPER.readValue(json, new TypeReference>() {});
} catch (Exception e) {
throw new RuntimeException(e);
}
diff --git a/at_client/src/main/java/org/atsign/client/cli/Activate.java b/at_client/src/main/java/org/atsign/client/cli/Activate.java
index 8d783389..9284a1e1 100644
--- a/at_client/src/main/java/org/atsign/client/cli/Activate.java
+++ b/at_client/src/main/java/org/atsign/client/cli/Activate.java
@@ -1,17 +1,10 @@
package org.atsign.client.cli;
-import static java.util.Collections.singletonList;
-import static java.util.Collections.singletonMap;
-import static org.atsign.client.util.EncryptionUtil.aesDecryptFromBase64;
-import static org.atsign.client.util.EncryptionUtil.aesEncryptToBase64;
-import static org.atsign.client.util.EncryptionUtil.generateAESKeyBase64;
-import static org.atsign.client.util.EncryptionUtil.generateRSAKeyPair;
-import static org.atsign.client.util.EncryptionUtil.generateRandomIvBase64;
-import static org.atsign.client.util.EncryptionUtil.rsaDecryptFromBase64;
-import static org.atsign.client.util.EncryptionUtil.rsaEncryptToBase64;
+import static org.atsign.client.util.EncryptionUtil.*;
import static org.atsign.client.util.EnrollmentId.createEnrollmentId;
import static org.atsign.client.util.KeysUtil.saveKeys;
import static org.atsign.client.util.Preconditions.checkNotNull;
+import static org.atsign.common.VerbBuilders.*;
import java.io.File;
import java.io.IOException;
@@ -23,6 +16,7 @@
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
+import org.atsign.client.api.AtKeyNames;
import org.atsign.client.api.AtKeys;
import org.atsign.client.api.impl.connections.AtSecondaryConnection;
import org.atsign.client.util.AuthUtil;
@@ -30,6 +24,7 @@
import org.atsign.client.util.KeysUtil;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
+import org.atsign.common.VerbBuilders;
import org.atsign.common.exceptions.AtUnauthenticatedException;
import picocli.CommandLine;
@@ -208,7 +203,7 @@ public EnrollmentId onboard(AtSecondaryConnection connection) throws Exception {
keys,
ensureNotNull(appName, DEFAULT_FIRST_APP),
ensureNotNull(deviceName, DEFAULT_FIRST_DEVICE));
- keys.setEnrollmentId(enrollmentId);
+ keys = keys.toBuilder().enrollmentId(enrollmentId).build();
authenticateWithApkam(connection, atSign, keys);
saveKeys(keys, file);
storeEncryptPublicKey(connection, atSign, keys);
@@ -236,7 +231,10 @@ public List list(String status) throws Exception {
}
public List list(AtSecondaryConnection connection, String status) throws Exception {
- String command = "enroll:list:" + encodeAsJson(singletonMap("enrollmentStatusFilter", singletonList(status)));
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.list)
+ .status(status)
+ .build();
return matchDataJsonMapOfObjects(connection.executeCommand(command), true).keySet().stream()
.map(Activate::inferEnrollmentId)
.collect(Collectors.toList());
@@ -265,27 +263,35 @@ public void approve(AtSecondaryConnection connection, EnrollmentId enrollmentId)
String key = fetchApkamSymmetricKey(connection, enrollmentId);
String privateKeyIv = generateRandomIvBase64(16);
String encryptPrivateKey = aesEncryptToBase64(keys.getEncryptPrivateKey(), key, privateKeyIv);
- String selfKeyIv = generateRandomIvBase64(16);
- String selfEncryptKey = aesEncryptToBase64(keys.getSelfEncryptKey(), key, selfKeyIv);
- String json = encodeKeyValuesAsJson("enrollmentId", enrollmentId,
- "encryptedDefaultEncryptionPrivateKey", encryptPrivateKey,
- "encPrivateKeyIV", privateKeyIv,
- "encryptedDefaultSelfEncryptionKey", selfEncryptKey,
- "selfEncKeyIV", selfKeyIv);
-
- Map response = matchDataJsonMapOfStrings(connection.executeCommand("enroll:approve:" + json));
+ String selfEncryptKeyIv = generateRandomIvBase64(16);
+ String selfEncryptKey = aesEncryptToBase64(keys.getSelfEncryptKey(), key, selfEncryptKeyIv);
+
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.approve)
+ .enrollmentId(enrollmentId)
+ .encryptPrivateKey(encryptPrivateKey)
+ .encryptPrivateKeyIv(privateKeyIv)
+ .selfEncryptKey(selfEncryptKey)
+ .selfEncryptKeyIv(selfEncryptKeyIv)
+ .build();
+
+ Map response = matchDataJsonMapOfStrings(connection.executeCommand(command));
if (!"approved".equals(response.get("status"))) {
throw new RuntimeException("status is not approved : " + response.get("status"));
}
}
private String fetchApkamSymmetricKey(AtSecondaryConnection connection, EnrollmentId enrollmentId) throws Exception {
- String command = "enroll:fetch:" + encodeKeyValuesAsJson("enrollmentId", enrollmentId);
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.fetch)
+ .enrollmentId(enrollmentId)
+ .build();
Map request = matchDataJsonMapOfObjects(connection.executeCommand(command));
if (!"pending".equals(request.get("status"))) {
throw new RuntimeException("status is not pending : " + request.get("status"));
}
- String encryptedApkamSymmetricKey = (String) request.get("encryptedAPKAMSymmetricKey");
+ String encryptedApkamSymmetricKey =
+ (String) request.get(VerbBuilders.EnrollParameters.ENCRYPTED_APKAM_SYMMETRIC_KEY);
return rsaDecryptFromBase64(encryptedApkamSymmetricKey, keys.getEncryptPrivateKey());
}
@@ -351,7 +357,8 @@ public String otp(AtSecondaryConnection connection) throws IOException, AtExcept
File file = checkExists(getAtKeysFile(keysFile, atSign));
AtKeys keys = KeysUtil.loadKeys(file);
authenticateWithApkam(connection, atSign, keys);
- return match(connection.executeCommand("otp:get"), DATA_NON_WHITESPACE);
+ String command = otpCommandBuilder().build();
+ return match(connection.executeCommand(command), DATA_NON_WHITESPACE);
}
public List scan() throws Exception {
@@ -361,7 +368,11 @@ public List scan() throws Exception {
}
public List scan(AtSecondaryConnection connection) throws Exception {
- return matchDataJsonListOfStrings(connection.executeCommand("scan:showHidden:true .*"));
+ String command = scanCommandBuilder()
+ .showHidden(true)
+ .regex(".*")
+ .build();
+ return matchDataJsonListOfStrings(connection.executeCommand(command));
}
private void singleArgEnrollAction(AtSecondaryConnection connection,
@@ -369,7 +380,10 @@ private void singleArgEnrollAction(AtSecondaryConnection connection,
EnrollmentId enrollmentId,
String expectedStatus)
throws Exception {
- String command = "enroll:" + action + ":" + encodeKeyValuesAsJson("enrollmentId", enrollmentId);
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.valueOf(action))
+ .enrollmentId(enrollmentId)
+ .build();
Map map = matchDataJsonMapOfStrings(connection.executeCommand(command));
if (!expectedStatus.equals(map.get("status"))) {
throw new RuntimeException("status is not " + expectedStatus + " : " + map.get("status"));
@@ -387,11 +401,13 @@ private static EnrollmentId enroll(AtSecondaryConnection connection,
String appName,
String deviceName)
throws Exception {
- String json = encodeKeyValuesAsJson(
- "appName", appName,
- "deviceName", deviceName,
- "apkamPublicKey", keys.getApkamPublicKey());
- Map response = matchDataJsonMapOfStrings(connection.executeCommand("enroll:request:" + json));
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.request)
+ .appName(appName)
+ .deviceName(deviceName)
+ .apkamPublicKey(keys.getApkamPublicKey())
+ .build();
+ Map response = matchDataJsonMapOfStrings(connection.executeCommand(command));
if (!response.get("status").equals("approved")) {
throw new RuntimeException("enroll request failed, expected status approved : " + response);
}
@@ -400,22 +416,28 @@ private static EnrollmentId enroll(AtSecondaryConnection connection,
protected static void storeEncryptPublicKey(AtSecondaryConnection connection, AtSign atSign, AtKeys keys)
throws IOException {
- match(connection.executeCommand("update:public:publickey" + atSign + " " + keys.getEncryptPublicKey()), DATA_INT);
+ String command = updateCommandBuilder()
+ .sharedBy(atSign)
+ .keyName(AtKeyNames.PUBLIC_ENCRYPT)
+ .isPublic(true)
+ .value(keys.getEncryptPublicKey())
+ .build();
+ match(connection.executeCommand(command), DATA_INT);
}
protected static void deleteCramSecret(AtSecondaryConnection connection) {
- deleteKey(connection, "privatekey:at_secret");
+ deleteKey(connection, AtKeyNames.PRIVATE_AT_SECRET);
}
protected static AtKeys generateAtKeys(boolean generateEncryptionKeyPair) throws NoSuchAlgorithmException {
- AtKeys keys = new AtKeys()
- .setSelfEncryptKey(generateAESKeyBase64())
- .setApkamKeyPair(generateRSAKeyPair())
- .setApkamSymmetricKey(generateAESKeyBase64());
+ AtKeys.AtKeysBuilder builder = AtKeys.builder()
+ .selfEncryptKey(generateAESKeyBase64())
+ .apkamKeyPair(generateRSAKeyPair())
+ .apkamSymmetricKey(generateAESKeyBase64());
if (generateEncryptionKeyPair) {
- keys.setEncryptKeyPair(generateRSAKeyPair());
+ builder.encryptKeyPair(generateRSAKeyPair());
}
- return keys;
+ return builder.build();
}
public EnrollmentId enroll() throws Exception {
@@ -425,28 +447,34 @@ public EnrollmentId enroll() throws Exception {
}
public EnrollmentId enroll(AtSecondaryConnection connection) throws Exception {
- String publicKey = matchDataString(connection.executeCommand("lookup:publickey" + atSign));
+ String command = lookupCommandBuilder()
+ .keyName(AtKeyNames.PUBLIC_ENCRYPT)
+ .sharedBy(atSign)
+ .build();
+ String publicKey = matchDataString(connection.executeCommand(command));
File file = keysFile;
if (!overwriteKeysFile) {
checkNotExists(file);
}
- AtKeys keys = generateAtKeys(false);
- keys.setEncryptPublicKey(publicKey);
- keys.setEnrollmentId(enroll(connection, keys));
+ AtKeys keys = generateAtKeys(false).toBuilder()
+ .encryptPublicKey(publicKey)
+ .build();
+ enrollmentId = enroll(connection, keys);
+ keys = keys.toBuilder().enrollmentId(enrollmentId).build();
KeysUtil.saveKeys(keys, keysFile);
return keys.getEnrollmentId();
}
private EnrollmentId enroll(AtSecondaryConnection connection, AtKeys keys) throws Exception {
- Map args = toObjectMap("appName", appName,
- "deviceName", deviceName,
- "apkamPublicKey", keys.getApkamPublicKey(),
- "encryptedAPKAMSymmetricKey",
- rsaEncryptToBase64(keys.getApkamSymmetricKey(), keys.getEncryptPublicKey()),
- "otp", otp,
- "namespaces", namespaces,
- "apkamKeysExpiryInMillis", 0);
- String command = "enroll:request:" + encodeAsJson(args);
+ String command = enrollCommandBuilder()
+ .operation(VerbBuilders.EnrollOperation.request)
+ .appName(appName)
+ .deviceName(deviceName)
+ .apkamPublicKey(keys.getApkamPublicKey())
+ .apkamSymmetricKey(rsaEncryptToBase64(keys.getApkamSymmetricKey(), keys.getEncryptPublicKey()))
+ .otp(otp)
+ .namespaces(namespaces)
+ .build();
Map response = matchDataJsonMapOfStrings(connection.executeCommand(command));
if ("pending".equals(response.get("status"))) {
return EnrollmentId.createEnrollmentId(response.get("enrollmentId"));
@@ -464,8 +492,12 @@ public void complete() throws Exception {
public void complete(AtSecondaryConnection connection) throws Exception {
AtKeys keys = KeysUtil.loadKeys(keysFile);
authenticate(connection);
- keys.setSelfEncryptKey(keysGetDecrypted(connection, atSign, keys, "default_self_enc_key"));
- keys.setEncryptPrivateKey(keysGetDecrypted(connection, atSign, keys, "default_enc_private_key"));
+ String selfEncryptKey = keysGetDecrypted(connection, atSign, keys, AtKeyNames.SELF_ENCRYPTION_KEY);
+ String encryptPrivateKey = keysGetDecrypted(connection, atSign, keys, AtKeyNames.ENCRYPT_PRIVATE_KEY);
+ keys = keys.toBuilder()
+ .selfEncryptKey(selfEncryptKey)
+ .encryptPrivateKey(encryptPrivateKey)
+ .build();
KeysUtil.saveKeys(keys, keysFile);
}
@@ -499,8 +531,11 @@ private static String keysGetDecrypted(AtSecondaryConnection connection,
AtKeys keys,
String keyConstant)
throws Exception {
- EnrollmentId enrollmentId = keys.getEnrollmentId();
- String command = "keys:get:keyName:" + enrollmentId + "." + keyConstant + ".__manage" + atSign;
+ String rawKeyName = keys.getEnrollmentId() + "." + keyConstant + ".__manage" + atSign;
+ String command = keysCommandBuilder()
+ .operation(VerbBuilders.KeysOperation.get)
+ .keyName(rawKeyName)
+ .build();
return decryptEncryptedKey(connection.executeCommand(command), keys.getApkamSymmetricKey());
}
diff --git a/at_client/src/main/java/org/atsign/client/cli/Delete.java b/at_client/src/main/java/org/atsign/client/cli/Delete.java
index 1dcaf01e..c52372ab 100644
--- a/at_client/src/main/java/org/atsign/client/cli/Delete.java
+++ b/at_client/src/main/java/org/atsign/client/cli/Delete.java
@@ -1,13 +1,13 @@
package org.atsign.client.cli;
-import lombok.extern.slf4j.Slf4j;
import org.atsign.client.api.AtClient;
import org.atsign.client.api.AtKeys;
import org.atsign.client.util.KeysUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
+import lombok.extern.slf4j.Slf4j;
+
/**
* A command-line interface half-example half-utility to delete something that was previously shared
*/
@@ -32,8 +32,10 @@ public static void main(String[] args) throws Exception {
try (AtClient atClient = AtClient.withRemoteSecondary(rootUrl, atSign, keys, true)) {
- Keys.SharedKey key = new KeyBuilders.SharedKeyBuilder(atSign, otherAtSign)
- .key(keyName)
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(atSign)
+ .sharedWith(otherAtSign)
+ .name(keyName)
.build();
String response = atClient.delete(key).get();
diff --git a/at_client/src/main/java/org/atsign/client/cli/Get.java b/at_client/src/main/java/org/atsign/client/cli/Get.java
index 90d17994..afc23334 100644
--- a/at_client/src/main/java/org/atsign/client/cli/Get.java
+++ b/at_client/src/main/java/org/atsign/client/cli/Get.java
@@ -1,13 +1,13 @@
package org.atsign.client.cli;
-import lombok.extern.slf4j.Slf4j;
import org.atsign.client.api.AtClient;
import org.atsign.client.api.AtKeys;
import org.atsign.client.util.KeysUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
+import lombok.extern.slf4j.Slf4j;
+
/**
* A command-line interface half-example half-utility to get something that was shared by another
* atSign
@@ -32,8 +32,10 @@ public static void main(String[] args) throws Exception {
try (AtClient atClient = AtClient.withRemoteSecondary(rootUrl, atSign, keys, true)) {
- Keys.SharedKey key = new KeyBuilders.SharedKeyBuilder(otherAtSign, atSign)
- .key(keyName)
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(otherAtSign)
+ .sharedWith(atSign)
+ .name(keyName)
.build();
String response = atClient.get(key).get();
diff --git a/at_client/src/main/java/org/atsign/client/cli/Scan.java b/at_client/src/main/java/org/atsign/client/cli/Scan.java
index 7ea83033..74ec7013 100644
--- a/at_client/src/main/java/org/atsign/client/cli/Scan.java
+++ b/at_client/src/main/java/org/atsign/client/cli/Scan.java
@@ -64,7 +64,7 @@ private static void printKeys(List keys, PrintStream out) {
out.println("atKeys: {");
for (int i = 0; i < keys.size(); i++) {
AtKey key = keys.get(i);
- out.println(" " + i + ": " + (key.metadata.isCached ? "cached:" : "") + key);
+ out.println(" " + i + ": " + (key.metadata().isCached() ? "cached:" : "") + key);
}
out.println("}");
}
@@ -72,36 +72,36 @@ private static void printKeys(List keys, PrintStream out) {
private static void printKeyInfo(AtKey key, PrintStream out) {
out.println("======================");
out.println("Full KeyName: " + key.toString());
- out.println("KeyName: " + key.name);
- out.println("Namespace: " + key.getNamespace());
- out.println("SharedBy: " + key.sharedBy.atSign);
- out.println("SharedWith: " + (key.sharedWith != null ? key.sharedWith.atSign : "null"));
+ out.println("KeyName: " + key.nameWithoutNamespace());
+ out.println("Namespace: " + key.namespace());
+ out.println("SharedBy: " + key.sharedBy());
+ out.println("SharedWith: " + (key.sharedWith() != null ? key.sharedWith() : "null"));
out.println("KeyType: " + key.getClass().toString().split("\\$")[1]);
out.println("Metadata -------------------");
- printKeyMetadata(key.metadata, out);
+ printKeyMetadata(key.metadata(), out);
out.println("======================");
out.println();
}
private static void printKeyMetadata(Metadata metadata, PrintStream out) {
- out.println("ttl: " + metadata.ttl);
- out.println("ttb: " + metadata.ttb);
- out.println("ttr: " + metadata.ttr);
- out.println("ccd: " + metadata.ccd);
- out.println("availableAt: " + (metadata.availableAt != null ? metadata.availableAt.toString() : "null"));
- out.println("expiresAt: " + (metadata.expiresAt != null ? metadata.expiresAt.toString() : "null"));
- out.println("refreshAt: " + (metadata.refreshAt != null ? metadata.refreshAt.toString() : "null"));
- out.println("createdAt: " + (metadata.createdAt != null ? metadata.createdAt.toString() : "null"));
- out.println("updatedAt: " + (metadata.updatedAt != null ? metadata.updatedAt.toString() : "null"));
- out.println("dataSignature: " + metadata.dataSignature);
- out.println("sharedKeyStatus: " + metadata.sharedKeyStatus);
- out.println("isPublic: " + metadata.isPublic);
- out.println("isEncrypted: " + metadata.isEncrypted);
- out.println("isHidden: " + metadata.isHidden);
- out.println("namespaceAware: " + metadata.namespaceAware);
- out.println("isBinary: " + metadata.isBinary);
- out.println("isCached: " + metadata.isCached);
- out.println("sharedKeyEnc: " + metadata.sharedKeyEnc);
- out.println("pubKeyCS: " + metadata.pubKeyCS);
+ out.println("ttl: " + metadata.ttl());
+ out.println("ttb: " + metadata.ttb());
+ out.println("ttr: " + metadata.ttr());
+ out.println("ccd: " + metadata.ccd());
+ out.println("availableAt: " + (metadata.availableAt() != null ? metadata.availableAt().toString() : "null"));
+ out.println("expiresAt: " + (metadata.expiresAt() != null ? metadata.expiresAt().toString() : "null"));
+ out.println("refreshAt: " + (metadata.refreshAt() != null ? metadata.refreshAt().toString() : "null"));
+ out.println("createdAt: " + (metadata.createdAt() != null ? metadata.createdAt().toString() : "null"));
+ out.println("updatedAt: " + (metadata.updatedAt() != null ? metadata.updatedAt().toString() : "null"));
+ out.println("dataSignature: " + metadata.dataSignature());
+ out.println("sharedKeyStatus: " + metadata.sharedKeyStatus());
+ out.println("isPublic: " + metadata.isPublic());
+ out.println("isEncrypted: " + metadata.isEncrypted());
+ out.println("isHidden: " + metadata.isHidden());
+ out.println("namespaceAware: " + metadata.namespaceAware());
+ out.println("isBinary: " + metadata.isBinary());
+ out.println("isCached: " + metadata.isCached());
+ out.println("sharedKeyEnc: " + metadata.sharedKeyEnc());
+ out.println("pubKeyCS: " + metadata.pubKeyCS());
}
}
diff --git a/at_client/src/main/java/org/atsign/client/cli/Share.java b/at_client/src/main/java/org/atsign/client/cli/Share.java
index a95aed67..f0866d23 100644
--- a/at_client/src/main/java/org/atsign/client/cli/Share.java
+++ b/at_client/src/main/java/org/atsign/client/cli/Share.java
@@ -4,7 +4,6 @@
import org.atsign.client.api.AtKeys;
import org.atsign.client.util.KeysUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
import lombok.extern.slf4j.Slf4j;
@@ -33,10 +32,12 @@ public static void main(String[] args) throws Exception {
AtKeys keys = KeysUtil.loadKeys(atSign);
try (AtClient atClient = AtClient.withRemoteSecondary(rootUrl, atSign, keys, true)) {
-
- Keys.SharedKey key = new KeyBuilders.SharedKeyBuilder(atSign, otherAtSign)
- .key(keyName)
- .cache(ttr, true)
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(atSign)
+ .sharedWith(otherAtSign)
+ .name(keyName)
+ .ccd(true)
+ .ttr((long) ttr)
.build();
String response = atClient.put(key, toShare).get();
diff --git a/at_client/src/main/java/org/atsign/client/util/AtClientValidation.java b/at_client/src/main/java/org/atsign/client/util/AtClientValidation.java
index c651bc2b..88f98ce7 100644
--- a/at_client/src/main/java/org/atsign/client/util/AtClientValidation.java
+++ b/at_client/src/main/java/org/atsign/client/util/AtClientValidation.java
@@ -5,65 +5,13 @@
import org.atsign.client.api.Secondary;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.Keys.AtKey;
-import org.atsign.common.Metadata;
import org.atsign.common.exceptions.AtIllegalArgumentException;
-import org.atsign.common.exceptions.AtInvalidAtKeyException;
import org.atsign.common.exceptions.AtSecondaryConnectException;
/**
* Utility class with key string validation methods
*/
public class AtClientValidation {
- // TODO Lots of atServer-address-finding going on here. Need a caching finder.
- // TODO Change all of these static methods.
- /**
- * @param keyName // e.g. "test" (not the fullKeyName like "public:test@bob")
- */
- public static void validateKeyName(String keyName) throws AtException {
- // key cannot be null and cannot be the empty string (length 0)
- if (keyName == null || keyName.isEmpty()) {
- throw new AtInvalidAtKeyException("Key cannot be null or empty");
- }
-
- // key cannot have spaces
- if (keyName.contains(" ")) {
- throw new AtInvalidAtKeyException("Key cannot have spaces");
- }
-
- // Key cannot contain @
- if (keyName.contains("@")) {
- throw new AtInvalidAtKeyException("Key cannot contain @");
- }
- }
-
- /**
- *
- * @param metadata Metadata object to validate
- * @throws AtException if metadata is null or has invalid values
- */
- public static void validateMetadata(Metadata metadata) throws AtException {
- // null check
- if (metadata == null) {
- throw new AtInvalidAtKeyException("Metadata cannot be null");
- }
-
- // validate ttl
- if (metadata.ttl == null || (metadata.ttl < 0)) {
- throw new AtInvalidAtKeyException("ttl cannot be null and cannot be negative");
- }
-
- // validate ttb
- if (metadata.ttb == null || metadata.ttb < 0) {
- throw new AtInvalidAtKeyException("ttb cannot be null and cannot be negative");
- }
-
- // validate ttr
- if (metadata.ttr == null || metadata.ttr < -1) {
- throw new AtInvalidAtKeyException("ttr cannot be null and cannot be < -1");
- }
-
- }
/**
* Checks if an atSign exists on a root server
@@ -88,35 +36,4 @@ public static void atSignExists(AtSign atSign, String rootUrl) throws AtExceptio
}
}
- /**
- * Validate if an AtKey object is valid 1. checks if atKey.name is a valid keyName 2. checks if
- * atKey.metadata has valid values 3. checks if atKey.sharedWith atSign is valid (if it exists)
- *
- * @param atKey AtKey object created usually through KeyBuilders
- * @param rootUrl RootURL of the Root Server (e.g. "root.atsign.org:64")
- * @throws AtException if the AtKey is invalid
- */
- public static void validateAtKey(AtKey atKey, String rootUrl) throws AtException {
- // 1. null check
- if (atKey == null) {
- throw new AtIllegalArgumentException("AtKey cannot be null");
- }
-
- if (rootUrl == null || rootUrl.isEmpty()) {
- throw new AtIllegalArgumentException("RootURL cannot be null or empty");
- }
-
- // 2. validate key name
- validateKeyName(atKey.name);
-
- // 3. validate metadata
- validateMetadata(atKey.metadata);
-
- // 4. validate sharedWith exists
- if (atKey.sharedWith != null) {
- atSignExists(atKey.sharedWith, rootUrl);
- }
-
- }
-
}
diff --git a/at_client/src/main/java/org/atsign/client/util/AuthUtil.java b/at_client/src/main/java/org/atsign/client/util/AuthUtil.java
index 58e278e5..7f1de8d0 100644
--- a/at_client/src/main/java/org/atsign/client/util/AuthUtil.java
+++ b/at_client/src/main/java/org/atsign/client/util/AuthUtil.java
@@ -1,5 +1,7 @@
package org.atsign.client.util;
+import static org.atsign.common.VerbBuilders.*;
+
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
@@ -31,7 +33,7 @@ public class AuthUtil {
*/
public void authenticateWithCram(AtSecondaryConnection connection, AtSign atSign, String cramSecret)
throws AtException, IOException {
- String fromResponse = connection.executeCommand("from:" + atSign);
+ String fromResponse = connection.executeCommand(fromCommandBuilder().atSign(atSign).build());
if (!fromResponse.startsWith("data:")) {
throw new AtUnauthenticatedException("Invalid response to 'from': " + fromResponse);
}
@@ -44,7 +46,7 @@ public void authenticateWithCram(AtSecondaryConnection connection, AtSign atSign
throw new AtEncryptionException("Failed to generate cramDigest", e);
}
- String cramResponse = connection.executeCommand("cram:" + cramDigest);
+ String cramResponse = connection.executeCommand(cramCommandBuilder().digest(cramDigest).build());
if (!cramResponse.startsWith("data:success")) {
throw new AtUnauthenticatedException("CRAM command failed: " + cramResponse);
}
@@ -61,11 +63,11 @@ public void authenticateWithCram(AtSecondaryConnection connection, AtSign atSign
*/
public void authenticateWithPkam(AtConnection connection, AtSign atSign, AtKeys keys)
throws AtException, IOException {
- if (!keys.hasPkamKeys()) {
+ if (!keys.hasPkamKey()) {
throw new AtClientConfigException("Cannot authenticate with PKAM: Keys file does not contain PKAM keys");
}
- String fromResponse = connection.executeCommand("from:" + atSign);
+ String fromResponse = connection.executeCommand(fromCommandBuilder().atSign(atSign).build());
String dataPrefix = "data:";
if (!fromResponse.startsWith(dataPrefix)) {
@@ -87,15 +89,15 @@ public void authenticateWithPkam(AtConnection connection, AtSign atSign, AtKeys
throw new AtEncryptionException("Failed to create SHA256 signature");
}
- StringBuilder builder = new StringBuilder().append("pkam");
+ PkamCommandBuilder builder = pkamCommandBuilder();
if (keys.hasEnrollmentId()) {
- builder.append(":signingAlgo:").append(EncryptionUtil.SIGNING_ALGO_RSA)
- .append(":hashingAlgo:").append(EncryptionUtil.HASHING_ALGO_SHA256)
- .append(":enrollmentId:").append(keys.getEnrollmentId());
+ builder.signingAlgo(EncryptionUtil.SIGNING_ALGO_RSA);
+ builder.hashingAlgo(EncryptionUtil.HASHING_ALGO_SHA256);
+ builder.enrollmentId(keys.getEnrollmentId());
}
- builder.append(":").append(signature);
+ builder.digest(signature);
- String pkamResponse = connection.executeCommand(builder.toString());
+ String pkamResponse = connection.executeCommand(builder.build());
if (!pkamResponse.startsWith("data:success")) {
throw new AtUnauthenticatedException("PKAM command failed: " + pkamResponse);
diff --git a/at_client/src/main/java/org/atsign/client/util/EncryptionUtil.java b/at_client/src/main/java/org/atsign/client/util/EncryptionUtil.java
index fcaaa4fd..68a7e8f2 100644
--- a/at_client/src/main/java/org/atsign/client/util/EncryptionUtil.java
+++ b/at_client/src/main/java/org/atsign/client/util/EncryptionUtil.java
@@ -12,6 +12,8 @@
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
+import org.atsign.common.exceptions.AtDecryptionException;
+import org.atsign.common.exceptions.AtEncryptionException;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
/**
@@ -28,19 +30,35 @@ public class EncryptionUtil {
}
public static String aesEncryptToBase64(String clearText, String keyBase64, String ivNonce)
- throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
- Cipher cipher = createAesCipher(Cipher.ENCRYPT_MODE, keyBase64, ivNonce);
- byte[] encrypted = cipher.doFinal(clearText.getBytes());
- return Base64.getEncoder().encodeToString(encrypted);
+ throws AtEncryptionException {
+ try {
+ Cipher cipher = createAesCipher(Cipher.ENCRYPT_MODE, keyBase64, ivNonce);
+ byte[] encrypted = cipher.doFinal(clearText.getBytes());
+ return Base64.getEncoder().encodeToString(encrypted);
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | BadPaddingException | IllegalBlockSizeException
+ | NoSuchPaddingException | InvalidKeyException | InvalidAlgorithmParameterException e) {
+ throw new AtEncryptionException("AES encryption failed", e);
+ }
}
- public static String aesDecryptFromBase64(String cipherTextBase64, String keyBase64, String ivNonce)
- throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException, NoSuchProviderException {
- Cipher cipher = createAesCipher(Cipher.DECRYPT_MODE, keyBase64, ivNonce);
- byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(cipherTextBase64));
- return new String(decrypted);
+ /**
+ * Decrypts the text using AES {@link Cipher}
+ *
+ * @param text base64 encoded text to decrypt
+ * @param key base64 encoded AES key to use
+ * @param iv base64 encoded initialization vector to use
+ * @return decrypted text
+ * @throws AtDecryptionException with underlying cause
+ */
+ public static String aesDecryptFromBase64(String text, String key, String iv) throws AtDecryptionException {
+ try {
+ Cipher cipher = createAesCipher(Cipher.DECRYPT_MODE, key, iv);
+ byte[] decrypted = cipher.doFinal(Base64.getDecoder().decode(text));
+ return new String(decrypted);
+ } catch (NoSuchAlgorithmException | NoSuchProviderException | NoSuchPaddingException | InvalidKeyException
+ | InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException e) {
+ throw new AtDecryptionException("AES decryption failed", e);
+ }
}
public static KeyPair generateRSAKeyPair() throws NoSuchAlgorithmException {
@@ -57,27 +75,33 @@ public static String generateAESKeyBase64() throws NoSuchAlgorithmException {
}
public static String rsaDecryptFromBase64(String cipherTextBase64, String privateKeyBase64)
- throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException {
- PrivateKey privateKey = _privateKeyFromBase64(privateKeyBase64);
- Cipher decryptCipher = Cipher.getInstance("RSA");
- decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
- byte[] decoded = Base64.getDecoder().decode(cipherTextBase64.getBytes(StandardCharsets.UTF_8));
- byte[] decryptedMessageBytes = decryptCipher.doFinal(decoded);
-
- return new String(decryptedMessageBytes, StandardCharsets.UTF_8);
+ throws AtDecryptionException {
+ try {
+ PrivateKey privateKey = _privateKeyFromBase64(privateKeyBase64);
+ Cipher decryptCipher = Cipher.getInstance("RSA");
+ decryptCipher.init(Cipher.DECRYPT_MODE, privateKey);
+ byte[] decoded = Base64.getDecoder().decode(cipherTextBase64.getBytes(StandardCharsets.UTF_8));
+ byte[] decryptedMessageBytes = decryptCipher.doFinal(decoded);
+ return new String(decryptedMessageBytes, StandardCharsets.UTF_8);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException
+ | IllegalBlockSizeException | BadPaddingException e) {
+ throw new AtDecryptionException("RSA decryption failed", e);
+ }
}
public static String rsaEncryptToBase64(String clearText, String publicKeyBase64)
- throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchPaddingException, InvalidKeyException,
- IllegalBlockSizeException, BadPaddingException {
- PublicKey publicKey = _publicKeyFromBase64(publicKeyBase64);
- Cipher encryptCipher = Cipher.getInstance("RSA");
- encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
- byte[] clearTextBytes = clearText.getBytes(StandardCharsets.UTF_8);
- byte[] encryptedMessageBytes = encryptCipher.doFinal(clearTextBytes);
-
- return Base64.getEncoder().encodeToString(encryptedMessageBytes);
+ throws AtEncryptionException {
+ try {
+ PublicKey publicKey = _publicKeyFromBase64(publicKeyBase64);
+ Cipher encryptCipher = Cipher.getInstance("RSA");
+ encryptCipher.init(Cipher.ENCRYPT_MODE, publicKey);
+ byte[] clearTextBytes = clearText.getBytes(StandardCharsets.UTF_8);
+ byte[] encryptedMessageBytes = encryptCipher.doFinal(clearTextBytes);
+ return Base64.getEncoder().encodeToString(encryptedMessageBytes);
+ } catch (NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException
+ | IllegalBlockSizeException | BadPaddingException e) {
+ throw new AtEncryptionException("RSA encryption failed", e);
+ }
}
public static String signSHA256RSA(String value, String privateKeyBase64)
diff --git a/at_client/src/main/java/org/atsign/client/util/KeyStringUtil.java b/at_client/src/main/java/org/atsign/client/util/KeyStringUtil.java
deleted file mode 100644
index 5c88eaeb..00000000
--- a/at_client/src/main/java/org/atsign/client/util/KeyStringUtil.java
+++ /dev/null
@@ -1,238 +0,0 @@
-package org.atsign.client.util;
-
-import static org.atsign.client.util.Preconditions.checkNotNull;
-
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Utility class which parses a key string and can be used to extract key characteristics.
- * Specifically:
- *
- * {@link KeyType}
- * namespace
- * unqualfied key name
- * "shared by" {@link org.atsign.common.AtSign}
- * "shared with" {@link org.atsign.common.AtSign}
- * whether key is cached on the {@link org.atsign.client.api.Secondary}
- * whether key is hidden
- *
- */
-public class KeyStringUtil {
-
- private static final Pattern NAMESPACE_QUALIFIED_KEY_NAME = Pattern.compile("^(?!shared_key)(.+)\\.([^.]+)$");
-
- /**
- * Different types of keys in the Atsign Platform
- */
- public enum KeyType {
- PUBLIC_KEY, // PublicKey
- SHARED_KEY, // SharedKey
- SELF_KEY, // SelfKey
- PRIVATE_HIDDEN_KEY, // PrivateHiddenKey
- ;
- }
-
- private String _fullKeyName; // e.g. "public:publickey@alice"
-
- private String _keyName; // should never be null (otherwise it's an error)
- private KeyType _keyType; // see enum above, should never be null (otherwise it's an error)
- private String _namespace; // nullable (some keys don't have namespaces)
-
- private String _sharedBy; // should never be null (all keys have a sharedBy atsign)
- private String _sharedWith; // nullable
-
- private boolean _isCached; // true if key starts with "cached:"
- private boolean _isHidden; // true if key contains "_"
-
- /**
- * Constructor
- *
- * @param fullKeyName full key name e.g. "public:publickey@bob"
- */
- public KeyStringUtil(String fullKeyName) {
- this._fullKeyName = fullKeyName;
- this._evaluate(fullKeyName);
- }
-
- /**
- * Returns the full key name (originally passed into the constructor)
- *
- * @return fullKeyName (what was originally passed into the constructor)
- */
- public String getFullKeyName() {
- return this._fullKeyName;
- }
-
- /**
- * Returns the key name (e.g. "publickey" from "public:publickey@alice")
- * This value is evaluated from the private _evaluate method that is called in the constructor
- *
- * @return the key name
- */
- public String getKeyName() {
- return this._keyName;
- }
-
- /**
- * Returns the namespace of a key (no implementation yet)
- *
- * @return the namespace from a key (e.g. "mospherepro" from "file_1.mospherepro@alice")
- */
- public String getNamespace() { // no namespace implementation in _evaluate
- return this._namespace;
- }
-
- /**
- * Returns the key type enum of the key type evaluated from the private _evaluate method
- *
- * @return KeyStringUtil.KeyType (e.g. KeyStringUtil.KeyType.PUBLIC_KEY)
- */
- public KeyType getKeyType() {
- return this._keyType;
- }
-
- /**
- * Returns the sharedBy atSign that is evlauated from the _evaluate private method.
- *
- * @return the sharedBy atSign String (e.g. "@alice" from "test@alice")
- */
- public String getSharedBy() {
- return this._sharedBy;
- }
-
- /**
- * Returns the sharedWith atSign that is evlauated from the _evaluate private method.
- *
- * @return the sharedWith atSign String (e.g. "@bob" from "@bob:test@alice")
- */
- public String getSharedWith() {
- return this._sharedWith;
- }
-
- /**
- * Returns true if the key is cached (e.g. "cached:public:publickey@alice")
- *
- * @return true if the fullKeyName begins with "cached:"
- */
- public boolean isCached() {
- return this._isCached;
- }
-
- /**
- * Returns true if the key is hidden by default in scan
- *
- * @return true if the fullKeyName begins with "_"
- */
- public boolean isHidden() {
- return this._isHidden;
- }
-
- /**
- * Given the fullKeyName, this method will evaluate all of the properties that can be exactracted
- * from the
- * fullKeyName. Example: fullKeyName "test@bob" will evaluate sharedBy to be "@bob" and keyName to
- * be "test"
- *
- * @param fullKeyName the fullKeyName to be evaluated (e.g. "test@bob")
- */
- private void _evaluate(String fullKeyName) {
- // Examples:
- // (1) PublicKey == public:signing_publickey@smoothalligator
- // (2) PublicKey (cached) == cached:public:publickey@denise
- // (3) SharedKey == @abbcservicesinc:shared_key@smoothalligator
- // (4) SharedKey (cached) == cached:@smoothalligator:shared_key@abbcservicesinc
- // (5) PrivateHiddenKey == _latestnotificationid.fourballcorporate9@smoothalligator
- // (6) SelfKey == shared_key.wildgreen@smoothalligator
- // (7) SelfKey == @smoothalligator:lemon@smoothalligator
- String[] split1 = fullKeyName.split(":");
- // split1 results
- // 1 == {"public", "signing_publickey@smoothalligator"} [len 2]
- // 2 == {"cached", "public", "publickey@denise"} [len 3]
- // 3 == {"@abbcservicesinc", "shared_key@smoothalligator"} [len 2]
- // 4 == {"cached", "@smoothalligator", "shared_key@abbcservicesinc"} [len 3]
- // 5 == {"_latestnotificationid.fourballcorporate9@smoothalligator"} [len 1]
- // 6 == {"shared_key.wildgreen@smoothalligator"} [len 1]
-
-
- if (split1.length > 1) {
- // must be scenarios 1, 2, 3, 4,
-
- // PublicKey check
- if (split1[0].equals("public") || (split1[0].equals("cached") && split1[1].equals("public"))) {
- // scenario 1 and 2,, it's a public key!
- _keyType = KeyType.PUBLIC_KEY;
- } else if (split1[0].equals("private") || split1[0].equals("privatekey")) {
- _keyType = KeyType.PRIVATE_HIDDEN_KEY;
- _isHidden = true;
- }
-
- if (split1[0].startsWith("@") || split1[1].startsWith("@")) {
- // scenario 3 and 4,, it is a SharedKey!
- if (_keyType == null) {
- _keyType = KeyType.SHARED_KEY; // don't want to overwrite the above checks
- }
- if (split1[0].startsWith("@")) {
- _sharedWith = split1[0].substring(1);
- } else {
- _sharedWith = split1[1].substring(1);
- }
- }
-
- String[] split2 = split1[split1.length - 1].split("@");
- // 1 == {"signing_publickey", "smoothalligator"}
- // 2 == {"publickey", "denise"}
- // 3 == {"shared_key", "smoothalligator"}
- // 4 == {"shared_key", "abbcservicesinc"}
- _keyName = checkNotNull(split2[0], "key name is null");
- _sharedBy = checkNotNull(split2[1], "shared by is null");
-
- // PublicKey and SharedKey can be cacheable!
- if (split1[0].equals("cached")) {
- _isCached = true;
- }
-
- // _sharedBy == _sharedWith => it's a SelfKey
- if (_sharedBy.equals(_sharedWith)) {
- _keyType = KeyType.SELF_KEY;
- }
-
- } else {
- // must be scenarios 5 and 6
- if (split1[0].startsWith("_")) {
- _keyType = KeyType.PRIVATE_HIDDEN_KEY;
- } else {
- _keyType = KeyType.SELF_KEY;
- }
-
- String[] split2 = split1[0].split("@");
- // 5 == {"_latestnotificationid.fourballcorporate9", "smoothalligator"}
- // 6 == {"shared_key.wildgreen", "smoothalligator"}
- _keyName = checkNotNull(split2[0], "key name is null");
- _sharedBy = checkNotNull(split2[1], "shared by is null");
-
- }
-
- Matcher matcher = createNamespaceQualifiedKeyNameMatcher(_keyName);
- if (matcher.matches()) {
- _keyName = matcher.group(1);
- _namespace = matcher.group(2);
- } else {
- _namespace = null;
- }
-
- if (_sharedBy != null) {
- _sharedBy = "@" + _sharedBy; // add atSign in front
- }
- if (_sharedWith != null) {
- _sharedWith = "@" + _sharedWith; // add atSign in front
- }
- if (!_isHidden) {
- _isHidden = _keyName.startsWith("_");
- }
- }
-
- public static Matcher createNamespaceQualifiedKeyNameMatcher(String s) {
- return NAMESPACE_QUALIFIED_KEY_NAME.matcher(s);
- }
-}
diff --git a/at_client/src/main/java/org/atsign/client/util/KeysUtil.java b/at_client/src/main/java/org/atsign/client/util/KeysUtil.java
index 7c80a6a8..b5a1bd8d 100644
--- a/at_client/src/main/java/org/atsign/client/util/KeysUtil.java
+++ b/at_client/src/main/java/org/atsign/client/util/KeysUtil.java
@@ -12,13 +12,16 @@
import java.util.Map;
import java.util.TreeMap;
+import com.fasterxml.jackson.core.JsonProcessingException;
import lombok.extern.slf4j.Slf4j;
import org.atsign.client.api.AtKeys;
import org.atsign.common.AtSign;
+import org.atsign.common.Json;
import org.atsign.common.exceptions.AtClientConfigException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
+import org.atsign.common.exceptions.AtDecryptionException;
/**
* Utility class for loading a saving {@link AtKeys} from the file system
@@ -28,7 +31,7 @@ public class KeysUtil {
static private final String EMPTY_IV = Base64.getEncoder().encodeToString(new byte[16]);
- private static final ObjectMapper MAPPER = new ObjectMapper();
+ private static final ObjectMapper MAPPER = Json.MAPPER;
private static final TypeReference> STRING_MAP_TYPE = new TypeReference<>() {};
@@ -80,7 +83,7 @@ public static AtKeys loadKeys(AtSign atSign) throws AtClientConfigException {
public static AtKeys loadKeys(File file) throws AtClientConfigException {
try {
- return setAtKeysFromJson(new AtKeys(), Files.readString(file.toPath()));
+ return createAtKeysFromJson(Files.readString(file.toPath()));
} catch (IOException e) {
throw new AtClientConfigException("failed to read " + file, e);
}
@@ -141,30 +144,31 @@ private static String getAsJson(AtKeys keys) {
}
}
- private static AtKeys setAtKeysFromJson(AtKeys keys, String json) {
+ private static AtKeys createAtKeysFromJson(String json) throws AtClientConfigException {
try {
Map map = MAPPER.readValue(json, STRING_MAP_TYPE);
String version = map.getOrDefault(VERSION_KEY, VERSION_1);
if (version.equals(VERSION_1)) {
- setAtKeysVersion1(keys, map);
+ return createAtKeysVersion1(map);
} else {
- throw new RuntimeException("unsupported version of atKeys json : " + version);
+ throw new AtClientConfigException("unsupported version of AtKeys json : " + version);
}
- } catch (Exception e) {
- throw new RuntimeException(e);
+ } catch (JsonProcessingException | AtDecryptionException e) {
+ throw new AtClientConfigException("failed to create AtKeys from json", e);
}
- return keys;
}
- private static void setAtKeysVersion1(AtKeys keys, Map map) throws Exception {
- keys.setSelfEncryptKey(mapGet(map, SELF_ENCRYPT_KEY));
- keys.setEnrollmentId(mapGetEnrollmentId(map, ENROLLMENT_ID));
- keys.setApkamSymmetricKey(mapGet(map, APKAM_SYMMETRIC_KEY));
-
- keys.setApkamPublicKey(mapGetDecrypted(map, PKAM_PUBLIC_KEY, keys.getSelfEncryptKey()));
- keys.setApkamPrivateKey(mapGetDecrypted(map, PKAM_PRIVATE_KEY, keys.getSelfEncryptKey()));
- keys.setEncryptPublicKey(mapGetDecrypted(map, ENCRYPT_PUBLIC_KEY, keys.getSelfEncryptKey()));
- keys.setEncryptPrivateKey(mapGetDecrypted(map, ENCRYPT_PRIVATE_KEY, keys.getSelfEncryptKey()));
+ private static AtKeys createAtKeysVersion1(Map map) throws AtDecryptionException {
+ String selfEncryptKey = mapGet(map, SELF_ENCRYPT_KEY);
+ return AtKeys.builder()
+ .selfEncryptKey(selfEncryptKey)
+ .enrollmentId(mapGetEnrollmentId(map, ENROLLMENT_ID))
+ .apkamSymmetricKey(mapGet(map, APKAM_SYMMETRIC_KEY))
+ .apkamPublicKey(mapGetDecrypted(map, PKAM_PUBLIC_KEY, selfEncryptKey))
+ .apkamPrivateKey(mapGetDecrypted(map, PKAM_PRIVATE_KEY, selfEncryptKey))
+ .encryptPublicKey(mapGetDecrypted(map, ENCRYPT_PUBLIC_KEY, selfEncryptKey))
+ .encryptPrivateKey(mapGetDecrypted(map, ENCRYPT_PRIVATE_KEY, selfEncryptKey))
+ .build();
}
private static void mapPut(Map map, String key, String value) {
@@ -194,7 +198,8 @@ private static String mapGet(Map map, String key) {
return map.get(key);
}
- private static String mapGetDecrypted(Map map, String key, String decryptKey) throws Exception {
+ private static String mapGetDecrypted(Map map, String key, String decryptKey)
+ throws AtDecryptionException {
String value = map.get(key);
return value != null ? aesDecryptFromBase64(value, decryptKey, EMPTY_IV) : null;
}
diff --git a/at_client/src/main/java/org/atsign/client/util/Preconditions.java b/at_client/src/main/java/org/atsign/client/util/Preconditions.java
index 2447796a..7d07b074 100644
--- a/at_client/src/main/java/org/atsign/client/util/Preconditions.java
+++ b/at_client/src/main/java/org/atsign/client/util/Preconditions.java
@@ -2,6 +2,8 @@
import java.io.File;
import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
/**
* Basic precondition helpers (we could use something like guava but we want to limit dependencies)
@@ -10,7 +12,7 @@ public class Preconditions {
public static T checkNotNull(T instance, String message) {
if (instance == null) {
- throw new RuntimeException(message);
+ throw new IllegalArgumentException(message);
}
return instance;
}
@@ -19,6 +21,45 @@ public static T checkNotNull(T instance) {
return checkNotNull(instance, "null");
}
+ public static void checkNull(Object instance, String message) {
+ if (instance != null) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+
+ public static void checkAllNull(String message, Object... instances) {
+ for (int i = 0; i < instances.length; i++) {
+ if (instances[i] != null) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+ }
+
+ public static Matcher checkMatches(String s, Pattern pattern, String message) {
+ Matcher matcher = pattern.matcher(s);
+ if (!matcher.matches()) {
+ throw new IllegalArgumentException(message);
+ }
+ return matcher;
+ }
+
+ public static String checkNotBlank(String s) {
+ return checkNotBlank(s, "blank");
+ }
+
+ public static String checkNotBlank(String s, String message) {
+ if (s == null || s.isBlank()) {
+ throw new IllegalArgumentException(message);
+ }
+ return s;
+ }
+
+ public static void checkTrue(boolean bool, String message) {
+ if (!bool) {
+ throw new IllegalArgumentException(message);
+ }
+ }
+
public static File checkFile(File f, Predicate predicate, String message) {
if (!predicate.test(f)) {
throw new IllegalArgumentException(message);
diff --git a/at_client/src/main/java/org/atsign/client/util/RegisterUtil.java b/at_client/src/main/java/org/atsign/client/util/RegisterUtil.java
index 12079e52..8b932cfd 100644
--- a/at_client/src/main/java/org/atsign/client/util/RegisterUtil.java
+++ b/at_client/src/main/java/org/atsign/client/util/RegisterUtil.java
@@ -18,6 +18,7 @@
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
+import org.atsign.common.Json;
import org.atsign.common.exceptions.AtRegistrarException;
import com.fasterxml.jackson.databind.ObjectMapper;
@@ -26,7 +27,8 @@
* Utility class for obtaining a new {@link AtSign}
*/
public class RegisterUtil {
- ObjectMapper objectMapper = new ObjectMapper();
+
+ ObjectMapper objectMapper = Json.MAPPER;
/**
* Calls API to get atsigns which are ready to be claimed. Returns a free atsign.
diff --git a/at_client/src/main/java/org/atsign/common/AtSign.java b/at_client/src/main/java/org/atsign/common/AtSign.java
index a335dfc7..2a3b1eea 100644
--- a/at_client/src/main/java/org/atsign/common/AtSign.java
+++ b/at_client/src/main/java/org/atsign/common/AtSign.java
@@ -1,65 +1,40 @@
package org.atsign.common;
-/**
- * The identity of people, systems and devices in the Atsign Platform
- */
-public class AtSign {
- public final String atSign;
- private final String withoutPrefix;
+import org.atsign.client.util.Preconditions;
+import org.atsign.client.util.TypedString;
- public AtSign(String atSign) {
- if (atSign == null || atSign.trim().isEmpty()) {
- throw new IllegalArgumentException("atSign may not be null or empty");
- }
- this.atSign = formatAtSign(atSign);
-
- if ("@".equals(atSign)) {
- throw new IllegalArgumentException("'" + atSign + "' is not a valid atSign");
- }
+/**
+ * The identity of a person or system in the Atsign Platform
+ */
+public class AtSign extends TypedString {
- this.withoutPrefix = this.atSign.substring(1);
+ public AtSign(String s) {
+ super(formatAtSign(s));
}
public String withoutPrefix() {
- return withoutPrefix;
- }
-
- @Override
- public String toString() {
- return atSign;
+ return toString().substring(1);
}
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- AtSign atSign1 = (AtSign) o;
-
- return atSign.equals(atSign1.atSign);
- }
-
- @Override
- public int hashCode() {
- return atSign.hashCode();
+ /**
+ * Factory method
+ *
+ * @param s the string representation of the Atsign (can be with our without @ prefix)
+ * @return null is s is null or blank, otherwise the corresponding {@link AtSign} for s
+ */
+ public static AtSign createAtSign(String s) {
+ return s != null && !s.isBlank() ? new AtSign(s) : null;
}
/**
- * Returns a formatted atSign
+ * Returns a formatted atSign, ensuring that there is an @ prefix
*
- * @param atSignStr e.g. "@bob"
- * @return formatted atSign (e.g. "alice " {@code -->} "@alice")
+ * @param s prefix or unprefixed atsign
+ * @return prefixed atsign
*/
- public static String formatAtSign(String atSignStr) {
- atSignStr = atSignStr.trim();
- if (!atSignStr.startsWith("@")) {
- atSignStr = "@" + atSignStr;
- }
- return atSignStr;
+ public static String formatAtSign(String s) {
+ String result = Preconditions.checkNotNull(s).trim();
+ return result.startsWith("@") ? result : "@" + s;
}
-
}
diff --git a/at_client/src/main/java/org/atsign/common/Json.java b/at_client/src/main/java/org/atsign/common/Json.java
new file mode 100644
index 00000000..658e83ad
--- /dev/null
+++ b/at_client/src/main/java/org/atsign/common/Json.java
@@ -0,0 +1,52 @@
+package org.atsign.common;
+
+import java.io.IOException;
+import java.time.OffsetDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+
+/**
+ * Utility class for JSON encoding / decoding
+ */
+public class Json {
+
+ public static final ObjectMapper MAPPER = objectMapper(false);
+
+ private static ObjectMapper objectMapper(boolean isStrict) {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, isStrict);
+ SimpleModule module = new SimpleModule();
+ module.addDeserializer(OffsetDateTime.class, new AtStringDateTimeDeserializer());
+ mapper.registerModule(module);
+ return mapper;
+ }
+
+ /**
+ * Jackson serializer for DateTime strings
+ */
+ private static class AtStringDateTimeDeserializer extends StdDeserializer {
+
+ protected AtStringDateTimeDeserializer() {
+ super((Class>) null);
+ }
+
+ static final DateTimeFormatter dateTimeFormatter =
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS'Z'").withZone(ZoneId.of("UTC"));
+
+ @Override
+ public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
+ throws IOException {
+ String dateString = jsonParser.getText();
+ ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, dateTimeFormatter);
+ return zonedDateTime.toOffsetDateTime();
+ }
+ }
+}
diff --git a/at_client/src/main/java/org/atsign/common/KeyBuilders.java b/at_client/src/main/java/org/atsign/common/KeyBuilders.java
deleted file mode 100644
index ec36c292..00000000
--- a/at_client/src/main/java/org/atsign/common/KeyBuilders.java
+++ /dev/null
@@ -1,321 +0,0 @@
-package org.atsign.common;
-
-import static org.atsign.common.Keys.AtKey;
-import static org.atsign.common.Keys.PrivateHiddenKey;
-import static org.atsign.common.Keys.PublicKey;
-import static org.atsign.common.Keys.SelfKey;
-import static org.atsign.common.Keys.SharedKey;
-import static org.atsign.common.Keys.defaultAtSign;
-
-import org.atsign.common.exceptions.AtInvalidAtKeyException;
-
-/**
- * Parent class for key builders
- */
-@SuppressWarnings({"unused", "UnusedReturnValue"})
-public class KeyBuilders {
-
- /**
- * Base interface for builders
- */
- public interface KeyBuilder {
- KeyBuilder timeToLive(int ttl);
-
- KeyBuilder timeToBirth(int ttb);
-
- Keys.AtKey build();
-
- void validate() throws AtException;
-
- KeyBuilder namespace(String namespace);
- }
-
- /**
- * Base key builder
- */
- public static abstract class BaseKeyBuilder {
- AtKey _atKey;
-
- /// Set simple key without any namespace. For example "phone", "email" etc...
- /// This is required.
- public BaseKeyBuilder key(String key) {
- key = key.trim();
- _atKey.name = key;
- return this;
- }
-
- /// Each app should write to a specific namespace.
- /// This is required, unless the key already includes some '.' delimiters
- public BaseKeyBuilder namespace(String namespace) {
- namespace = namespace != null ? namespace.trim() : null;
- _atKey.setNamespace(namespace);
- return this;
- }
-
- /// Set this value to set an expiry to a key in milliseconds.
- /// Time until expiry
- public BaseKeyBuilder timeToLive(int ttl) {
- _atKey.metadata.ttl = ttl;
- return this;
- }
-
- /// Set this value to set time after which the key should be available in milliseconds.
- /// Time until availability
- public BaseKeyBuilder timeToBirth(int ttb) {
- _atKey.metadata.ttb = ttb;
- return this;
- }
-
- /// Returns an instance of AtKey
- public Keys.AtKey build() throws AtException {
- // Validate if the data is set properly
- validate();
-
- return _atKey;
- }
-
- /// Validates AtKey and throws Exception for a given issue
- public void validate() throws AtException {
- if (_atKey.name == null || _atKey.name.isEmpty()) {
- throw new AtInvalidAtKeyException("Key cannot be empty");
- }
-
- // We only need to check namespace if the key already doesn't include a namespace
- if (!_atKey.name.contains(".")) {
- if (_atKey.getNamespace() == null || _atKey.getNamespace().isEmpty()) {
- throw new AtInvalidAtKeyException("Namespace cannot be empty");
- }
- }
- }
- }
-
- /**
- * Builder class for cacheable keys.
- */
- public static abstract class CachedKeyBuilder extends BaseKeyBuilder {
- /**
- *
- * Cacheable keys are cached on the recipient AtSign's secondary server when the
- * ttr metadata value is set to a value greater than zero.
- * TTR denotes the time to refresh the cached key. Accepts an integer value
- * which represents the time units in seconds.
- * CCD denotes the cascade delete. Accepts a boolean value. When set to true, deletes
- * the cached key when corresponding key is deleted. When set to false, the cached key remains
- * when corresponding key is deleted.
- *
- */
- public CachedKeyBuilder cache(int ttr, boolean ccd) {
- _atKey.metadata.ttr = ttr;
- _atKey.metadata.ccd = ccd;
- _atKey.metadata.isCached = (ttr != 0);
- return this;
- }
- }
-
- /**
- * Builder for "public keys" in the AtSign Platform
- */
- public static class PublicKeyBuilder extends CachedKeyBuilder implements KeyBuilder {
- public PublicKeyBuilder() {
- this(defaultAtSign);
- }
-
- public PublicKeyBuilder(AtSign sharedBy) {
- _atKey = new PublicKey(sharedBy);
- _atKey.metadata.isPublic = true;
- _atKey.metadata.isHidden = false;
- }
-
- @Override
- public PublicKeyBuilder key(String key) {
- super.key(key);
- return this;
- }
-
- @Override
- public PublicKeyBuilder namespace(String namespace) {
- super.namespace(namespace);
- return this;
- }
-
- @Override
- public PublicKeyBuilder timeToLive(int ttl) {
- super.timeToLive(ttl);
- return this;
- }
-
- @Override
- public PublicKeyBuilder timeToBirth(int ttb) {
- super.timeToBirth(ttb);
- return this;
- }
-
- @Override
- public PublicKey build() {
- return (PublicKey) _atKey;
- }
-
- @Override
- public PublicKeyBuilder cache(int ttr, boolean ccd) {
- super.cache(ttr, ccd);
- return this;
- }
- }
-
- /**
- * Builder for "shared keys" in the AtSign Platform
- */
- public static class SharedKeyBuilder extends CachedKeyBuilder implements KeyBuilder {
- public SharedKeyBuilder(AtSign sharedWith) {
- this(defaultAtSign, sharedWith);
- }
-
- public SharedKeyBuilder(AtSign sharedBy, AtSign sharedWith) {
- _atKey = new SharedKey(sharedBy, sharedWith);
- _atKey.metadata.isPublic = false;
- _atKey.metadata.isHidden = false;
- }
-
- /// Accepts a string which represents an atSign for the key is created.
- void sharedWith(AtSign sharedWith) {
- _atKey.sharedWith = sharedWith;
- }
-
- @Override
- public SharedKeyBuilder key(String key) {
- super.key(key);
- return this;
- }
-
- @Override
- public SharedKeyBuilder namespace(String namespace) {
- super.namespace(namespace);
- return this;
- }
-
- @Override
- public SharedKeyBuilder timeToLive(int ttl) {
- super.timeToLive(ttl);
- return this;
- }
-
- @Override
- public SharedKeyBuilder timeToBirth(int ttb) {
- super.timeToBirth(ttb);
- return this;
- }
-
- @Override
- public SharedKey build() {
- return (SharedKey) _atKey;
- }
-
- @Override
- public SharedKeyBuilder cache(int ttr, boolean ccd) {
- super.cache(ttr, ccd);
- return this;
- }
-
- @Override
- public void validate() throws AtException {
- //Call AbstractKeyBuilder validate method to perform the common validations.
- super.validate();
- if (_atKey.sharedWith == null || _atKey.sharedWith.toString().isEmpty()) {
- throw new AtInvalidAtKeyException("sharedWith cannot be empty");
- }
- }
- }
-
- /**
- * Builder for "self keys" in the AtSign Platform
- */
- public static class SelfKeyBuilder extends BaseKeyBuilder implements KeyBuilder {
- public SelfKeyBuilder() {
- this(defaultAtSign);
- }
-
- public SelfKeyBuilder(AtSign sharedBy) {
- this(sharedBy, null);
- }
-
- public SelfKeyBuilder(AtSign sharedBy, AtSign sharedWith) {
- _atKey = new SelfKey(sharedBy, sharedWith);
- _atKey.metadata.isPublic = false;
- _atKey.metadata.isHidden = false;
- }
-
- @Override
- public SelfKeyBuilder key(String key) {
- super.key(key);
- return this;
- }
-
- @Override
- public SelfKeyBuilder namespace(String namespace) {
- super.namespace(namespace);
- return this;
- }
-
- @Override
- public SelfKeyBuilder timeToLive(int ttl) {
- super.timeToLive(ttl);
- return this;
- }
-
- @Override
- public SelfKeyBuilder timeToBirth(int ttb) {
- super.timeToBirth(ttb);
- return this;
- }
-
- @Override
- public SelfKey build() {
- return (SelfKey) _atKey;
- }
- }
-
- /**
- * Builder for "private hidden keys" in the AtSign Platform
- */
- public static class PrivateHiddenKeyBuilder extends BaseKeyBuilder {
- public PrivateHiddenKeyBuilder() {
- this(defaultAtSign);
- }
-
- public PrivateHiddenKeyBuilder(AtSign sharedBy) {
- _atKey = new PrivateHiddenKey(sharedBy);
- _atKey.metadata.isHidden = true;
- _atKey.metadata.isPublic = false;
- }
-
- @Override
- public PrivateHiddenKeyBuilder key(String key) {
- super.key(key);
- return this;
- }
-
- @Override
- public PrivateHiddenKeyBuilder namespace(String namespace) {
- super.namespace(namespace);
- return this;
- }
-
- @Override
- public PrivateHiddenKeyBuilder timeToLive(int ttl) {
- super.timeToLive(ttl);
- return this;
- }
-
- @Override
- public PrivateHiddenKeyBuilder timeToBirth(int ttb) {
- super.timeToBirth(ttb);
- return this;
- }
-
- @Override
- public PrivateHiddenKey build() {
- return (PrivateHiddenKey) _atKey;
- }
- }
-
-}
diff --git a/at_client/src/main/java/org/atsign/common/Keys.java b/at_client/src/main/java/org/atsign/common/Keys.java
index 723510b3..1c88d0d7 100644
--- a/at_client/src/main/java/org/atsign/common/Keys.java
+++ b/at_client/src/main/java/org/atsign/common/Keys.java
@@ -1,72 +1,147 @@
package org.atsign.common;
-import org.atsign.client.api.Secondary;
-import org.atsign.client.util.KeyStringUtil;
-import org.atsign.client.util.KeyStringUtil.KeyType;
-import org.atsign.common.exceptions.MalformedKeyException;
+import static org.atsign.client.util.Preconditions.*;
+import static org.atsign.common.AtSign.createAtSign;
+import static org.atsign.common.Metadata.*;
-import com.fasterxml.jackson.core.JsonProcessingException;
+import java.util.List;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.function.Predicate;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import lombok.Builder;
+import lombok.Getter;
+import lombok.experimental.Accessors;
/**
* Parent class for key classes in the Atsign Platform
*/
@SuppressWarnings("unused")
public abstract class Keys {
- public static AtSign defaultAtSign;
+
+ private static final Metadata PUBLIC_KEY_METADATA = Metadata.builder()
+ .isPublic(true)
+ .isHidden(false)
+ .isCached(false)
+ .isEncrypted(false)
+ .build();
+
+ private static final Metadata SELF_KEY_METADATA = Metadata.builder()
+ .isPublic(false)
+ .isHidden(false)
+ .isCached(false)
+ .isEncrypted(true)
+ .build();
+
+ private static final Metadata SHARED_KEY_METADATA = Metadata.builder()
+ .isPublic(false)
+ .isHidden(false)
+ .isCached(false)
+ .isEncrypted(true)
+ .build();
+
+ private static final Metadata PRIVATE_HIDDEN_KEY_METADATA = Metadata.builder()
+ .isPublic(false)
+ .isHidden(true)
+ .isCached(false)
+ .build();
+
+ private static final ThreadLocal>> RAW_KEY_PARSERS =
+ ThreadLocal.withInitial(() -> List.of(new SharedKeyRawKeyParser(),
+ new PrivateHiddenKeyRawKeyParser(),
+ new PublicKeyRawKeyParser(),
+ new SelfKeyRawKeyParser()));
+
+ private static final Pattern ILLEGAL_KEY_CHARS = Pattern.compile("[@:\\s]");
+
+ private static final Pattern NAMESPACE_QUALIFIED_KEY_NAME = Pattern.compile("^(?!shared_key)(.+)\\.([^.]+)$");
+
+ public static Matcher createNamespaceQualifiedKeyNameMatcher(String s) {
+ return NAMESPACE_QUALIFIED_KEY_NAME.matcher(s);
+ }
/**
- * Base class for keys in the Atsign Platform
+ * Base class for keys in the Atsign Platform.
*/
+ @Getter
+ @Accessors(fluent = true)
public static abstract class AtKey {
- public String name;
- public AtSign sharedWith;
- public AtSign sharedBy;
- private String namespace;
- public String getNamespace() {
- return namespace;
+ private final String name;
+ private final AtSign sharedWith;
+ private final AtSign sharedBy;
+ private final AtomicReference metadata;
+ private final String rawKey;
+
+ protected AtKey(AtSign sharedBy, AtSign sharedWith, String name, Metadata metadata, String rawKey) {
+ this.sharedBy = checkNotNull(sharedBy, "sharedBy is null");
+ this.sharedWith = sharedWith;
+ this.name = checkKeyName(name);
+ this.metadata = new AtomicReference<>(checkMetadata(metadata));
+ this.rawKey = rawKey;
}
- public void setNamespace(String namespace) {
- if (namespace != null) {
- while (namespace.startsWith(".")) {
- namespace = namespace.substring(1);
- }
- namespace = namespace.trim();
- }
- this.namespace = namespace;
+ protected AtKey(AtSign sharedBy, AtSign sharedWith, String name, Metadata metadata) {
+ this.sharedBy = checkNotNull(sharedBy, "sharedBy is null");
+ this.sharedWith = sharedWith;
+ this.name = checkKeyName(name);
+ this.metadata = new AtomicReference<>(checkMetadata(metadata));
+ this.rawKey = createRawKey();
}
- public Metadata metadata;
+ public Metadata metadata() {
+ return metadata.get();
+ }
- // bool isRef = false;
- public AtKey(AtSign sharedBy) {
- if (sharedBy == null) {
- throw new IllegalArgumentException("AtKey: sharedBy may not be null");
- }
- this.sharedBy = sharedBy;
- this.metadata = new Metadata();
+ /**
+ * Sets any {@link Metadata} fields that are currently unset.
+ *
+ * @param metadata new values if those fields are unset in the key's current {@link Metadata}.
+ */
+ public void updateMissingMetadata(Metadata metadata) {
+ this.metadata.set(checkMetadata(Metadata.merge(this.metadata.get(), metadata)));
+ }
+
+ /**
+ * Updates {@link Metadata} fields with any non-null fields
+ *
+ * @param metadata new values (unset fields are ignored).
+ */
+ public void overwriteMetadata(Metadata metadata) {
+ this.metadata.set(checkMetadata(Metadata.merge(metadata, this.metadata.get())));
}
- public String getFullyQualifiedKeyName() {
- return name + (namespace != null && !namespace.trim().isEmpty() ? "." + namespace : "");
+ /**
+ * @return the namespace component of the name or null if no namespace.
+ */
+ public String namespace() {
+ return getNamespace(name);
+ }
+
+ /**
+ *
+ * @return the name without the namespace component.
+ */
+ public String nameWithoutNamespace() {
+ return stripNamespace(name);
}
@Override
public String toString() {
- String s = "";
- if (metadata.isPublic) {
- s += "public:";
- } else if (sharedWith != null) {
- s += sharedWith + ":";
- }
- s += getFullyQualifiedKeyName();
+ return rawKey;
+ }
- if (sharedBy != null) {
- s += sharedBy;
- }
- return s;
+ protected String createRawKey() {
+ Metadata metadata = this.metadata.get();
+ return new StringBuilder()
+ .append(isNotNullAndTrue(metadata.isCached()) ? "cached:" : "")
+ .append(isNotNullAndTrue(metadata.isPublic()) ? "public:" : "")
+ .append(sharedWith != null ? sharedWith + ":" : "")
+ .append(name)
+ .append(sharedBy)
+ .toString();
}
}
@@ -74,161 +149,320 @@ public String toString() {
* Represents a "public key" in the Atsign Platform
*/
public static class PublicKey extends AtKey {
- public PublicKey() {
- this(defaultAtSign);
+ protected PublicKey(AtSign sharedBy, String name, Metadata metadata) {
+ super(sharedBy, null, name, metadata);
}
+ }
- public PublicKey(AtSign sharedBy) {
- super(sharedBy);
- super.metadata.isPublic = true;
- super.metadata.isEncrypted = false;
- super.metadata.isHidden = false;
+ @Builder(builderMethodName = "publicKeyBuilder", builderClassName = "PublicKeyBuilder")
+ public static PublicKey publicKey(AtSign sharedBy, String name, String namespace, Long ttl, Long ttb, Long ttr,
+ Boolean ccd, Boolean isCached, Boolean isBinary, Metadata metadata) {
+ if (metadata != null) {
+ checkAllNull("both metadata and metadata fields set, this is ambiguous and not supported",
+ ttl, ttb, ttr, ccd, isCached, isBinary);
+ } else {
+ MetadataBuilder builder = PUBLIC_KEY_METADATA.toBuilder();
+ setTtlIfNotNull(builder, ttl);
+ setTtrIfNotNull(builder, ttr);
+ setTtbIfNotNull(builder, ttb);
+ setCcdIfNotNull(builder, ccd);
+ setIsCachedIfNotNull(builder, isCached);
+ setIsBinaryIfNotNull(builder, isBinary);
+ metadata = builder.build();
}
+ checkNotNull(sharedBy, "sharedBy is not set");
+ checkNotNull(name, "name is not set");
+ return new PublicKey(sharedBy, toName(name, namespace), metadata);
}
/**
* Represents a "self key" in the Atsign Platform
*/
public static class SelfKey extends AtKey {
- public SelfKey() {
- this(defaultAtSign);
- }
-
- public SelfKey(AtSign sharedBy) {
- this(sharedBy, null);
+ protected SelfKey(AtSign sharedBy, AtSign sharedWith, String name, Metadata metadata) {
+ super(sharedBy, sharedWith, name, metadata);
}
+ }
- public SelfKey(AtSign sharedBy, AtSign sharedWith) { // possibility of `@bob:keyName@bob`
- super(sharedBy);
- super.sharedWith = sharedWith;
- super.metadata.isPublic = false;
- super.metadata.isEncrypted = true;
- super.metadata.isHidden = false;
+ @Builder(builderMethodName = "selfKeyBuilder", builderClassName = "SelfKeyBuilder")
+ public static SelfKey selfKey(AtSign sharedBy, AtSign sharedWith, String name, String namespace, Long ttl,
+ Long ttb, Long ttr, Boolean ccd, Boolean isHidden, Boolean isBinary,
+ Metadata metadata) {
+ if (metadata != null) {
+ checkAllNull("both metadata and metadata fields set, this is ambiguous and not supported",
+ ttl, ttb, ttr, ccd, isBinary);
+ } else {
+ MetadataBuilder builder = SELF_KEY_METADATA.toBuilder();
+ setTtlIfNotNull(builder, ttl);
+ setTtrIfNotNull(builder, ttr);
+ setTtbIfNotNull(builder, ttb);
+ setCcdIfNotNull(builder, ccd);
+ setIsHiddenIfNotNull(builder, isHidden);
+ setIsBinaryIfNotNull(builder, isBinary);
+ metadata = builder.build();
}
+ checkNotNull(sharedBy, "sharedBy is not set");
+ checkNotNull(name, "name is not set");
+ return new SelfKey(sharedBy, sharedWith, toName(name, namespace), metadata);
}
/**
* Represents a "shared key" in the Atsign Platform
*/
public static class SharedKey extends AtKey {
- public SharedKey(AtSign sharedBy, AtSign sharedWith) {
- super(sharedBy);
- if (sharedWith == null) {
- throw new IllegalArgumentException("SharedKey: sharedWith may not be null");
+ protected SharedKey(AtSign sharedBy, AtSign sharedWith, String name, Metadata metadata) {
+ super(sharedBy, checkNotNull(sharedWith), name, metadata);
+ }
+ }
+
+ @Builder(builderMethodName = "sharedKeyBuilder", builderClassName = "SharedKeyBuilder")
+ public static SharedKey sharedKey(AtSign sharedBy, AtSign sharedWith, String name, String namespace, Long ttl,
+ Long ttb, Long ttr, Boolean ccd, Boolean isCached, Boolean isBinary,
+ Boolean isHidden, Metadata metadata, String rawKey) {
+ if (rawKey != null) {
+ checkAllNull("both rawKey and other fields set",
+ sharedBy, sharedWith, name, namespace, ttl, ttb, ttr, ccd, isCached, isBinary, isHidden);
+ SharedKeyRawKeyParser parser = new SharedKeyRawKeyParser();
+ parser.test(rawKey);
+ return parser.parse(rawKey, metadata);
+ }
+ if (metadata != null) {
+ checkAllNull("both metadata and metadata fields set",
+ ttl, ttb, ttr, ccd, isCached, isBinary, isHidden);
+ } else {
+ MetadataBuilder builder = SHARED_KEY_METADATA.toBuilder();
+ setTtlIfNotNull(builder, ttl);
+ setTtrIfNotNull(builder, ttr);
+ setTtbIfNotNull(builder, ttb);
+ setCcdIfNotNull(builder, ccd);
+ setIsCachedIfNotNull(builder, isCached);
+ setIsHiddenIfNotNull(builder, isHidden);
+ setIsBinaryIfNotNull(builder, isBinary);
+ metadata = builder.build();
+ }
+ checkNotNull(sharedBy, "sharedBy is not set");
+ checkNotNull(sharedWith, "sharedWith is not set");
+ checkNotNull(name, "name is not set");
+ return new SharedKey(sharedBy, sharedWith, toName(name, namespace), metadata);
+ }
+
+ /**
+ * Represents a "private hidden key" in the Atsign Platform
+ */
+ public static class PrivateHiddenKey extends AtKey {
+ protected PrivateHiddenKey(AtSign sharedBy, String name, Metadata metadata, String rawKey) {
+ super(sharedBy, null, name, metadata, checkNotNull(rawKey));
+ }
+ }
+
+ @Builder(builderMethodName = "privateHiddenKeyBuilder", builderClassName = "PrivateHiddenKeyBuilder")
+ public static PrivateHiddenKey privateHiddenKey(AtSign sharedBy, String name, String namespace, Metadata metadata,
+ String rawKey) {
+ metadata = metadata != null ? metadata : PRIVATE_HIDDEN_KEY_METADATA;
+ checkNotNull(sharedBy, "sharedBy is not set");
+ checkNotNull(name, "name is not set");
+ return new PrivateHiddenKey(sharedBy, toName(name, namespace), metadata, rawKey);
+ }
+
+ @Builder(builderMethodName = "keyBuilder", builderClassName = "KeyBuilder")
+ public static AtKey key(String rawKey, Metadata metadata) {
+ for (RawKeyParser extends AtKey> parser : RAW_KEY_PARSERS.get()) {
+ if (parser.test(rawKey)) {
+ return parser.parse(rawKey, metadata);
+ }
+ }
+ throw new IllegalArgumentException(rawKey + " does NOT match any raw key parser");
+ }
+
+ private interface RawKeyParser extends Predicate {
+ T parse(String rawKey, Metadata metadata);
+ }
+
+ private static class PublicKeyRawKeyParser implements RawKeyParser {
+
+ private final Pattern PATTERN = Pattern.compile("(cached:)?public:([^@]+)(@.+)");
+
+ private Matcher matcher;
+
+ public boolean test(String rawKey) {
+ matcher = PATTERN.matcher(rawKey);
+ if (matcher.matches()) {
+ return isLegalKeyName(matcher.group(2));
+ } else {
+ return false;
}
- super.sharedWith = sharedWith;
- super.metadata.isPublic = false;
- super.metadata.isEncrypted = true;
- super.metadata.isHidden = false;
}
- public static SharedKey fromString(String key) throws IllegalArgumentException {
- if (key == null) {
- throw new IllegalArgumentException("SharedKey.fromString(key) : key may not be null");
+ public PublicKey parse(String rawKey, Metadata metadata) {
+ checkNotNull(matcher, "matcher does not match");
+ MetadataBuilder metadataBuilder = PUBLIC_KEY_METADATA.toBuilder();
+ if (metadata != null) {
+ metadataBuilder = Metadata.merge(metadata, metadataBuilder.build()).toBuilder();
}
- String[] splitByColon = key.split(":");
- if (splitByColon.length != 2) {
- throw new IllegalArgumentException(
- "SharedKey.fromString('" + key + "') : key must have structure @bob:foo.bar@alice");
+ if (matcher.group(1) != null) {
+ metadataBuilder.isCached(true);
}
- String sharedWith = splitByColon[0];
- String[] splitByAtSign = splitByColon[1].split("@");
- if (splitByAtSign.length != 2) {
- throw new IllegalArgumentException(
- "SharedKey.fromString('" + key + "') : key must have structure @bob:foo.bar@alice");
+ if (matcher.group(2).startsWith("_")) {
+ metadataBuilder.isHidden(true);
}
- String keyName = splitByAtSign[0];
- String sharedBy = splitByAtSign[1];
- SharedKey sharedKey = new SharedKey(new AtSign(sharedBy), new AtSign(sharedWith));
- sharedKey.name = keyName;
- return sharedKey;
+ return publicKeyBuilder()
+ .name(matcher.group(2))
+ .sharedBy(createAtSign(matcher.group(3)))
+ .metadata(metadataBuilder.build())
+ .build();
}
+ }
+
+ private static class SelfKeyRawKeyParser implements RawKeyParser {
+
+ private static final Pattern PATTERN = Pattern.compile("(@[^:]+:)?([^@]+)(@.+)");
- public String getSharedSharedKeyName() {
- return sharedWith + ":shared_key" + sharedBy;
+ private Matcher matcher;
+
+ public boolean test(String rawKey) {
+ matcher = PATTERN.matcher(rawKey);
+ if (matcher.matches()) {
+ return (matcher.group(1) == null || chop(matcher.group(1)).equals(matcher.group(3)))
+ && isLegalKeyName(matcher.group(2));
+ } else {
+ return false;
+ }
+ }
+
+ public SelfKey parse(String rawKey, Metadata metadata) {
+ checkNotNull(matcher, "matcher does not match");
+ MetadataBuilder metadataBuilder = SELF_KEY_METADATA.toBuilder();
+ if (metadata != null) {
+ metadataBuilder = Metadata.merge(metadata, metadataBuilder.build()).toBuilder();
+ }
+ if (matcher.group(2).startsWith("_")) {
+ metadataBuilder.isHidden(true);
+ }
+ return selfKeyBuilder()
+ .sharedWith(createAtSign(chop(matcher.group(1))))
+ .name(matcher.group(2))
+ .sharedBy(createAtSign(matcher.group(3)))
+ .metadata(metadataBuilder.build())
+ .build();
}
}
- /**
- * Represents a "private hidden key" in the Atsign Platform
- */
- public static class PrivateHiddenKey extends AtKey {
- public PrivateHiddenKey() {
- this(defaultAtSign);
+ private static class SharedKeyRawKeyParser implements RawKeyParser {
+
+ private static final Pattern PATTERN = Pattern.compile("(cached:)?(@[^:]+):([^@]+)(@.+)");
+
+ private Matcher matcher;
+
+ public boolean test(String rawKey) {
+ matcher = PATTERN.matcher(rawKey);
+ if (matcher.matches()) {
+ return !matcher.group(2).equals(matcher.group(4));
+ } else {
+ return false;
+ }
}
- public PrivateHiddenKey(AtSign sharedBy) {
- super(sharedBy);
- super.metadata = new Metadata();
+ public SharedKey parse(String rawKey, Metadata metadata) {
+ checkNotNull(matcher, "matcher does not match");
+ MetadataBuilder metadataBuilder = SHARED_KEY_METADATA.toBuilder();
+ if (metadata != null) {
+ metadataBuilder = Metadata.merge(metadata, metadataBuilder.build()).toBuilder();
+ }
+ if (matcher.group(1) != null) {
+ metadataBuilder.isCached(true);
+ }
+ if (matcher.group(3).startsWith("_")) {
+ metadataBuilder.isHidden(true);
+ }
+ return sharedKeyBuilder()
+ .sharedWith(createAtSign(matcher.group(2)))
+ .name(matcher.group(3))
+ .sharedBy(createAtSign(matcher.group(4)))
+ .metadata(metadataBuilder.build())
+ .build();
}
}
- /**
- * Generate an AtKey object from a given full key name.
- *
- * @param fullAtKeyName eg: @bob:phone@alice
- * @return AtKey object
- * @throws AtException if key string doesn't match recognized structure
- */
- @SuppressWarnings("JavaDoc")
- public static AtKey fromString(String fullAtKeyName) throws AtException {
- KeyStringUtil keyStringUtil = new KeyStringUtil(fullAtKeyName);
- KeyType keyType = keyStringUtil.getKeyType();
- String keyName = keyStringUtil.getKeyName();
- AtSign sharedBy = new AtSign(keyStringUtil.getSharedBy());
- AtSign sharedWith = null;
- if (keyStringUtil.getSharedWith() != null) {
- sharedWith = new AtSign(keyStringUtil.getSharedWith());
- }
- String namespace = keyStringUtil.getNamespace();
- boolean isCached = keyStringUtil.isCached();
- boolean isHidden = keyStringUtil.isHidden();
- AtKey atKey;
- switch (keyType) {
- case PUBLIC_KEY:
- atKey = new KeyBuilders.PublicKeyBuilder(sharedBy).key(keyName).build();
- break;
- case SHARED_KEY:
- atKey = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key(keyName).build();
- break;
- case SELF_KEY:
- atKey = new KeyBuilders.SelfKeyBuilder(sharedBy, sharedWith).key(keyName).build();
- break;
- case PRIVATE_HIDDEN_KEY:
- atKey = new KeyBuilders.PrivateHiddenKeyBuilder(sharedBy).key(keyName).build();
- break;
- default:
- throw new MalformedKeyException("Could not find KeyType for Key \"" + fullAtKeyName);
- }
- atKey.setNamespace(namespace);
- atKey.metadata.isCached = isCached;
- if (!atKey.metadata.isHidden) {
- atKey.metadata.isHidden = isHidden; // if KeyBuilders constructor did not already evaluate isHidden, then do it
- // here
- }
- return atKey;
+ private static class PrivateHiddenKeyRawKeyParser implements RawKeyParser {
+
+ private static final Pattern PATTERN = Pattern.compile("(private|privatekey):([^@]+)(@.+)");
+
+ private Matcher matcher;
+
+ public boolean test(String rawKey) {
+ matcher = PATTERN.matcher(rawKey);
+ return matcher.matches();
+ }
+
+ public PrivateHiddenKey parse(String rawKey, Metadata metadata) {
+ checkNotNull(matcher, "matcher does not match");
+ MetadataBuilder metadataBuilder;
+ if (metadata != null) {
+ metadataBuilder = Metadata.merge(metadata, PRIVATE_HIDDEN_KEY_METADATA).toBuilder();
+ } else {
+ metadataBuilder = PRIVATE_HIDDEN_KEY_METADATA.toBuilder();
+ }
+ return privateHiddenKeyBuilder()
+ .name(matcher.group(2))
+ .sharedBy(createAtSign(matcher.group(3)))
+ .metadata(metadataBuilder.build())
+ .rawKey(rawKey)
+ .build();
+ }
}
- /**
- * Generate an {@link AtKey} whose metadata is populated from the given `llookup:meta:key`
- * response.
- *
- * @param fullAtKeyName The full AtKey name, eg: `@bob:phone@alice`
- * @param metadataResponse `llookup:meta:key` rawResponse from secondary server
- * @return AtKey whose metadata is populated from the llookup:meta:key rawResponse from
- * secondary server
- * @throws AtException if key string doesn't match recognized structure
- * @throws JsonProcessingException if metadataResponse is invalid JSON
- */
- @SuppressWarnings("JavaDoc")
- public static AtKey fromString(String fullAtKeyName, Secondary.Response metadataResponse)
- throws AtException, JsonProcessingException {
- AtKey atKey = fromString(fullAtKeyName);
- atKey.metadata = Metadata.squash(atKey.metadata, Metadata.fromJson(metadataResponse.getRawDataResponse()));
- return atKey;
+ private static String toName(String name, String namespace) {
+ if (namespace != null && !namespace.isBlank()) {
+ return name + "." + namespace;
+ } else {
+ return name;
+ }
+ }
+
+ protected static String getNamespace(String name) {
+ Matcher matcher = createNamespaceQualifiedKeyNameMatcher(name);
+ if (matcher.matches()) {
+ return matcher.group(2);
+ } else {
+ return null;
+ }
+ }
+
+ protected static String stripNamespace(String name) {
+ Matcher matcher = createNamespaceQualifiedKeyNameMatcher(name);
+ if (matcher.matches()) {
+ return matcher.group(1);
+ } else {
+ return name;
+ }
+ }
+
+ private static String checkKeyName(String s) {
+ checkNotBlank(s, "key name is blank");
+ if (!isLegalKeyName(s)) {
+ throw new IllegalArgumentException("illegal characters in key name");
+ }
+ return s;
+ }
+
+ private static boolean isLegalKeyName(String s) {
+ return !ILLEGAL_KEY_CHARS.matcher(s).find();
+ }
+
+ private static String chop(String s) {
+ return s != null ? s.substring(0, s.length() - 1) : null;
}
- public static AtKey fromString(Secondary.Response lookupAllResponse) {
- throw new RuntimeException("Not implemented");
+ private static Metadata checkMetadata(Metadata metadata) {
+ checkNotNull(metadata, "metadata is null");
+ checkTrue(metadata.ttl() == null || metadata.ttl() >= 0, "ttl cannot be negative");
+ checkTrue(metadata.ttb() == null || metadata.ttb() >= 0, "ttb cannot be negative");
+ checkTrue(metadata.ttr() == null || metadata.ttr() >= -1, "ttr cannot be < -1");
+ return metadata;
}
+
+ private static boolean isNotNullAndTrue(Boolean b) {
+ return b != null ? b : false;
+ }
+
}
diff --git a/at_client/src/main/java/org/atsign/common/Metadata.java b/at_client/src/main/java/org/atsign/common/Metadata.java
index f622f432..6895fe6a 100644
--- a/at_client/src/main/java/org/atsign/common/Metadata.java
+++ b/at_client/src/main/java/org/atsign/common/Metadata.java
@@ -1,277 +1,356 @@
package org.atsign.common;
-import java.io.IOException;
import java.time.OffsetDateTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-import java.time.format.DateTimeFormatter;
-import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
-import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JavaType;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
+
+import lombok.Builder;
+import lombok.Value;
+import lombok.experimental.Accessors;
+import lombok.extern.jackson.Jacksonized;
/**
- * Data class which models key metadata in the Atsign Platform
+ * Value class which models key metadata in the Atsign Platform
*/
-@JsonIgnoreProperties(ignoreUnknown = true)
+@Value
+@Builder(toBuilder = true)
+@Accessors(fluent = true)
+@Jacksonized
public class Metadata {
- static final ObjectMapper mapper = new ObjectMapper();
-
- public Integer ttl;
- public Integer ttb;
- public Integer ttr;
- public Boolean ccd;
- public String createdBy;
- public String updatedBy;
- @JsonDeserialize(using = AtStringDateTimeDeserializer.class)
- public OffsetDateTime availableAt;
- @JsonDeserialize(using = AtStringDateTimeDeserializer.class)
- public OffsetDateTime expiresAt;
- @JsonDeserialize(using = AtStringDateTimeDeserializer.class)
- public OffsetDateTime refreshAt;
- @JsonDeserialize(using = AtStringDateTimeDeserializer.class)
- public OffsetDateTime createdAt;
- @JsonDeserialize(using = AtStringDateTimeDeserializer.class)
- public OffsetDateTime updatedAt;
- public String status;
- public Integer version;
- public String dataSignature;
- public String sharedKeyStatus;
- public Boolean isPublic = false;
- public Boolean isEncrypted = true;
- public Boolean isHidden = false;
- public Boolean namespaceAware = true;
- public Boolean isBinary = false;
- public Boolean isCached = false;
- public String sharedKeyEnc;
- public String pubKeyCS;
- public String encoding;
- public String ivNonce;
+
+ Long ttl;
+ Long ttb;
+ Long ttr;
+ Boolean ccd;
+ String createdBy;
+ String updatedBy;
+ OffsetDateTime availableAt;
+ OffsetDateTime expiresAt;
+ OffsetDateTime refreshAt;
+ OffsetDateTime createdAt;
+ OffsetDateTime updatedAt;
+ String status;
+ Integer version;
+ String dataSignature;
+ String sharedKeyStatus;
+ Boolean isPublic;
+ Boolean isEncrypted;
+ Boolean isHidden;
+ Boolean namespaceAware;
+ Boolean isBinary;
+ Boolean isCached;
+ String sharedKeyEnc;
+ String pubKeyCS;
+ String encoding;
+ String ivNonce;
+
+ // required for successful javadoc
+
+ /**
+ * A builder for instantiating {@link Metadata} instances. Note: Metadata is immutable so if you
+ * want create a modified instance then use the toBuilder() method, override the fields and invoke
+ * build().
+ */
+ public static class MetadataBuilder {
+ };
public static Metadata fromJson(String json) throws JsonProcessingException {
- return mapper.readValue(json, Metadata.class);
+ return Json.MAPPER.readValue(json, Metadata.class);
}
@Override
public String toString() {
- String s = "";
- if (ttl != null) {
- s += ":ttl:" + ttl;
+ return new StringBuilder()
+ .append(ttl != null ? ":ttl:" + ttl : "")
+ .append(ttb != null ? ":ttb:" + ttb : "")
+ .append(ttr != null ? ":ttr:" + ttr : "")
+ .append(ccd != null ? ":ccd:" + ccd : "")
+ .append(dataSignature != null ? ":dataSignature:" + dataSignature : "")
+ .append(sharedKeyStatus != null ? ":sharedKeyStatus:" + sharedKeyStatus : "")
+ .append(sharedKeyEnc != null ? ":sharedKeyEnc:" + sharedKeyEnc : "")
+ .append(pubKeyCS != null ? ":pubKeyCS:" + pubKeyCS : "")
+ .append(isBinary != null ? ":isBinary:" + isBinary : "")
+ .append(isEncrypted != null ? ":isEncrypted:" + isEncrypted : "")
+ .append(encoding != null ? ":encoding:" + encoding : "")
+ .append(ivNonce != null ? ":ivNonce:" + ivNonce : "")
+ .toString();
+ }
+
+ /**
+ * Combines two metadata instances into a new metadata instance
+ *
+ * @param md1 has priority
+ * @param md2 use fields from here if not in md1
+ * @return A new merged metadata instance
+ */
+ public static Metadata merge(Metadata md1, Metadata md2) {
+ return toMergedBuilder(md1, md2).build();
+ }
+
+ /**
+ * Creates a builder for {@link Metadata} based on the combined fields of two
+ * Metadata instances.
+ *
+ * @param md1 has priority
+ * @param md2 use fields from here if not in md1
+ * @return a builder with the squashed fields
+ */
+ public static MetadataBuilder toMergedBuilder(Metadata md1, Metadata md2) {
+ MetadataBuilder builder = new MetadataBuilder();
+
+ if (!setIsPublicIfNotNull(builder, md1.isPublic)) {
+ setIsPublicIfNotNull(builder, md2.isPublic);
}
- if (ttb != null) {
- s += ":ttb:" + ttb;
+ if (!setIsHiddenIfNotNull(builder, md1.isHidden)) {
+ setIsHiddenIfNotNull(builder, md2.isHidden);
}
- if (ttr != null) {
- s += ":ttr:" + ttr;
+ if (!setIsCachedIfNotNull(builder, md1.isCached)) {
+ setIsCachedIfNotNull(builder, md2.isCached);
}
- if (ccd != null) {
- s += ":ccd:" + ccd;
+ if (!setTtlIfNotNull(builder, md1.ttl)) {
+ setTtlIfNotNull(builder, md2.ttl);
}
- if (dataSignature != null) {
- s += ":dataSignature:" + dataSignature;
+ if (!setTtbIfNotNull(builder, md1.ttb)) {
+ setTtbIfNotNull(builder, md2.ttb);
}
- if (sharedKeyStatus != null) {
- s += ":sharedKeyStatus:" + sharedKeyStatus;
+ if (!setTtrIfNotNull(builder, md1.ttr)) {
+ setTtrIfNotNull(builder, md2.ttr);
}
- if (sharedKeyEnc != null) {
- s += ":sharedKeyEnc:" + sharedKeyEnc;
+ if (!setCcdIfNotNull(builder, md1.ccd)) {
+ setCcdIfNotNull(builder, md2.ccd);
}
- if (pubKeyCS != null) {
- s += ":pubKeyCS:" + pubKeyCS;
+ if (!setAvailableAtIfNotNull(builder, md1.availableAt)) {
+ setAvailableAtIfNotNull(builder, md2.availableAt);
}
- if (isBinary != null) {
- s += ":isBinary:" + isBinary;
+ if (!setExpiresAtIfNotNull(builder, md1.expiresAt)) {
+ setExpiresAtIfNotNull(builder, md2.expiresAt);
}
- if (isEncrypted != null) {
- s += ":isEncrypted:" + isEncrypted;
+ if (!setRefreshAtIfNotNull(builder, md1.refreshAt)) {
+ setRefreshAtIfNotNull(builder, md2.refreshAt);
}
- if (encoding != null) {
- s += ":encoding:" + encoding;
+ if (!setCreatedAtIfNotNull(builder, md1.createdAt)) {
+ setCreatedAtIfNotNull(builder, md2.createdAt);
}
- if (ivNonce != null && !ivNonce.isEmpty()) {
- s += ":ivNonce:" + ivNonce;
+ if (!setUpdatedAtIfNotNull(builder, md1.updatedAt)) {
+ setUpdatedAtIfNotNull(builder, md2.updatedAt);
}
- return s;
- }
-
- /**
- * Squashes the two metadatas into one metadata.
- *
- * @param firstMetadata has priority
- * @param secondMetadata use fields from here if not in firstMetadata
- * @return One merged metadata object
- */
- public static Metadata squash(Metadata firstMetadata, Metadata secondMetadata) {
- Metadata metadata = new Metadata();
- if (firstMetadata.ttl != null) {
- metadata.ttl = firstMetadata.ttl;
- } else if (secondMetadata.ttl != null) {
- metadata.ttl = secondMetadata.ttl;
+ if (!setDataSignatureIfNotNull(builder, md1.dataSignature)) {
+ setDataSignatureIfNotNull(builder, md2.dataSignature);
}
-
- if (firstMetadata.ttb != null) {
- metadata.ttb = firstMetadata.ttb;
- } else if (secondMetadata.ttb != null) {
- metadata.ttb = secondMetadata.ttb;
+ if (!setSharedKeyStatusIfNotNull(builder, md1.sharedKeyStatus)) {
+ setSharedKeyStatusIfNotNull(builder, md2.sharedKeyStatus);
}
-
- if (firstMetadata.ttr != null) {
- metadata.ttr = firstMetadata.ttr;
- } else if (secondMetadata.ttr != null) {
- metadata.ttr = secondMetadata.ttr;
+ if (!setSharedKeyEncIfNotNull(builder, md1.sharedKeyEnc)) {
+ setSharedKeyEncIfNotNull(builder, md2.sharedKeyEnc);
}
-
- if (firstMetadata.ccd != null) {
- metadata.ccd = firstMetadata.ccd;
- } else if (secondMetadata.ccd != null) {
- metadata.ccd = secondMetadata.ccd;
+ if (!setIsEncryptedIfNotNull(builder, md1.isEncrypted)) {
+ setIsEncryptedIfNotNull(builder, md2.isEncrypted);
}
-
- if (firstMetadata.availableAt != null) {
- metadata.availableAt = firstMetadata.availableAt;
- } else if (secondMetadata.availableAt != null) {
- metadata.availableAt = secondMetadata.availableAt;
+ if (!setNamespaceAwareIfNotNull(builder, md1.namespaceAware)) {
+ setNamespaceAwareIfNotNull(builder, md2.namespaceAware);
}
-
- if (firstMetadata.expiresAt != null) {
- metadata.expiresAt = firstMetadata.expiresAt;
- } else if (secondMetadata.expiresAt != null) {
- metadata.expiresAt = secondMetadata.expiresAt;
+ if (!setIsBinaryIfNotNull(builder, md1.isBinary)) {
+ setIsBinaryIfNotNull(builder, md2.isBinary);
}
-
- if (firstMetadata.refreshAt != null) {
- metadata.refreshAt = firstMetadata.refreshAt;
- } else if (secondMetadata.refreshAt != null) {
- metadata.refreshAt = secondMetadata.refreshAt;
+ if (!setPubKeyCSIfNotNull(builder, md1.pubKeyCS)) {
+ setPubKeyCSIfNotNull(builder, md2.pubKeyCS);
}
-
- if (firstMetadata.createdAt != null) {
- metadata.createdAt = firstMetadata.createdAt;
- } else if (secondMetadata.createdAt != null) {
- metadata.createdAt = secondMetadata.createdAt;
+ if (!setEncodingIfNotNull(builder, md1.encoding)) {
+ setEncodingIfNotNull(builder, md2.encoding);
}
+ if (!setIvNonceIfNotNull(builder, md1.ivNonce)) {
+ setIvNonceIfNotNull(builder, md2.ivNonce);
+ }
+
+ return builder;
+ }
- if (firstMetadata.updatedAt != null) {
- metadata.updatedAt = firstMetadata.updatedAt;
- } else if (secondMetadata.updatedAt != null) {
- metadata.updatedAt = secondMetadata.updatedAt;
+ public static boolean setIsHiddenIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.isHidden(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.dataSignature != null) {
- metadata.dataSignature = firstMetadata.dataSignature;
- } else if (secondMetadata.dataSignature != null) {
- metadata.dataSignature = secondMetadata.dataSignature;
+ public static boolean setIsPublicIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.isPublic(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.sharedKeyStatus != null) {
- metadata.sharedKeyStatus = firstMetadata.sharedKeyStatus;
- } else if (secondMetadata.sharedKeyStatus != null) {
- metadata.sharedKeyStatus = secondMetadata.sharedKeyStatus;
+ public static boolean setIsCachedIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.isCached(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.sharedKeyEnc != null) {
- metadata.sharedKeyEnc = firstMetadata.sharedKeyEnc;
- } else if (secondMetadata.sharedKeyEnc != null) {
- metadata.sharedKeyEnc = secondMetadata.sharedKeyEnc;
+ public static boolean setTtlIfNotNull(MetadataBuilder builder, Long value) {
+ if (value != null) {
+ builder.ttl(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.isPublic != null) {
- metadata.isPublic = firstMetadata.isPublic;
- } else if (secondMetadata.isPublic != null) {
- metadata.isPublic = secondMetadata.isPublic;
+ public static boolean setTtbIfNotNull(MetadataBuilder builder, Long value) {
+ if (value != null) {
+ builder.ttb(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.isEncrypted != null) {
- metadata.isEncrypted = firstMetadata.isEncrypted;
- } else if (secondMetadata.isEncrypted != null) {
- metadata.isEncrypted = secondMetadata.isEncrypted;
+ public static boolean setTtrIfNotNull(MetadataBuilder builder, Long value) {
+ if (value != null) {
+ builder.ttr(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.isHidden != null) {
- metadata.isHidden = firstMetadata.isHidden;
- } else if (secondMetadata.isHidden != null) {
- metadata.isHidden = secondMetadata.isHidden;
+ public static boolean setCcdIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.ccd(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.namespaceAware != null) {
- metadata.namespaceAware = firstMetadata.namespaceAware;
- } else if (secondMetadata.namespaceAware != null) {
- metadata.namespaceAware = secondMetadata.namespaceAware;
+ private static boolean setAvailableAtIfNotNull(MetadataBuilder builder, OffsetDateTime value) {
+ if (value != null) {
+ builder.availableAt(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.isBinary != null) {
- metadata.isBinary = firstMetadata.isBinary;
- } else if (secondMetadata.isBinary != null) {
- metadata.isBinary = secondMetadata.isBinary;
+ private static boolean setExpiresAtIfNotNull(MetadataBuilder builder, OffsetDateTime value) {
+ if (value != null) {
+ builder.expiresAt(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.isCached != null) {
- metadata.isCached = firstMetadata.isCached;
- } else if (secondMetadata.isCached != null) {
- metadata.isCached = secondMetadata.isCached;
+ private static boolean setRefreshAtIfNotNull(MetadataBuilder builder, OffsetDateTime value) {
+ if (value != null) {
+ builder.refreshAt(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.sharedKeyEnc != null) {
- metadata.sharedKeyEnc = firstMetadata.sharedKeyEnc;
- } else if (secondMetadata.sharedKeyEnc != null) {
- metadata.sharedKeyEnc = secondMetadata.sharedKeyEnc;
+ private static boolean setCreatedAtIfNotNull(MetadataBuilder builder, OffsetDateTime value) {
+ if (value != null) {
+ builder.createdAt(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.pubKeyCS != null) {
- metadata.pubKeyCS = firstMetadata.pubKeyCS;
- } else if (secondMetadata.pubKeyCS != null) {
- metadata.pubKeyCS = secondMetadata.pubKeyCS;
+ private static boolean setUpdatedAtIfNotNull(MetadataBuilder builder, OffsetDateTime value) {
+ if (value != null) {
+ builder.updatedAt(value);
+ return true;
+ } else {
+ return false;
}
+ }
- if (firstMetadata.encoding != null) {
- metadata.encoding = firstMetadata.encoding;
- } else if (secondMetadata.encoding != null) {
- metadata.encoding = secondMetadata.encoding;
+ public static boolean setIsBinaryIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.isBinary(value);
+ return true;
+ } else {
+ return false;
}
- if (firstMetadata.ivNonce != null) {
- metadata.ivNonce = firstMetadata.ivNonce;
- } else if (secondMetadata.ivNonce != null) {
- metadata.ivNonce = secondMetadata.ivNonce;
+ }
+
+ public static boolean setIsEncryptedIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.isEncrypted(value);
+ return true;
+ } else {
+ return false;
}
+ }
- return metadata;
+ public static boolean setDataSignatureIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.dataSignature(value);
+ return true;
+ } else {
+ return false;
+ }
}
- /**
- * Jackson serializer for DateTime strings
- */
- @SuppressWarnings("unused")
- public static class AtStringDateTimeDeserializer extends StdDeserializer {
- public AtStringDateTimeDeserializer() {
- this((Class>) null);
+ public static boolean setNamespaceAwareIfNotNull(MetadataBuilder builder, Boolean value) {
+ if (value != null) {
+ builder.namespaceAware(value);
+ return true;
+ } else {
+ return false;
}
+ }
- protected AtStringDateTimeDeserializer(Class> vc) {
- super(vc);
+ public static boolean setSharedKeyStatusIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.sharedKeyStatus(value);
+ return true;
+ } else {
+ return false;
}
+ }
- protected AtStringDateTimeDeserializer(JavaType valueType) {
- super(valueType);
+ public static boolean setSharedKeyEncIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.sharedKeyEnc(value);
+ return true;
+ } else {
+ return false;
}
+ }
- protected AtStringDateTimeDeserializer(StdDeserializer> src) {
- super(src);
+ public static boolean setPubKeyCSIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.pubKeyCS(value);
+ return true;
+ } else {
+ return false;
}
+ }
- static final DateTimeFormatter dateTimeFormatter =
- DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS'Z'").withZone(ZoneId.of("UTC"));
+ public static boolean setEncodingIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.encoding(value);
+ return true;
+ } else {
+ return false;
+ }
+ }
- @Override
- public OffsetDateTime deserialize(JsonParser jsonParser, DeserializationContext deserializationContext)
- throws IOException {
- String dateString = jsonParser.getText();
- ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateString, dateTimeFormatter);
- return zonedDateTime.toOffsetDateTime();
+ public static boolean setIvNonceIfNotNull(MetadataBuilder builder, String value) {
+ if (value != null) {
+ builder.ivNonce(value);
+ return true;
+ } else {
+ return false;
}
}
}
diff --git a/at_client/src/main/java/org/atsign/common/ResponseTransformers.java b/at_client/src/main/java/org/atsign/common/ResponseTransformers.java
index 4bd9c824..c546c085 100644
--- a/at_client/src/main/java/org/atsign/common/ResponseTransformers.java
+++ b/at_client/src/main/java/org/atsign/common/ResponseTransformers.java
@@ -15,7 +15,8 @@
*/
@Slf4j
public class ResponseTransformers {
- static final ObjectMapper mapper = new ObjectMapper();
+
+ static final ObjectMapper mapper = Json.MAPPER;
/**
* Transformer for scan command responses
diff --git a/at_client/src/main/java/org/atsign/common/VerbBuilders.java b/at_client/src/main/java/org/atsign/common/VerbBuilders.java
index a585c8b1..9da7ef66 100644
--- a/at_client/src/main/java/org/atsign/common/VerbBuilders.java
+++ b/at_client/src/main/java/org/atsign/common/VerbBuilders.java
@@ -1,799 +1,722 @@
package org.atsign.common;
+import static java.util.Collections.singletonList;
+import static java.util.Collections.singletonMap;
+import static org.atsign.client.util.Preconditions.*;
+import static org.atsign.client.util.StringUtil.isBlank;
+import static org.atsign.common.Metadata.*;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+import org.atsign.client.util.EnrollmentId;
+import org.atsign.client.util.TypedString;
import org.atsign.common.Keys.AtKey;
-import org.atsign.common.Keys.PublicKey;
-import org.atsign.common.Keys.SharedKey;
+import org.atsign.common.Metadata.MetadataBuilder;
-import static org.atsign.client.util.StringUtil.isBlank;
+import com.fasterxml.jackson.core.JsonProcessingException;
+
+import lombok.Builder;
/**
*
- * Parent class for builders that build commands that are accepted by a secondary server
+ * Contains builders for composing Atsign protocol command strings
*
*/
public class VerbBuilders {
+ private static final Metadata EMPTY_METADATA = Metadata.builder().build();
+
/**
- * Base command interface
+ * A builder to compose an Atsign protocol command with the from verb. The from verb
+ * is used to tell the Atsign server whom you claim to be and initiates the authentication workflow.
+ *
+ * @param atSign The {@link AtSign} you claim to be
+ * @return A correctly formed from verb command
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
- public interface VerbBuilder {
- /// Build the command to be sent to remote secondary for execution.
- String build();
+ @Builder(builderMethodName = "fromCommandBuilder", builderClassName = "FromCommandBuilder")
+ public static String from(AtSign atSign) {
+ checkNotNull(atSign, "atSign not set");
+ return "from:" + atSign;
}
/**
- * Atsign Platform from command builder.
- * This initiates authentication
+ * A builder to compose an Atsign protocol command with the cram verb. The cram verb
+ * is used to boostrap authenticate one's own self as an owner of the Atsign server. It is intended
+ * to be used once until a set of PKAM keys are cut on the owner's mobile device and from then on we
+ * use the pkam verb.
+ *
+ * @param digest the challenge sent as a result of the from verb encrypted with the CRAM key/secret
+ * @return A correctly formed cram verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set.
*/
- public static class FromVerbBuilder implements VerbBuilder {
- // the atSign that we are authenticating with (e.g. atSignStr.equals("@alice") <=> true) [required]
- private String atSignStr;
-
- public void setAtSign(String atSignStr) {
- this.atSignStr = atSignStr;
- }
-
- @Override
- public String build() {
- atSignStr = AtSign.formatAtSign(atSignStr);
- if (atSignStr == null || atSignStr.isEmpty()) {
- throw new IllegalArgumentException("atSignStr cannot be null or empty");
- }
- return "from:" + atSignStr;
- }
+ @Builder(builderMethodName = "cramCommandBuilder", builderClassName = "CramCommandBuilder")
+ public static String cram(String digest) {
+ checkNotNull(digest, "digest not set");
+ return "cram:" + digest;
}
/**
- * Atsign Platform cram (Challenge Response Authentication Management) command builder
+ * A builder to compose an Atsign protocol command with the pol verb. The pol verb
+ * is part of the pkam process to authenticate oneself while connecting to someone else's atServer.
+ * The term 'pol' means 'proof of life' as it provides a near realtime assurance that the requestor
+ * is who it claims to be.
+ *
+ * @return A correctly formed pol verb command.
*/
- public static class CRAMVerbBuilder implements VerbBuilder {
-
- // chlallenge response authentication method
-
- private String digest; // the digest to use for authentication, encrypt the challenge (given by the from verb) to get the digest [required]
-
- public void setDigest(String digest) {
- this.digest = digest;
- }
-
- @Override
- public String build() {
- String s = "cram:" + digest;
- return s;
- }
+ @Builder(builderMethodName = "polCommandBuilder", builderClassName = "PolCommandBuilder")
+ public static String pol() {
+ return "pol";
}
/**
- * Atsign Platform pol (Proof of Life) command builder
+ * A builder to compose an Atsign protocol command with the pkam verb. The pkam verb
+ * follows the from verb. As an owner of the atServer, you should be able to take the
+ * challenge thrown by the from verb and encrypt using the private key of the RSA key pair
+ * with what the server has been bound with. Upon receiving the cram verb along with the digest, the
+ * server decrypts the digest using the public key and matches it with the challenge. If they are
+ * the same then the atServer lets you connect to the atServer and changes the prompt to your
+ * {@link AtSign}.
+ *
+ * @param digest The challenge sent as a result of the from verb signed with the {@link AtSign}'s
+ * private authentication key.
+ * @param signingAlgo The signing algorithm used.
+ * @param hashingAlgo The hashing algorithm used.
+ * @param enrollmentId The specific enrollment id for the {@link AtSign} that matches a specific
+ * authentication key pair.
+ * @return A correctly formed pkam verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
- public static class POLVerbBuilder implements VerbBuilder {
-
- @Override
- public String build() {
- return "pol";
- }
+ @Builder(builderMethodName = "pkamCommandBuilder", builderClassName = "PkamCommandBuilder")
+ public static String pkam(String digest, String signingAlgo, String hashingAlgo, EnrollmentId enrollmentId) {
+ checkNotNull(digest, "digest not set");
+ if (enrollmentId != null) {
+ checkNotBlank(signingAlgo, "signingAlgo not set");
+ checkNotBlank(hashingAlgo, "hashingAlgo not set");
+ }
+
+ return new StringBuilder("pkam")
+ .append(signingAlgo != null ? ":signingAlgo:" + signingAlgo : "")
+ .append(hashingAlgo != null ? ":hashingAlgo:" + hashingAlgo : "")
+ .append(enrollmentId != null ? ":enrollmentId:" + enrollmentId : "")
+ .append(':').append(digest)
+ .toString();
}
/**
- * Atsign Platform pkam (Public Key Authentication Management) command builder
+ * A builder to compose an Atsign protocol command with the update verb. The update
+ * is used to insert key/value pairs into a Key Store. An update command can only be sent by the
+ * {@link AtSign} that "owns" the key value and can only be sent to their own Atsign server.
+ *
+ * @param keyName The namespace qualified key name (without the sharedBy or sharedWith or public,
+ * hidden or cache qualifiers).
+ * @param sharedBy The {@link AtSign} which is owns / is sharing this key value (this will qualify
+ * the keyName is the built command).
+ * @param sharedWith The {@link AtSign} which is receiving this key value (this will qualify the
+ * keyName is the built command).
+ * @param isHidden Denotes whether the key value is hidden (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isPublic Denotes whether the key value is public (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isCached Denotes whether the key value is cached (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param ttl Sets the time to live in the metadata (milliseconds). This overrides the metadata
+ * param if this is also set.
+ * @param ttb Sets the time to birth in the metadata (milliseconds). This overrides the metadata
+ * param if this is also set.
+ * @param ttr Sets the time to refresh (for a cached key) in the metadata (milliseconds). The value
+ * -1 denotes "cached forever". This overrides the metadata param if this is also set.
+ * @param ccd Indicates if a cached key needs to be deleted when the atSign user who has originally
+ * shared it deletes it. This overrides the metadata param if this is also set.
+ * @param isBinary Sets metadata field which indicates a binary value. This overrides the metadata
+ * param if this is also set.
+ * @param isEncrypted Sets metadata field which indicates that value is encrypted. This overrides
+ * the metadata param if this is also set.
+ * @param dataSignature sets metadata field that holds signature of the value. This overrides the
+ * metadata param if this is also set.
+ * @param sharedKeyEnc Sets metadata field. This overrides the metadata param if this is also set.
+ * @param pubKeyCS sets metadata field. This overrides the metadata param if this is also set.
+ * @param encoding sets metadata field. This overrides the metadata param if this is also set.
+ * @param ivNonce sets metadata field used to hold the encryption initialization vector when value
+ * is encrypted. This overrides the metadata param if this is also set.
+ * @param value the value of the key / value. This overrides the metadata param if this is also set.
+ * @param key a {@link AtKey} instance from which keyName, sharedBy, sharedWith and metadata will be
+ * taken from.
+ * @param rawKey the Atsign protocol key with cached and public qualifications
+ * @return A correctly formed update verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
- public static class PKAMVerbBuilder implements VerbBuilder {
-
- // public key authentication method
-
- private String digest; // digest the challenge string given by the from verb [required]
-
- public void setDigest(String digest) {
- this.digest = digest;
- }
-
- @Override
- public String build() {
- String s = "pkam:" + digest;
- return s;
- }
-
+ @Builder(builderMethodName = "updateCommandBuilder", builderClassName = "UpdateCommandBuilder")
+ public static String update(String keyName, AtSign sharedBy, AtSign sharedWith, Boolean isHidden, Boolean isPublic,
+ Boolean isCached, Long ttl, Long ttb, Long ttr, Boolean ccd, Boolean isBinary,
+ Boolean isEncrypted, String dataSignature, String sharedKeyEnc, String pubKeyCS,
+ String encoding, String ivNonce, Object value, AtKey key, String rawKey) {
+
+ String metadataString;
+ String keyString;
+
+ if (key != null) {
+ checkAllNull("both key and key fields set", keyName, sharedBy, sharedWith, isHidden, isPublic, isCached, ttl, ttb,
+ ttr, ccd, isBinary, isEncrypted, dataSignature, sharedKeyEnc, pubKeyCS, encoding, ivNonce);
+ metadataString = key.metadata().toString();
+ keyString = key.toString();
+ } else {
+ MetadataBuilder metadataBuilder = createBlankMetadataBuilder();
+ if (rawKey == null) {
+ setIsHiddenIfNotNull(metadataBuilder, isHidden);
+ setIsPublicIfNotNull(metadataBuilder, isPublic);
+ setIsCachedIfNotNull(metadataBuilder, isCached);
+ } else {
+ checkAllNull("both rawKeys and isHidden, isPublic isCached set", isHidden, isPublic, isCached);
+ checkAllNull("both rawKeys and key fields set", keyName, sharedBy, sharedWith);
+ }
+ setTtlIfNotNull(metadataBuilder, ttl);
+ setTtrIfNotNull(metadataBuilder, ttr);
+ setTtbIfNotNull(metadataBuilder, ttb);
+ setCcdIfNotNull(metadataBuilder, ccd);
+ setIsBinaryIfNotNull(metadataBuilder, isBinary);
+ setIsEncryptedIfNotNull(metadataBuilder, isEncrypted);
+ setDataSignatureIfNotNull(metadataBuilder, dataSignature);
+ setSharedKeyEncIfNotNull(metadataBuilder, sharedKeyEnc);
+ setPubKeyCSIfNotNull(metadataBuilder, pubKeyCS);
+ setEncodingIfNotNull(metadataBuilder, encoding);
+ setIvNonceIfNotNull(metadataBuilder, ivNonce);
+
+ checkNotBlank(keyName, "keyName not set");
+ checkNotNull(sharedBy, "sharedBy not set");
+ checkNotNull(value, "value not set");
+
+ Metadata metadata = metadataBuilder.build();
+ metadataString = metadata.toString();
+ keyString = rawKey != null ? rawKey : toRawKey(keyName, sharedBy, sharedWith, metadata);
+ }
+
+ return String.format("update%s:%s %s", metadataString, keyString, value);
}
/**
- * Atsign Platform update command builder
+ * Controls whether lookups return just the value, just the metadata or the value and metadata
*/
- public static class UpdateVerbBuilder implements VerbBuilder {
-
- /// Update the value (and metadata optionally) of a key.
-
- // =======================================
- // AtKey name details
- // =======================================
- private String key; // e.g. "test", "location", "email" [required]
- private String sharedBy; // e.g. "@alice" [required]
- private String sharedWith = null; // e.g. "@bob"
- private Boolean isHidden = null; // if true, adds _ at the beginning of the fullKeyName
- private Boolean isPublic = null; // /// if [isPublic] is true, then [atKey] is accessible by all atSigns, if [isPublic] is false, then [atKey] is accessible either by [sharedWith] or [sharedBy]
- private Boolean isCached = false; // if true, will add "cached:" to the fullKeyName
- private Integer ttl = null; // time to live in milliseconds (how long AtKey will exist) (0 by default)
- private Integer ttb = null; // time to birth in milliseconds (how long it will take for AtKey to exist) (0 by default)
- private Integer ttr = null; // time to refresh in milliseconds (how long it will take for AtKey to refresh)
- private Boolean ccd = null; // if true, cached keys will be deleted if the original key is deleted
- private Boolean isBinary = null; // if true, the value contains binary data
- private Boolean isEncrypted = null; // if true, the value is encrypted with some encryption key
- private String dataSignature = null; // usually public data is signed with the private key to prove that the data is authentic
- private String sharedKeyEnc = null; // will be set only when [sharedWith] is set. Will be encrypted using the public key of [sharedWith] atsign
- private String pubKeyCS = null; // checksum of the public of of [sharedWith] atSign. Will be set only when [sharedWith] is set.
- private String encoding = null; // indicates if public data is encoded. If the public data contains a new line character, the data will be encoded and the encoding will be set to given type of encoding
- private String ivNonce = null;
-
- private Object value; // the value to set [required]
-
- public void setKeyName(String keyName) {
- this.key = keyName;
- }
-
- public void setSharedBy(String sharedBy) {
- this.sharedBy = sharedBy;
- }
-
- public void setSharedWith(String sharedWith) {
- this.sharedWith = sharedWith;
- }
-
- public void setIsHidden(Boolean isHidden) {
- this.isHidden = isHidden;
- }
-
- public void setIsPublic(Boolean isPublic) {
- this.isPublic = isPublic;
- }
-
- public void setIsCached(Boolean isCached) {
- this.isCached = isCached;
- }
-
- public void setTtl(Integer ttl) {
- this.ttl = ttl;
- }
-
- public void setTtb(Integer ttb) {
- this.ttb = ttb;
- }
-
- public void setTtr(Integer ttr) {
- this.ttr = ttr;
- }
-
- public void setCcd(Boolean ccd) {
- this.ccd = ccd;
- }
-
- public void setIsBinary(boolean isBinary) {
- this.isBinary = isBinary;
- }
-
- public void setIsEncrypted(boolean isEncrypted) {
- this.isEncrypted = isEncrypted;
- }
-
- public void setDataSignature(String dataSignature) {
- this.dataSignature = dataSignature;
- }
-
- public void setSharedKeyEnc(String sharedKeyEnc) {
- this.sharedKeyEnc = sharedKeyEnc;
- }
-
- public void setPubKeyCS(String pubKeyCS) {
- this.pubKeyCS = pubKeyCS;
- }
-
- public void setEncoding(String encoding) {
- this.encoding = encoding;
- }
-
- public void setValue(Object value) {
- this.value = value;
- }
-
- public void setMetadata(Metadata metadata) {
- this.isHidden = metadata.isHidden;
- this.isPublic = metadata.isPublic;
- this.isCached = metadata.isCached;
- this.ttl = metadata.ttl;
- this.ttb = metadata.ttb;
- this.ttr = metadata.ttr;
- this.ccd = metadata.ccd;
- this.isBinary = metadata.isBinary;
- this.isEncrypted = metadata.isEncrypted;
- this.dataSignature = metadata.dataSignature;
- this.sharedKeyEnc = metadata.sharedKeyEnc;
- this.pubKeyCS = metadata.pubKeyCS;
- this.encoding = metadata.encoding;
- this.ivNonce = metadata.ivNonce;
- }
-
- public void with(AtKey atKey, Object value) {
- setKeyName(atKey.getFullyQualifiedKeyName());
- setSharedBy(atKey.sharedBy.toString());
- if (atKey.sharedWith != null && !atKey.sharedWith.toString().isEmpty()) {
- setSharedWith(atKey.sharedWith.toString());
- }
- setIsCached(atKey.metadata.isCached);
- setIsHidden(atKey.metadata.isHidden);
- setIsPublic(atKey.metadata.isPublic);
- setMetadata(atKey.metadata);
- setValue(value);
- }
-
- @Override
- public String build() {
- if (key == null || key.isEmpty() || sharedBy == null || sharedBy.isEmpty() || value == null
- || value.toString().isEmpty()) {
- throw new IllegalArgumentException("keyName, sharedBy, and value cannot be null or empty");
- }
- String fullKeyName = buildAtKeyStr();
- String metadata = buildMetadataStr();
- String s = "update" + metadata + ":" + fullKeyName + " " + value.toString();
- return s;
- }
-
- private String buildAtKeyStr() {
- String s = "";
- if (isHidden != null && isHidden) {
- s += "_";
- }
- if (isCached != null && isCached) {
- s += "cached:";
- }
- if (isPublic != null && isPublic) {
- s += "public:";
- }
- if (sharedWith != null && !sharedWith.isEmpty()) {
- s += AtSign.formatAtSign(sharedWith) + ":";
- }
- s += key;
- s += AtSign.formatAtSign(sharedBy);
- return s;
- }
-
- private String buildMetadataStr() {
- Metadata metadata = new Metadata();
- metadata.ttl = ttl;
- metadata.ttb = ttb;
- metadata.ttr = ttr;
- metadata.ccd = ccd;
- metadata.isBinary = isBinary;
- metadata.isEncrypted = isEncrypted;
- metadata.dataSignature = dataSignature;
- metadata.sharedKeyEnc = sharedKeyEnc;
- metadata.pubKeyCS = pubKeyCS;
- metadata.encoding = encoding;
- metadata.ivNonce = ivNonce;
- return metadata.toString();
- }
+ public enum LookupOperation {
+ none, meta, all
+ };
+ /**
+ * A builder to compose an Atsign protocol command with the llookup verb. The llookup
+ * verb is used to look up key values "owned" / shared by the {@link AtSign} that is sending the
+ * command.
+ *
+ * @param keyName The namespace qualified key name (without the sharedBy or sharedWith or public,
+ * hidden or cache qualifiers).
+ * @param sharedBy The {@link AtSign} which is owns / is sharing this key value (this will qualify
+ * the keyName is the built command).
+ * @param sharedWith The {@link AtSign} which is receiving this key value (this will qualify the
+ * keyName is the built command).
+ * @param isHidden Denotes whether the key value is hidden (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isPublic Denotes whether the key value is public (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isCached Denotes whether the key value is cached (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param operation Controls whether lookups return just the value, just the metadata or the value
+ * and metadata.
+ * @param key a {@link AtKey} instance from which keyName, sharedBy, sharedWith and
+ * public/hidden/cached qualifiers will be taken from.
+ * @param rawKey The "raw" protocol key string for the key. i.e. includes keyName, sharedBy,
+ * sharedWith and public/hidden/cached qualifiers (this will override those fields).
+ * @return A correctly formed llookup verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "llookupCommandBuilder", builderClassName = "LlookupCommandBuilder")
+ public static String llookup(String keyName, AtSign sharedBy, AtSign sharedWith, Boolean isHidden, Boolean isPublic,
+ Boolean isCached, LookupOperation operation, AtKey key, String rawKey) {
+
+ String operationString = toOperationString(operation);
+ String keyString;
+ if (rawKey != null) {
+ checkAllNull("both rawKey and key fields are set", keyName, sharedBy, sharedWith, key);
+ keyString = rawKey;
+ } else if (key != null) {
+ checkAllNull("both key and key fields are set", keyName, sharedBy, sharedWith, isHidden, isPublic, isCached);
+ keyString = key.toString();
+ } else {
+ checkNotBlank(keyName, "keyName not set");
+ checkNotNull(sharedBy, "sharedBy not set");
+ MetadataBuilder metadataBuilder = createBlankMetadataBuilder();
+ setIsHiddenIfNotNull(metadataBuilder, isHidden);
+ setIsPublicIfNotNull(metadataBuilder, isPublic);
+ setIsCachedIfNotNull(metadataBuilder, isCached);
+ keyString = toRawKey(keyName, sharedBy, sharedWith, metadataBuilder.build());
+ }
+ return String.format("llookup:%s%s", operationString, keyString);
}
/**
- * Atsign Platform llookup (Local lookup) command builder.
- * Used when key is "owned" by the {@link AtSign} sending the command
+ * A builder to compose an Atsign protocol command with the lookup verb. The lookup
+ * verb is used to look up key values shared by other {@link AtSign}s with the {@link AtSign} that
+ * is sending the command.
+ *
+ * @param keyName The namespace qualified key name (without the sharedBy or sharedWith or public,
+ * hidden or cache qualifiers).
+ * @param sharedBy The {@link AtSign} which is owns / is sharing this key value (this will qualify
+ * the keyName is the built command).
+ * @param operation Controls whether lookups return just the value, just the metadata or the value
+ * and metadata.
+ * @param key a {@link AtKey} instance from which keyName, sharedBy, sharedWith and
+ * public/hidden/cached qualifiers will be taken from.
+ * @param rawKey The "raw" protocol key string for the key. i.e. includes keyName, sharedBy,
+ * sharedWith and public/hidden/cached qualifiers (this will override those fields).
+ * @return A correctly formed lookup verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
-
- public static class LlookupVerbBuilder implements VerbBuilder {
-
- /**
- * Builder argument which controls the scope of the lookup command
- */
- public enum Type {
- NONE, // llookup:
- METADATA, // llookup:meta:
- ALL, // llookup:all:
- }
-
- private String key; // e.g. "test", "location", "email" [required]
- private String sharedBy; // e.g. sharedBy atSign "@alice" [required]
- private String sharedWith = null; // e.g. sharedWith atSign "@bob"
- private Boolean isHidden = null; // if true, adds _ at the beginning of the fullKeyName
- private Boolean isPublic = null; // if [isPublic] is true, then [atKey] is accessible by all atSigns and "public:" will be added to the fullKeyName, if [isPublic] is false, then [atKey] is accessible either by [sharedWith] or [sharedBy]
- private Boolean isCached = null; // if true, will add "cached:" to the fullKeyName
-
- private Type type = Type.NONE;
-
- public void setKeyName(String key) {
- this.key = key;
- }
-
- public void setSharedBy(String sharedBy) {
- this.sharedBy = sharedBy;
- }
-
- public void setSharedWith(String sharedWith) {
- this.sharedWith = sharedWith;
- }
-
- public void setIsHidden(Boolean isHidden) {
- this.isHidden = isHidden;
- }
-
- public void setIsPublic(Boolean isPublic) {
- this.isPublic = isPublic;
- }
-
- public void setIsCached(Boolean isCached) {
- this.isCached = isCached;
- }
-
- public void setType(Type type) {
- this.type = type;
- }
-
- public void with(AtKey atKey, LlookupVerbBuilder.Type type) {
- setKeyName(atKey.getFullyQualifiedKeyName());
- setSharedBy(atKey.sharedBy.toString());
- if (atKey.sharedWith != null && !atKey.sharedWith.toString().isEmpty()) {
- setSharedWith(atKey.sharedWith.toString());
- }
- setIsHidden(atKey.metadata.isHidden);
- setIsPublic(atKey.metadata.isPublic);
- setIsCached(atKey.metadata.isCached);
- setType(type);
- }
-
- @Override
- public String build() {
- if (key == null || key.isEmpty() || sharedBy == null || sharedBy.isEmpty()) {
- throw new IllegalArgumentException("keyName and sharedBy cannot be null or empty");
- }
- String s = "llookup:";
- switch (type) {
- case METADATA:
- s += "meta:";
- break;
- case ALL:
- s += "all:";
- break;
- default:
- break;
- }
- if (isHidden != null && isHidden) {
- s += "_";
- }
- if (isCached != null && isCached) {
- s += "cached:";
- }
- if (isPublic != null && isPublic) {
- s += "public:";
- }
- if (sharedWith != null && !sharedWith.isEmpty()) {
- s += AtSign.formatAtSign(sharedWith) + ":";
- }
- s += key;
- s += AtSign.formatAtSign(sharedBy);
- return s; // eg: "llookup:meta:cached:public:test@bob"
-
- }
-
+ @Builder(builderMethodName = "lookupCommandBuilder", builderClassName = "LookupCommandBuilder")
+ public static String lookup(String keyName, AtSign sharedBy, LookupOperation operation, Keys.SharedKey key,
+ String rawKey) {
+ String operationString = toOperationString(operation);
+ String keyString;
+ if (rawKey != null) {
+ checkAllNull("both rawKey and key fields are set", keyName, sharedBy, key);
+ keyString = rawKey;
+ } else if (key != null) {
+ checkAllNull("both key and key fields are set", keyName, sharedBy);
+ keyString = toRawKey(key.name(), key.sharedBy());
+ } else {
+ checkNotBlank(keyName, "keyName not set");
+ checkNotNull(sharedBy, "sharedBy not set");
+ keyString = toRawKey(keyName, sharedBy);
+ }
+ return String.format("lookup:%s%s", operationString, keyString);
}
/**
- * Atsign Platform lookup command builder.
- * Used when key shared with the {@link AtSign} sending the command.
+ * A builder to compose an Atsign protocol command with the plookup verb. The plookup
+ * verb is used to look up a public key value shared by an {@link AtSign} other than the one that
+ * is sending the command.
+ *
+ * @param keyName The namespace qualified key name (without the sharedBy or sharedWith or public,
+ * hidden or cache qualifiers).
+ * @param sharedBy The {@link AtSign} which is owns / is sharing this key value (this will qualify
+ * the keyName is the built command).
+ * @param bypassCache If true this forces the value to be fetch from the Atsign server that has
+ * shared the key value.
+ * @param operation Controls whether lookups return just the value, just the metadata or the value
+ * and metadata.
+ * @param key a {@link AtKey} instance from which keyName, sharedBy, sharedWith and
+ * public/hidden/cached qualifiers will be taken from.
+ * @param rawKey The "raw" protocol key string for the key. i.e. includes keyName, sharedBy,
+ * sharedWith and public/hidden/cached qualifiers (this will override those fields).
+ * @return A correctly formed plookup verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
- public static class LookupVerbBuilder implements VerbBuilder {
-
- /**
- * Builder argument which controls the scope of the lookup command
- */
- public enum Type {
- NONE, // lookup:
- METADATA, // lookup:meta:
- ALL, // lookup:all:
- }
-
- private String key; // key name e.g. "test", "location", "email" [required]
- private String sharedBy; // sharedBy atSign e.g. "@alice" [required] (not your atSign, the atSign of another secondary, get)
-
- private Type type = Type.NONE;
-
- public void setKeyName(String key) {
- this.key = key;
- }
-
- public void setSharedBy(String sharedBy) {
- this.sharedBy = sharedBy;
- }
-
- public void setType(Type type) {
- this.type = type;
- }
-
- public void with(SharedKey sharedKey, LookupVerbBuilder.Type type) {
- setKeyName(sharedKey.getFullyQualifiedKeyName());
- setSharedBy(sharedKey.sharedBy.toString());
- setType(type);
- }
-
- @Override
- public String build() {
- if (key == null || key.isEmpty() || sharedBy == null || sharedBy.isEmpty()) {
- throw new IllegalArgumentException("keyName and sharedBy cannot be null or empty");
- }
- String s = "lookup:";
- switch (type) {
- case METADATA:
- s += "meta:";
- break;
- case ALL:
- s += "all:";
- break;
- default:
- break;
- }
- s += this.key;
- s += AtSign.formatAtSign(this.sharedBy);
- return s; // eg: "lookup:meta:test@bob"
- }
+ @Builder(builderMethodName = "plookupCommandBuilder", builderClassName = "PlookupCommandBuilder")
+ public static String plookup(String keyName, AtSign sharedBy, Boolean bypassCache, LookupOperation operation,
+ AtKey key, String rawKey) {
+
+ String bypassCacheString = toBypassCacheString(bypassCache);
+ String operationString = toOperationString(operation);
+ String keyString;
+ if (rawKey != null) {
+ checkAllNull("both rawKey and key fields are set", keyName, sharedBy, key);
+ keyString = rawKey;
+ } else if (key != null) {
+ checkAllNull("both key and key fields are set", keyName, sharedBy);
+ keyString = toRawKey(key.name(), key.sharedBy());
+ } else {
+ checkNotBlank(keyName, "keyName not set");
+ checkNotNull(sharedBy, "sharedBy not set");
+ keyString = toRawKey(keyName, sharedBy);
+ }
+
+ return String.format("plookup:%s%s%s", bypassCacheString, operationString, keyString);
}
/**
- * Atsign Platform plookup (public lookup) command builder.
- * Used when key is a public key owned by an {@link AtSign} other than the one sending the command.
+ * A builder to compose an Atsign protocol command with the delete verb. The delete
+ * verb is used to remove key/value pairs into a Key Store. An delete command can only be
+ * sent by the {@link AtSign} that "owns" the key value and can only be sent to their own Atsign
+ * server.
+ *
+ * @param keyName The namespace qualified key name (without the sharedBy or sharedWith or public,
+ * hidden or cache qualifiers).
+ * @param sharedBy The {@link AtSign} which is owns / is sharing this key value (this will qualify
+ * the keyName is the built command).
+ * @param sharedWith The {@link AtSign} which is receiving this key value (this will qualify the
+ * keyName is the built command).
+ * @param isHidden Denotes whether the key value is hidden (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isPublic Denotes whether the key value is public (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param isCached Denotes whether the key value is cached (this will qualify the keyName in the
+ * built command and set the metadata).
+ * @param key a {@link AtKey} instance from which keyName, sharedBy, sharedWith and metadata will be
+ * taken from.
+ * @return A correctly formed delete verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
*/
- public static class PlookupVerbBuilder implements VerbBuilder {
-
- /**
- * Builder argument which controls the scope of the lookup command
- */
- public enum Type {
- NONE, // just get the data
- METADATA, // get the metadata but no data (plookup:meta:)
- ALL, // get the data and metadata (plookup:all:)
- }
-
- // AtKey details
- private String key; // key name (e.g. location, test) [required]
- private String sharedBy; // sharedBy atSign ("@bob") [required]
-
- private Boolean bypassCache = false; // bypass cache (plookup:bypassCache:[true/false]) [optional]
-
- private Type type = Type.NONE;
-
- public void setKeyName(String key) {
- this.key = key;
- }
-
- public void setSharedBy(String sharedBy) {
- this.sharedBy = sharedBy;
- }
-
- public void setType(Type type) {
- this.type = type;
- }
-
- public void setBypassCache(Boolean bypassCache) {
- this.bypassCache = bypassCache;
- }
-
- public void with(PublicKey atKey, PlookupVerbBuilder.Type type) {
- setKeyName(atKey.getFullyQualifiedKeyName());
- setSharedBy(atKey.sharedBy.toString());
- setType(type);
- }
-
- @Override
- public String build() {
- if (this.key == null || this.key.isEmpty() || this.sharedBy == null || this.sharedBy.isEmpty()) {
- throw new IllegalArgumentException("key or sharedBy is null or empty");
- }
- String s = "plookup:";
- if (this.bypassCache != null && this.bypassCache) {
- s += "bypassCache:true:";
- }
- switch (type) {
- case METADATA:
- s += "meta:";
- break;
- case ALL:
- s += "all:";
- break;
- default:
- break;
- }
- s += this.key;
- s += AtSign.formatAtSign(this.sharedBy);
-
- return s; // e.g: "plookup:meta:@alice:test@bob"
- }
-
+ @Builder(builderMethodName = "deleteCommandBuilder", builderClassName = "DeleteCommandBuilder")
+ public static String delete(String keyName, AtSign sharedBy, AtSign sharedWith, Boolean isHidden, Boolean isPublic,
+ Boolean isCached, AtKey key, String rawKey) {
+
+ String keyString;
+ if (rawKey != null) {
+ checkAllNull("both rawKey and key fields are set", keyName, sharedBy, sharedWith, key);
+ keyString = rawKey;
+ } else if (key != null) {
+ checkAllNull("both key and isHidden, isPublic, isCached are set",
+ keyName, sharedBy, sharedWith, isHidden, isPublic, isCached);
+ keyString = key.toString();
+ } else {
+ MetadataBuilder metadataBuilder = createBlankMetadataBuilder();
+ setIsHiddenIfNotNull(metadataBuilder, isHidden);
+ setIsPublicIfNotNull(metadataBuilder, isPublic);
+ setIsCachedIfNotNull(metadataBuilder, isCached);
+ checkNotBlank(keyName, "keyName not set");
+ checkNotNull(sharedBy, "sharedBy not set");
+ keyString = toRawKey(keyName, sharedBy, sharedWith, metadataBuilder.build());
+ }
+
+ return String.format("delete:%s", keyString);
}
/**
- * Atsign Platform delete command builder.
- * Used to delete a key owned by the {@link AtSign} sending the command.
+ * A builder to compose an Atsign protocol command with the scan verb. The scan verb
+ * is used to list the keys in an {@link AtSign}'s Atsign server.
+ *
+ * @param regex If set only show keys that match this regular expression pattern.
+ * @param fromAtSign If set only show keys that are created by the {@link AtSign}.
+ * @param showHidden If true, will show hidden internal keys.
+ * @return A correctly formed scan verb command.
*/
- public static class DeleteVerbBuilder implements VerbBuilder {
-
- private String key; // e.g. "test", "location", "email" [required]
- private String sharedBy; // e.g. sharedBy atSign "@alice" [required]
- private String sharedWith = ""; // e.g. sharedWith atSign "@bob"
- private Boolean isHidden = false;
- private Boolean isPublic = false; // if [isPublic] is true, then [atKey] is accessible by all atSigns and "public:" will be added to the fullKeyName, if [isPublic] is false, then [atKey] is accessible either by [sharedWith] or [sharedBy]
- private Boolean isCached = false; // if true, will add "cached:" to the fullKeyName
+ @Builder(builderMethodName = "scanCommandBuilder", builderClassName = "ScanCommandBuilder")
+ public static String scan(String regex, AtSign fromAtSign, Boolean showHidden) {
- public void setKeyName(String keyName) {
- this.key = keyName;
+ StringBuilder builder = new StringBuilder("scan");
+ if (isTrue(showHidden)) {
+ builder.append(":showHidden:true");
}
-
- public void setSharedBy(String sharedBy) {
- this.sharedBy = sharedBy;
- }
-
- public void setSharedWith(String sharedWith) {
- this.sharedWith = sharedWith;
+ if (fromAtSign != null) {
+ builder.append(':').append(fromAtSign);
}
-
- public void setIsHidden(Boolean isHidden) {
- this.isHidden = isHidden;
+ if (!isBlank(regex)) {
+ builder.append(' ').append(regex);
}
+ return builder.toString();
+ }
- public void setIsPublic(Boolean isPublic) {
- this.isPublic = isPublic;
- }
+ /**
+ * A builder to compose an Atsign protocol command with the notify:messageType:text verb.
+ * The notify:messageType:text verb is used to send an arbitrary message to another
+ * {@link AtSign}.
+ *
+ * @param recipient The {@link AtSign} you wish to send the message to.
+ * @param text The message.
+ * @return A correctly formed notify:messageType:text verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "notifyTextCommandBuilder", builderClassName = "NotifyTextCommandBuilder")
+ public static String notifyText(AtSign recipient, String text) {
+ checkNotNull(recipient, "recipient not set");
+ checkNotBlank(text, "text not set");
+ return String.format("notify:messageType:text:%s:%s", recipient, text);
+ }
- public void setIsCached(Boolean isCached) {
- this.isCached = isCached;
- }
+ /**
+ * The type of key change operation
+ */
+ public enum NotifyOperation {
+ update, delete
+ }
- public void with(AtKey atKey) {
- setKeyName(atKey.getFullyQualifiedKeyName());
- setSharedBy(atKey.sharedBy.toString());
- if (atKey.sharedWith != null && !atKey.sharedWith.toString().isEmpty()) {
- setSharedWith(atKey.sharedWith.toString());
- }
- setIsHidden(atKey.metadata.isHidden);
- setIsPublic(atKey.metadata.isPublic);
- setIsCached(atKey.metadata.isCached);
- }
+ /**
+ * A builder to compose an Atsign protocol command with the
+ * notify:(update|delete):messageType:key verb.
+ * The notify:(update|delete):messageType:key verb is used to send key change notifications
+ * to other
+ * {@link AtSign}s.
+ *
+ * @param operation Update or Delete.
+ * @param recipient The {@link AtSign} to send the notification to.
+ * @param sender The {@link AtSign} that is sending the notification.
+ * @param key The namespace qualified key name.
+ * @param value The updated value for the key.
+ * @param ttr Sets the time to refresh (milliseconds).
+ * @return A correctly formed notify:messageType:key verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "notifyKeyChangeCommandBuilder", builderClassName = "NotifyKeyChangeCommandBuilder")
+ public static String notifyKeyChange(NotifyOperation operation, AtSign recipient, AtSign sender, String key,
+ String value,
+ Long ttr) {
+
+ checkNotBlank(key, "key not set");
+ checkNotNull(operation, "operation not set");
+
+ if (ttr != null) {
+ checkTrue(ttr >= -1, "ttr < -1");
+ checkNotBlank(value, "value not set (mandatory when ttr is set)");
+ }
+
+ return new StringBuilder("notify:")
+ .append(operation)
+ .append(":messageType:key:")
+ .append(ttr != null ? "ttr:" + ttr + ":" : "")
+ .append(recipient != null ? recipient + ":" : "")
+ .append(key)
+ .append(sender != null ? sender : "")
+ .append(!isBlank(value) ? ":" + value : "")
+ .toString();
+ }
- @Override
- public String build() {
- if (key == null || sharedBy == null) {
- throw new IllegalArgumentException("key or sharedBy is null. These are required fields");
- }
+ /**
+ * A builder to compose an Atsign protocol command with the notify:status verb.
+ * The notify:status verb is query the status of a previously sent notification.
+ *
+ * @param notificationId The unique id of a notification. This will have been the response for to a
+ * previously sent notify:(update:delete) command.
+ * @return A correctly formed notify:status verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "notifyStatusCommandBuilder", builderClassName = "NotifyStatusCommandBuilder")
+ public static String notifyStatus(String notificationId) {
- String s = "delete:";
- if (isHidden) {
- s += "_";
- }
- if (isCached) {
- s += "cached:";
- }
- if (isPublic) {
- s += "public:";
- }
- if (sharedWith != null && !sharedWith.isEmpty()) {
- s += AtSign.formatAtSign(sharedWith) + ":";
- }
- s += key;
- s += AtSign.formatAtSign(sharedBy);
- return s; // eg: "delete:cached:public:test@bob"
- }
+ checkNotBlank(notificationId, "notificationId not set");
+ return "notify:status:" + notificationId;
}
/**
- * Atsign Platform scan command builder.
- * Used to list all the keys visible to the {@link AtSign} sending the command.
+ * Types of enroll operations
*/
- public static class ScanVerbBuilder implements VerbBuilder {
-
- // Regex to filter the keys
- private String regex;
+ public enum EnrollOperation {
+ request, approve, deny, revoke, list, fetch, unrevoke, delete
+ }
- // Scans the keys shared by forAtSign
- private String fromAtSign;
+ /**
+ * JSON member names used in enroll parameters
+ */
+ public static class EnrollParameters {
+ public static final String ENROLLMENT_ID = "enrollmentId";
+ public static final String ENCRYPTED_PRIVATE_KEY = "encryptedDefaultEncryptionPrivateKey";
+ public static final String PRIVATE_KEY_IV = "encPrivateKeyIV";
+ public static final String ENCRYPTED_SELF_ENCRYPTION_KEY = "encryptedDefaultSelfEncryptionKey";
+ public static final String SELF_ENCRYPTION_KEY_IV = "selfEncKeyIV";
+ public static final String ENROLLMENT_STATUS_FILTER = "enrollmentStatusFilter";
+ public static final String APP_NAME = "appName";
+ public static final String DEVICE_NAME = "deviceName";
+ public static final String APKAM_PUBLIC_KEY = "apkamPublicKey";
+ public static final String ENCRYPTED_APKAM_SYMMETRIC_KEY = "encryptedAPKAMSymmetricKey";
+ public static final String OTP = "otp";
+ public static final String NAMESPACES = "namespaces";
+ public static final String APKAM_KEYS_EXPIRY_IN_MILLIS = "apkamKeysExpiryInMillis";
+ }
- // Scans for hidden keys (showHidden:true)
- private boolean showHidden = false;
+ /**
+ * A builder to compose an Atsign protocol command with the enroll verb.
+ * The enroll verb is used to submit an APKAM enrollment.
+ *
+ * @param operation The specific enroll operation to perform see {@link EnrollOperation}.
+ * @param status Filters {@link EnrollOperation#list} operations.
+ * @param enrollmentId The unique enrollment id to refer to in fetch, approve,deny,delete,revoke or
+ * unrevoke.
+ * @param encryptPrivateKey The private encryption key which all enrollments share for an
+ * {@link AtSign}. This is mandatory for an approve and the value should be encrypted with
+ * the APKAM symmetric key that was provided by the {@link EnrollOperation#request}.
+ * @param encryptPrivateKeyIv The initialization vector used for the private key encryption.
+ * @param selfEncryptKey The self encryption key which all enrollments share for an
+ * {@link AtSign}. This is mandatory for an approve and the value should be encrypted with
+ * the APKAM symmetric key that was provided by the {@link EnrollOperation#request}.
+ * @param selfEncryptKeyIv The initialization vector used for the self key encryption.
+ * @param appName The application name qualifier for the appName deviceName combination we are
+ * enrolling.
+ * @param deviceName The device name qualifier for the appName deviceName combination we are
+ * enrolling.
+ * @param apkamPublicKey The public authentication key for the appName and device we are enrolling.
+ * @param otp The one time password for {@link EnrollOperation#request}.
+ * @param namespaces A map of namespace access control associations. e.g. ns1 {@code -->} rw, ns2
+ * {@code -->} r (r = read only, rw = read write).
+ * @param apkamSymmetricKey A one-time symmetric key used for the duration of the enrollment
+ * workflow. This should be encrypted with the public encryption key of the {@link AtSign}.
+ * @param ttl The time to live for the enrollment request.
+ * @return A correctly formed enroll verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "enrollCommandBuilder", builderClassName = "EnrollCommandBuilder")
+ public static String enroll(EnrollOperation operation, String status, EnrollmentId enrollmentId,
+ String encryptPrivateKey, String encryptPrivateKeyIv, String selfEncryptKey,
+ String selfEncryptKeyIv, String appName, String deviceName, String apkamPublicKey,
+ String otp, Map namespaces, String apkamSymmetricKey,
+ long ttl) {
- public void setRegex(String regex) {
- this.regex = regex;
- }
+ checkNotNull(operation, "operation not set");
- public void setFromAtSign(String fromAtSign) {
- this.fromAtSign = fromAtSign;
- }
+ Object params = null;
- public void setShowHidden(boolean showHidden) {
- this.showHidden = showHidden;
+ switch (operation) {
+ case list:
+ if (!isBlank(status)) {
+ params = singletonMap(EnrollParameters.ENROLLMENT_STATUS_FILTER, singletonList(status));
+ }
+ break;
+ case approve:
+ checkNotNull(enrollmentId, "enrollmentId not set");
+ checkNotNull(encryptPrivateKey, "encryptPrivateKey not set");
+ checkNotNull(encryptPrivateKeyIv, "encryptPrivateKeyIv not set");
+ checkNotNull(selfEncryptKey, "selfEncryptKey not set");
+ checkNotNull(selfEncryptKeyIv, "selfEncryptKeyIv not set");
+ params = toObjectMap(EnrollParameters.ENROLLMENT_ID, enrollmentId,
+ EnrollParameters.ENCRYPTED_PRIVATE_KEY, encryptPrivateKey,
+ EnrollParameters.PRIVATE_KEY_IV, encryptPrivateKeyIv,
+ EnrollParameters.ENCRYPTED_SELF_ENCRYPTION_KEY, selfEncryptKey,
+ EnrollParameters.SELF_ENCRYPTION_KEY_IV, selfEncryptKeyIv);
+ break;
+ case fetch:
+ case deny:
+ case revoke:
+ case unrevoke:
+ case delete:
+ checkNotNull(enrollmentId, "enrollmentId not set");
+ params = toObjectMap(EnrollParameters.ENROLLMENT_ID, enrollmentId);
+ break;
+ case request:
+ checkNotBlank(appName, "appName not set");
+ checkNotBlank(deviceName, "deviceName not set");
+ checkNotBlank(apkamPublicKey, "apkamPublicKey not set");
+ if (otp == null) {
+ params = toObjectMap(EnrollParameters.APP_NAME, appName,
+ EnrollParameters.DEVICE_NAME, deviceName,
+ EnrollParameters.APKAM_PUBLIC_KEY, apkamPublicKey);
+ } else {
+ checkNotBlank(otp, "otp not set");
+ checkNotNull(namespaces, "namespaces not set");
+ params = toObjectMap(EnrollParameters.APP_NAME, appName,
+ EnrollParameters.DEVICE_NAME, deviceName,
+ EnrollParameters.APKAM_PUBLIC_KEY, apkamPublicKey,
+ EnrollParameters.ENCRYPTED_APKAM_SYMMETRIC_KEY, apkamSymmetricKey,
+ EnrollParameters.OTP, otp,
+ EnrollParameters.NAMESPACES, namespaces,
+ EnrollParameters.APKAM_KEYS_EXPIRY_IN_MILLIS, ttl);
+ }
+ break;
+ default:
+ throw new IllegalArgumentException("unsupported operation");
}
- // r'^scan$|scan(:(?@[^:@\s]+))?(:page:(?\d+))?( (?\S+))?$';
- public String build() {
-
- String command = "scan";
-
- if (showHidden) {
- command += ":showHidden:true";
- }
-
- if (fromAtSign != null && !isBlank(fromAtSign)) {
- command += ":" + fromAtSign;
- }
-
- if (regex != null && !isBlank(regex)) {
- command += " " + regex;
- }
-
- return command;
- }
+ return new StringBuilder("enroll:")
+ .append(operation)
+ .append(params != null ? encodeAsJson(params) : "")
+ .toString();
}
/**
- * Atsign Platform notify command builder.
+ * Types of operation for keys verb
*/
- public static class NotifyTextVerbBuilder implements VerbBuilders.VerbBuilder {
- //notify:((?update|delete):)?(messageType:(?key|text):)?(priority:(?low|medium|high):)?(strategy:(?all|latest):)?(latestN:(?\d+):)?(notifier:(?[^\s:]+):)?(ttln:(?\d+):)?(ttl:(?\d+):)?(ttb:(?\d+):)?(ttr:(?(-)?\d+):)?(ccd:(?true|false):)?(@(?[^@:\s]*)):(?[^:@]((?!:{2})[^@])+)(@(?[^@:\s]+))?(:(?.+))?$
-
- private String recipientAtSign;
- private String text;
-
+ public enum KeysOperation {
+ put, get, delete
+ };
- public void setRecipientAtSign(String recipientAtSign) {
- this.recipientAtSign = recipientAtSign;
+ /**
+ * A builder to compose an Atsign protocol command with the keys verb.
+ * The keys verb is specifically used to update security keys in the Atsign server.
+ *
+ * @param operation put, get or delete.
+ * @param keyName The full qualified key name which includes sharedBy, sharedWith, namespace and
+ * visibility qualifiers.
+ * @return A correctly formed keys verb command.
+ * @throws IllegalArgumentException If mandatory fields are not set or if field values conflict.
+ */
+ @Builder(builderMethodName = "keysCommandBuilder", builderClassName = "KeysCommandBuilder")
+ public static String keys(KeysOperation operation, String keyName) {
+ checkNotNull(operation, "operation not set");
+ if (operation == KeysOperation.get) {
+ checkNotBlank(keyName, "keyName not set");
+ return String.format("keys:get:keyName:%s", keyName);
+ } else {
+ throw new IllegalArgumentException(operation + " not supported");
}
+ }
+ /**
+ * A builder to compose an Atsign protocol command with the otp verb.
+ * The otp verb is used to request a one time password for the enrollment workflow.
+ *
+ * @return A correctly formed otp verb command.
+ */
+ @Builder(builderMethodName = "otpCommandBuilder", builderClassName = "OtpCommandBuilder")
+ public static String otp() {
+ return "otp:get";
+ }
- public void setText(String text) {
- this.text = text;
+ protected static Map toObjectMap(Object... nameValuePairs) {
+ if ((nameValuePairs.length % 2) != 0) {
+ throw new IllegalArgumentException("odd number of parameters");
}
-
-
- public String build() {
-
- if (recipientAtSign == null || recipientAtSign.isEmpty()) {
- throw new IllegalArgumentException("recipientAtSign cannot be null or empty");
- }
-
- if (text == null || text.isEmpty()) {
- throw new IllegalArgumentException("text cannot be null or empty");
- }
-
- if (!recipientAtSign.startsWith("@")) {
- recipientAtSign = "@" + recipientAtSign;
+ Map map = new LinkedHashMap<>();
+ for (int i = 0; i < nameValuePairs.length; i++) {
+ String key = nameValuePairs[i].toString();
+ Object value = nameValuePairs[++i];
+ if (value instanceof TypedString) {
+ map.put(key, value.toString());
+ } else {
+ map.put(key, value);
}
-
- return "notify:messageType:text:" + recipientAtSign + ":" + text;
}
+ return map;
}
- /**
- * Atsign Platform notify command builder.
- */
- public static class NotifyKeyChangeBuilder implements VerbBuilders.VerbBuilder {
-
- // Only allowed values are "update" or "delete"
- private String operation = "update";
- // Optional if key contains the recipient
- private String recipientAtSign;
- private String key;
- // Optional if key contains the owner
- private String senderAtSign;
- // Value to be notified when the change needs to be cached.
- private String value;
-
- // If the key has to be cached by the other @sign
- // ttr of -1 indicated cache forever without a need to refresh the value again.
- // Any other positive value indicates time after which the value needs to be refreshed
- private final int defaultTTRValue = -2;
- private long ttr = defaultTTRValue;
-
-
- public void setOperation(String operation) {
- this.operation = operation;
- }
-
- // This is optional if the key is fully formed. i.e. key in the format @recipientAtSign:phone@senderAtSign
- public void setRecipientAtSign(String recipientAtSign) {
- this.recipientAtSign = recipientAtSign;
+ protected static String encodeAsJson(Object o) {
+ try {
+ return Json.MAPPER.writeValueAsString(o);
+ } catch (JsonProcessingException e) {
+ throw new IllegalArgumentException("json encoding exception", e);
}
+ }
+ private static boolean isTrue(Boolean bool) {
+ return bool != null && bool;
+ }
- public void setKey(String key) {
- this.key = key;
- }
+ private static String toRawKey(String keyName, AtSign sharedBy) {
+ return toRawKey(keyName, sharedBy, null, EMPTY_METADATA);
+ }
- // This is optional if the key is fully formed. i.e. key in the format @recipientAtSign:phone@senderAtSign
- public void setSenderAtSign(String senderAtSign) {
- this.senderAtSign = senderAtSign;
+ private static String toRawKey(String keyName, AtSign sharedBy, AtSign sharedWith, Metadata metadata) {
+ StringBuilder builder = new StringBuilder();
+ if (isTrue(metadata.isHidden())) {
+ builder.append("_");
}
-
-
- public void setValue(String value) {
- this.value = value;
+ if (isTrue(metadata.isCached())) {
+ builder.append("cached:");
}
-
-
- public void setTtr(long ttr) {
- this.ttr = ttr;
+ if (isTrue(metadata.isPublic())) {
+ builder.append("public:");
}
-
-
- //notify:((?update|delete):)?(messageType:(?key|text):)?(priority:(?low|medium|high):)?(strategy:(?all|latest):)?(latestN:(?\d+):)?(notifier:(?[^\s:]+):)?(ttln:(?\d+):)?(ttl:(?\d+):)?(ttb:(?\d+):)?(ttr:(?(-)?\d+):)?(ccd:(?true|false):)?(@(?[^@:\s]*)):(?[^:@]((?!:{2})[^@])+)(@(?[^@:\s]+))?(:(?.+))?$
- public String build() {
-
- if (key == null || isBlank(key)) {
- throw new IllegalArgumentException("key cannot be null or empty");
- }
-
-
- if (!"update".equals(operation) && !"delete".equals(operation)) {
- throw new IllegalArgumentException("Only 'update' and 'delete' are allowed for operation");
- }
-
- if (ttr < -1 && ttr != defaultTTRValue) {
- throw new IllegalArgumentException("Invalid value for ttr. Only -1 and positive numbers are allowed");
- }
-
- if (ttr != defaultTTRValue && (value == null || isBlank(value))) {
- throw new IllegalArgumentException("When the ttr is specified value cannot be null or empty");
- }
-
- String command = "notify:" + operation + ":messageType:key:";
-
- // append ttr
- if (ttr != defaultTTRValue) {
- command += "ttr:" + ttr + ":";
- }
-
- // append recipients @sign if it is not part of the key already
- if (recipientAtSign != null && !isBlank(recipientAtSign)) {
-
- if (!recipientAtSign.startsWith("@")) {
- recipientAtSign = "@" + recipientAtSign;
- }
-
- command += recipientAtSign + ":";
- }
-
- // append the key
- command += key;
-
- if (senderAtSign != null && !isBlank(senderAtSign)) {
-
- if (!senderAtSign.startsWith("@")) {
- senderAtSign = "@" + senderAtSign;
- }
-
- command += senderAtSign;
- }
-
- if (value != null && !isBlank(value)) {
- command += ":" + value;
- }
-
- return command;
+ if (sharedWith != null) {
+ builder.append(sharedWith).append(':');
}
+ builder.append(keyName);
+ builder.append(sharedBy);
+ return builder.toString();
}
- /**
- * Atsign Platform notify command builder.
- */
- public static class NotificationStatusVerbBuilder implements VerbBuilders.VerbBuilder {
-
- private String notificationId;
-
- public void setNotificationId(String notificationId) {
- this.notificationId = notificationId;
+ private static String toOperationString(LookupOperation operation) {
+ if (operation == null || operation == LookupOperation.none) {
+ return "";
}
+ return operation + ":";
+ }
- //notify:status:(?\S+)$';
- public String build() {
-
- if (notificationId == null || isBlank(notificationId)) {
- throw new IllegalArgumentException("notificationId cannot be null or empty");
- }
-
- return "notify:status:" + notificationId;
- }
+ private static String toBypassCacheString(Boolean bypassCache) {
+ return isTrue(bypassCache) ? "bypassCache:true:" : "";
}
+ private static MetadataBuilder createBlankMetadataBuilder() {
+ return Metadata.builder()
+ .isPublic(null)
+ .isEncrypted(null)
+ .isHidden(null)
+ .namespaceAware(null)
+ .isBinary(null)
+ .isCached(null);
+ }
}
diff --git a/at_client/src/test/java/org/atsign/client/api/AtKeyNamesTest.java b/at_client/src/test/java/org/atsign/client/api/AtKeyNamesTest.java
new file mode 100644
index 00000000..3ff710d8
--- /dev/null
+++ b/at_client/src/test/java/org/atsign/client/api/AtKeyNamesTest.java
@@ -0,0 +1,17 @@
+package org.atsign.client.api;
+
+import org.junit.jupiter.api.Test;
+
+import static org.atsign.client.api.AtKeyNames.*;
+import static org.atsign.common.AtSign.createAtSign;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+
+class AtKeyNamesTest {
+
+ @Test
+ void testToSharedByMeKeyNameReturnsExpectedValue() {
+ assertThat(toSharedByMeKeyName(createAtSign("gary")), equalTo("shared_key.gary"));
+ }
+
+}
diff --git a/at_client/src/test/java/org/atsign/client/api/AtKeysTest.java b/at_client/src/test/java/org/atsign/client/api/AtKeysTest.java
index b5adcb37..d79af312 100644
--- a/at_client/src/test/java/org/atsign/client/api/AtKeysTest.java
+++ b/at_client/src/test/java/org/atsign/client/api/AtKeysTest.java
@@ -1,372 +1,100 @@
package org.atsign.client.api;
import static org.atsign.client.util.EnrollmentId.createEnrollmentId;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertNull;
-import static org.junit.jupiter.api.Assertions.assertSame;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+import static org.junit.jupiter.api.Assertions.*;
+import java.security.Key;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.util.Base64;
import java.util.Map;
-import org.atsign.client.util.EnrollmentId;
-import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
class AtKeysTest {
- private AtKeys atKeys;
- private static final String TEST_ENROLLMENT_ID = "test-enrollment-123";
- private static final String TEST_SELF_ENCRYPT_KEY = "testSelfEncryptKey123";
- private static final String TEST_APKAM_SYMMETRIC_KEY = "testApkamSymmetricKey";
-
- @BeforeEach
- void setUp() {
- atKeys = new AtKeys();
- }
-
- // EnrollmentId Tests
-
@Test
void testHasEnrollmentIdReturnsFalseWhenNotSet() {
- assertFalse(atKeys.hasEnrollmentId());
+ AtKeys keys = AtKeys.builder().build();
+ assertFalse(keys.hasEnrollmentId());
}
@Test
void testHasEnrollmentIdReturnsTrueWhenSet() {
- atKeys.setEnrollmentId(createEnrollmentId(TEST_ENROLLMENT_ID));
- assertTrue(atKeys.hasEnrollmentId());
- }
-
- @Test
- void testSetAndGetEnrollmentId() {
- EnrollmentId enrollmentId = createEnrollmentId(TEST_ENROLLMENT_ID);
- atKeys.setEnrollmentId(enrollmentId);
- assertEquals(enrollmentId, atKeys.getEnrollmentId());
- }
-
- @Test
- void testSetEnrollmentIdSupportsChaining() {
- EnrollmentId enrollmentId = createEnrollmentId(TEST_ENROLLMENT_ID);
- AtKeys result = atKeys.setEnrollmentId(enrollmentId);
- assertSame(atKeys, result);
- }
-
- @Test
- void testGetEnrollmentIdReturnsNullWhenNotSet() {
- assertNull(atKeys.getEnrollmentId());
- }
-
- // Self Encryption Key Tests
-
- @Test
- void testSetAndGetSelfEncryptionKey() {
- atKeys.setSelfEncryptKey(TEST_SELF_ENCRYPT_KEY);
- assertEquals(TEST_SELF_ENCRYPT_KEY, atKeys.getSelfEncryptKey());
- }
-
- @Test
- void testSetSelfEncryptKeySupportsChaining() {
- AtKeys result = atKeys.setSelfEncryptKey(TEST_SELF_ENCRYPT_KEY);
- assertSame(atKeys, result);
- }
-
- @Test
- void testGetSelfEncryptionKeyReturnsNullWhenNotSet() {
- assertNull(atKeys.getSelfEncryptKey());
- }
-
- // APKAM Public Key Tests
-
- @Test
- void testSetAndGetApkamPublicKeyAsString() {
- String testKey = "testPublicKey123";
- atKeys.setApkamPublicKey(testKey);
- assertEquals(testKey, atKeys.getApkamPublicKey());
- }
-
- @Test
- void testSetApkamPublicKeyFromPublicKeyObject() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- keyGen.initialize(2048);
- KeyPair keyPair = keyGen.generateKeyPair();
-
- atKeys.setApkamPublicKey(keyPair.getPublic());
-
- assertNotNull(atKeys.getApkamPublicKey());
- String expected = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
- assertEquals(expected, atKeys.getApkamPublicKey());
- }
-
- @Test
- void testSetApkamPublicKeyWithStringSupportsChaining() {
- AtKeys result = atKeys.setApkamPublicKey("testKey");
- assertSame(atKeys, result);
+ AtKeys keys = AtKeys.builder().enrollmentId(createEnrollmentId("123")).build();
+ assertTrue(keys.hasEnrollmentId());
}
@Test
- void testSetApkamPublicKeyWithObjectSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setApkamPublicKey(keyPair.getPublic());
- assertSame(atKeys, result);
- }
-
- // APKAM Private Key Tests
-
- @Test
- void testSetAndGetApkamPrivateKeyAsString() {
- String testKey = "testPrivateKey123";
- atKeys.setApkamPrivateKey(testKey);
- assertEquals(testKey, atKeys.getApkamPrivateKey());
- }
-
- @Test
- void testSetApkamPrivateKeyFromPrivateKeyObject() throws Exception {
+ void testApkamKeyPairBuilderExtension() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
- atKeys.setApkamPrivateKey(keyPair.getPrivate());
+ AtKeys keys = AtKeys.builder()
+ .apkamKeyPair(keyPair)
+ .build();
- assertNotNull(atKeys.getApkamPrivateKey());
- String expected = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
- assertEquals(expected, atKeys.getApkamPrivateKey());
+ assertThat(keys.getApkamPublicKey(), equalTo(toBase64(keyPair.getPublic())));
+ assertThat(keys.getApkamPrivateKey(), equalTo(toBase64(keyPair.getPrivate())));
}
@Test
- void testSetApkamPrivateKeyWithStringSupportsChaining() {
- AtKeys result = atKeys.setApkamPrivateKey("testKey");
- assertSame(atKeys, result);
- }
-
- @Test
- void testSetApkamPrivateKeyWithObjectSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setApkamPrivateKey(keyPair.getPrivate());
- assertSame(atKeys, result);
- }
-
- // APKAM Key Pair Tests
-
- @Test
- void testSetApkamKeyPair() throws Exception {
+ void testEncryptKeyPairBuilderExtension() throws Exception {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
keyGen.initialize(2048);
KeyPair keyPair = keyGen.generateKeyPair();
- atKeys.setApkamKeyPair(keyPair);
-
- assertNotNull(atKeys.getApkamPublicKey());
- assertNotNull(atKeys.getApkamPrivateKey());
-
- String expectedPublic = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
- String expectedPrivate = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
-
- assertEquals(expectedPublic, atKeys.getApkamPublicKey());
- assertEquals(expectedPrivate, atKeys.getApkamPrivateKey());
- }
-
- @Test
- void testSetApkamKeyPairSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setApkamKeyPair(keyPair);
- assertSame(atKeys, result);
- }
-
- // hasPkamKeys Tests
+ AtKeys keys = AtKeys.builder()
+ .encryptKeyPair(keyPair)
+ .build();
- @Test
- void testHasPkamKeysReturnsFalseWhenNotSet() {
- assertFalse(atKeys.hasPkamKeys());
+ assertThat(keys.getEncryptPublicKey(), equalTo(toBase64(keyPair.getPublic())));
+ assertThat(keys.getEncryptPrivateKey(), equalTo(toBase64(keyPair.getPrivate())));
}
@Test
- void testHasPkamKeysReturnsFalseWhenOnlyPublicKeySet() {
- atKeys.setApkamPublicKey("testPublicKey");
- assertFalse(atKeys.hasPkamKeys());
+ void testHasPkamKeyReturnsFalseWhenNotSet() {
+ AtKeys keys = AtKeys.builder().build();
+ assertFalse(keys.hasPkamKey());
}
@Test
- void testHasPkamKeysReturnsFalseWhenOnlyPrivateKeySet() {
- atKeys.setApkamPrivateKey("testPrivateKey");
- assertFalse(atKeys.hasPkamKeys());
+ void testHasPkamKeyReturnsFalseWhenOnlyPublicKeySet() {
+ AtKeys keys = AtKeys.builder().apkamPublicKey("xxxx").build();
+ assertFalse(keys.hasPkamKey());
}
@Test
- void testHasPkamKeysReturnsTrueWhenBothSet() {
- atKeys.setApkamPublicKey("testPublicKey");
- atKeys.setApkamPrivateKey("testPrivateKey");
- assertTrue(atKeys.hasPkamKeys());
+ void testHasPkamKeyReturnsTrueWhenPrivateKeySet() {
+ AtKeys keys = AtKeys.builder().apkamPrivateKey("xxxx").build();
+ assertTrue(keys.hasPkamKey());
}
- // Encrypt Public Key Tests
-
@Test
- void testSetAndGetEncryptPublicKeyAsString() {
- String testKey = "testEncryptPublicKey";
- atKeys.setEncryptPublicKey(testKey);
- assertEquals(testKey, atKeys.getEncryptPublicKey());
- }
-
- @Test
- void testSetEncryptPublicKeyFromPublicKeyObject() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- keyGen.initialize(2048);
- KeyPair keyPair = keyGen.generateKeyPair();
-
- atKeys.setEncryptPublicKey(keyPair.getPublic());
-
- assertNotNull(atKeys.getEncryptPublicKey());
- String expected = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
- assertEquals(expected, atKeys.getEncryptPublicKey());
+ void testGetReturnsNullForKeyBeforePut() {
+ AtKeys keys = AtKeys.builder().build();
+ assertThat(keys.get("key1"), nullValue());
}
@Test
- void testSetEncryptPublicKeyWithStringSupportsChaining() {
- AtKeys result = atKeys.setEncryptPublicKey("testKey");
- assertSame(atKeys, result);
- }
-
- @Test
- void testSetEncryptPublicKeyWithObjectSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setEncryptPublicKey(keyPair.getPublic());
- assertSame(atKeys, result);
- }
-
- // Encrypt Private Key Tests
-
- @Test
- void testSetAndGetEncryptPrivateKeyAsString() {
- String testKey = "testEncryptPrivateKey";
- atKeys.setEncryptPrivateKey(testKey);
- assertEquals(testKey, atKeys.getEncryptPrivateKey());
- }
-
- @Test
- void testSetEncryptPrivateKeyFromPrivateKeyObject() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- keyGen.initialize(2048);
- KeyPair keyPair = keyGen.generateKeyPair();
-
- atKeys.setEncryptPrivateKey(keyPair.getPrivate());
-
- assertNotNull(atKeys.getEncryptPrivateKey());
- String expected = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
- assertEquals(expected, atKeys.getEncryptPrivateKey());
- }
-
- @Test
- void testSetEncryptPrivateKeyWithStringSupportsChaining() {
- AtKeys result = atKeys.setEncryptPrivateKey("testKey");
- assertSame(atKeys, result);
- }
-
- @Test
- void testSetEncryptPrivateKeyWithObjectSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setEncryptPrivateKey(keyPair.getPrivate());
- assertSame(atKeys, result);
- }
-
- // Encrypt Key Pair Tests
-
- @Test
- void testSetEncryptKeyPair() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- keyGen.initialize(2048);
- KeyPair keyPair = keyGen.generateKeyPair();
-
- atKeys.setEncryptKeyPair(keyPair);
-
- assertNotNull(atKeys.getEncryptPublicKey());
- assertNotNull(atKeys.getEncryptPrivateKey());
-
- String expectedPublic = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
- String expectedPrivate = Base64.getEncoder().encodeToString(keyPair.getPrivate().getEncoded());
-
- assertEquals(expectedPublic, atKeys.getEncryptPublicKey());
- assertEquals(expectedPrivate, atKeys.getEncryptPrivateKey());
- }
-
- @Test
- void testSetEncryptKeyPairSupportsChaining() throws Exception {
- KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA");
- KeyPair keyPair = keyGen.generateKeyPair();
- AtKeys result = atKeys.setEncryptKeyPair(keyPair);
- assertSame(atKeys, result);
- }
-
- // APKAM Symmetric Key Tests
-
- @Test
- void testSetAndGetApkamSymmetricKey() {
- atKeys.setApkamSymmetricKey(TEST_APKAM_SYMMETRIC_KEY);
- assertEquals(TEST_APKAM_SYMMETRIC_KEY, atKeys.getApkamSymmetricKey());
- }
-
- @Test
- void testSetApkamSymmetricKeySupportsChaining() {
- AtKeys result = atKeys.setApkamSymmetricKey(TEST_APKAM_SYMMETRIC_KEY);
- assertSame(atKeys, result);
- }
-
- @Test
- void testGetApkamSymmetricKeyReturnsNullWhenNotSet() {
- assertNull(atKeys.getApkamSymmetricKey());
- }
-
- // Cache Tests
-
- @Test
- void testPutAndGetFromCache() {
- String key = "customKey";
- String value = "customValue";
-
- atKeys.put(key, value);
- assertEquals(value, atKeys.get(key));
- }
-
- @Test
- void testGetReturnsNullForNonExistentKey() {
- assertNull(atKeys.get("nonExistentKey"));
- }
-
- @Test
- void testPutOverwritesExistingKeyValue() {
- String key = "testKey";
- atKeys.put(key, "value1");
- atKeys.put(key, "value2");
- assertEquals("value2", atKeys.get(key));
- }
-
- @Test
- void testPutMultipleKeys() {
- atKeys.put("key1", "value1");
- atKeys.put("key2", "value2");
- atKeys.put("key3", "value3");
-
- assertEquals("value1", atKeys.get("key1"));
- assertEquals("value2", atKeys.get("key2"));
- assertEquals("value3", atKeys.get("key3"));
+ void testGetReturnsExpectedValueForKeyAfterPut() {
+ AtKeys keys = AtKeys.builder().build();
+ keys.put("key1", "value1");
+ assertThat(keys.get("key1"), equalTo("value1"));
+ assertThat(keys.get("key2"), nullValue());
}
@Test
void testGetCacheReturnsUnmodifiableMap() {
- atKeys.put("key1", "value1");
- atKeys.put("key2", "value2");
+ AtKeys keys = AtKeys.builder().build();
+ keys.put("key1", "value1");
+ keys.put("key2", "value2");
- Map cache = atKeys.getCache();
+ Map cache = keys.getCache();
assertNotNull(cache);
assertEquals(2, cache.size());
@@ -378,26 +106,8 @@ void testGetCacheReturnsUnmodifiableMap() {
});
}
- @Test
- void testGetCacheReturnsEmptyUnmodifiableMapWhenEmpty() {
- Map cache = atKeys.getCache();
-
- assertNotNull(cache);
- assertTrue(cache.isEmpty());
-
- assertThrows(UnsupportedOperationException.class, () -> {
- cache.put("key1", "value1");
- });
+ private static String toBase64(Key key) {
+ return Base64.getEncoder().encodeToString(key.getEncoded());
}
- @Test
- void testGetCacheReflectsChanges() {
- atKeys.put("key1", "value1");
- Map cache1 = atKeys.getCache();
- assertEquals(1, cache1.size());
-
- atKeys.put("key2", "value2");
- Map cache2 = atKeys.getCache();
- assertEquals(2, cache2.size());
- }
}
diff --git a/at_client/src/test/java/org/atsign/common/AtClientValidationIT.java b/at_client/src/test/java/org/atsign/common/AtClientValidationIT.java
index 66fdd8b7..fdd270fd 100644
--- a/at_client/src/test/java/org/atsign/common/AtClientValidationIT.java
+++ b/at_client/src/test/java/org/atsign/common/AtClientValidationIT.java
@@ -4,9 +4,8 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.atsign.client.util.AtClientValidation;
-import org.atsign.common.Keys.PublicKey;
-import org.atsign.common.Keys.SelfKey;
-import org.atsign.common.Keys.SharedKey;
+import org.atsign.common.exceptions.AtSecondaryConnectException;
+import org.atsign.common.exceptions.AtSecondaryNotFoundException;
import org.atsign.cucumber.helpers.Helpers;
import org.atsign.virtualenv.VirtualEnv;
import org.junit.jupiter.api.BeforeAll;
@@ -34,120 +33,22 @@ public void atSignExistsTest() {
});
// empty atSign
- assertThrows(IllegalArgumentException.class, () -> {
+ assertThrows(AtSecondaryNotFoundException.class, () -> {
AtSign atSign = new AtSign("");
AtClientValidation.atSignExists(atSign, VE_ROOT_URL);
});
// root does not contain atSign
- assertThrows(AtException.class, () -> {
+ assertThrows(AtSecondaryNotFoundException.class, () -> {
AtSign atSign = new AtSign("someAtSignThatDNE456");
AtClientValidation.atSignExists(atSign, VE_ROOT_URL);
});
// invalid root
- assertThrows(AtException.class, () -> {
+ assertThrows(AtSecondaryConnectException.class, () -> {
AtSign atSign = new AtSign("smoothalligator");
AtClientValidation.atSignExists(atSign, "invalidroot:32123");
});
}
-
- // validate AtKey object is ready (checks atKey.name validity, metadata
- // validity, and if sharedWith exists)
- @Test
- public void validateAtKeyTest() {
-
- // ====================================
- // PublicKey tests
- // ====================================
-
- // null publicKey
- assertThrows(AtException.class, () -> {
- PublicKey publicKey = null;
- AtClientValidation.validateAtKey(publicKey, VE_ROOT_URL);
- });
-
- // public key with invalid ttr
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@bob");
- PublicKey publicKey = new KeyBuilders.PublicKeyBuilder(sharedBy).key("test").build();
- publicKey.metadata.ttr = -2;
- AtClientValidation.validateAtKey(publicKey, "");
- });
-
- // ====================================
- // SelfKey tests
- // ====================================
-
- // null selfKey
- assertThrows(AtException.class, () -> {
- SelfKey selfKey = null;
- AtClientValidation.validateAtKey(selfKey, VE_ROOT_URL);
- });
-
- // self key with invalid keyName
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@bob");
- SelfKey selfKey = new KeyBuilders.SelfKeyBuilder(sharedBy).key("t est").build();
- AtClientValidation.validateAtKey(selfKey, VE_ROOT_URL);
- });
-
- // self key with non-existent sharedWith atSign in root
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@nonexistentatsign");
- AtSign sharedWith = new AtSign("@nonexistentatsign"); // atSign does not exist in root
- SelfKey selfKey = new KeyBuilders.SelfKeyBuilder(sharedBy, sharedWith).key("test").build();
- AtClientValidation.validateAtKey(selfKey, VE_ROOT_URL);
- });
-
- // ====================================
- // SharedKey tests
- // ====================================
-
- // null shared key test
- assertThrows(AtException.class, () -> {
- SharedKey sharedKey = null;
- AtClientValidation.validateAtKey(sharedKey, VE_ROOT_URL);
- });
-
- // shared key with ttr < -1
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@bob");
- AtSign sharedWith = new AtSign("@alice");
- SharedKey sharedKey = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key("test").build();
- sharedKey.metadata.ttr = -22323;
- AtClientValidation.validateAtKey(sharedKey, VE_ROOT_URL);
- });
-
- // shared key with invalid keyName
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@bob");
- AtSign sharedWith = new AtSign("@alice");
- SharedKey sharedKey = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key("t est").build();
- AtClientValidation.validateAtKey(sharedKey, VE_ROOT_URL);
- });
-
- // shared key with invalid sharedWith atSign (atSign dne in root)
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@wildgreen");
- AtSign sharedWith = new AtSign("@nonexistentatsign"); // atSign does not exist in root
- SharedKey sharedKey = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key("test").build();
- AtClientValidation.validateAtKey(sharedKey, VE_ROOT_URL);
- });
-
- // empty root url
- assertThrows(AtException.class, () -> {
- AtSign sharedBy = new AtSign("@bob");
- AtSign sharedWith = new AtSign("@alice");
- SharedKey sharedKey = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key("test").build();
- AtClientValidation.validateAtKey(sharedKey, "");
- });
-
- // ====================================
- // PrivateHiddenKey tests
- // ====================================
-
- // TODO
- }
}
diff --git a/at_client/src/test/java/org/atsign/common/AtClientValidationTest.java b/at_client/src/test/java/org/atsign/common/AtClientValidationTest.java
deleted file mode 100644
index 50989dfd..00000000
--- a/at_client/src/test/java/org/atsign/common/AtClientValidationTest.java
+++ /dev/null
@@ -1,118 +0,0 @@
-package org.atsign.common;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.jupiter.api.Assertions.assertThrows;
-
-import org.atsign.client.util.AtClientValidation;
-import org.atsign.common.exceptions.AtInvalidAtKeyException;
-import org.junit.jupiter.api.Test;
-
-public class AtClientValidationTest {
-
- // valid key names (like "test", but not "cached:public:test@bob" <-- these key
- // names will always fail this test)
- @Test
- public void validateKeyNameTest() {
- // null key name
- AtException ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- String keyName = null;
- AtClientValidation.validateKeyName(keyName);
- });
- assertThat(ex.getMessage(), equalTo("Key cannot be null or empty"));
-
- // empty key name
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- String keyName = "";
- AtClientValidation.validateKeyName(keyName);
- });
- assertThat(ex.getMessage(), equalTo("Key cannot be null or empty"));
-
- // key name with @
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- String keyName = "test@bob";
- AtClientValidation.validateKeyName(keyName);
- });
- assertThat(ex.getMessage(), equalTo("Key cannot contain @"));
-
- // key name with spaces
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- String keyName = " te st ";
- AtClientValidation.validateKeyName(keyName);
- });
- assertThat(ex.getMessage(), equalTo("Key cannot have spaces"));
- }
-
- // valid metadata (null check, ttl, ttb, ttr)
- @Test
- public void validateMetadataTest() {
-
- // null metadata
- AtException ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = null;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("Metadata cannot be null"));
-
- // null ttl
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = null;
- metadata.ttb = 0;
- metadata.ttr = -1;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttl cannot be null and cannot be negative"));
-
- // negative ttl
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = -100;
- metadata.ttb = 0;
- metadata.ttr = -1;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttl cannot be null and cannot be negative"));
-
- // null ttb
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = 0;
- metadata.ttb = null;
- metadata.ttr = -1;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttb cannot be null and cannot be negative"));
-
- // negative ttb
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = 0;
- metadata.ttb = -100;
- metadata.ttr = -1;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttb cannot be null and cannot be negative"));
-
- // null ttr
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = 0;
- metadata.ttb = 0;
- metadata.ttr = null;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttr cannot be null and cannot be < -1"));
-
- // ttr < -1
- ex = assertThrows(AtInvalidAtKeyException.class, () -> {
- Metadata metadata = new Metadata();
- metadata.ttl = 0;
- metadata.ttb = 0;
- metadata.ttr = -2;
- AtClientValidation.validateMetadata(metadata);
- });
- assertThat(ex.getMessage(), equalTo("ttr cannot be null and cannot be < -1"));
-
- }
-}
diff --git a/at_client/src/test/java/org/atsign/common/AtSignTest.java b/at_client/src/test/java/org/atsign/common/AtSignTest.java
new file mode 100644
index 00000000..4fc0edab
--- /dev/null
+++ b/at_client/src/test/java/org/atsign/common/AtSignTest.java
@@ -0,0 +1,31 @@
+package org.atsign.common;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.nullValue;
+
+import org.junit.jupiter.api.Test;
+
+class AtSignTest {
+
+ @Test
+ void testStaticCreateMethod() {
+ assertThat(AtSign.createAtSign("@fred"), equalTo(new AtSign("@fred")));
+ assertThat(AtSign.createAtSign("fred"), equalTo(new AtSign("@fred")));
+ assertThat(AtSign.createAtSign(null), nullValue());
+ assertThat(AtSign.createAtSign(""), nullValue());
+ }
+
+ @Test
+ void testWithoutPrefixReturnsExpectedResult() {
+ assertThat(new AtSign("fred").withoutPrefix(), equalTo("fred"));
+ assertThat(new AtSign("@fred").withoutPrefix(), equalTo("fred"));
+ }
+
+ @Test
+ void testFormatAtSignReturnsExpectedResults() {
+ assertThat(AtSign.formatAtSign("@fred"), equalTo("@fred"));
+ assertThat(AtSign.formatAtSign("fred"), equalTo("@fred"));
+ assertThat(AtSign.formatAtSign("@fred "), equalTo("@fred"));
+ }
+}
diff --git a/at_client/src/test/java/org/atsign/common/FromStringTest.java b/at_client/src/test/java/org/atsign/common/FromStringTest.java
index 9e3b0bf1..e2dc639e 100644
--- a/at_client/src/test/java/org/atsign/common/FromStringTest.java
+++ b/at_client/src/test/java/org/atsign/common/FromStringTest.java
@@ -6,6 +6,7 @@
import com.fasterxml.jackson.core.JsonProcessingException;
import org.junit.jupiter.api.Test;
+import static org.atsign.common.AtSign.createAtSign;
import static org.junit.jupiter.api.Assertions.*;
public class FromStringTest {
@@ -14,13 +15,14 @@ public class FromStringTest {
@Test
public void fromStringTest0() throws AtException {
// no llookup meta
- AtKey atKey = Keys.fromString("public:publickey@alice");
-
- assertEquals(true, atKey.metadata.isPublic);
- assertEquals(false, atKey.metadata.isEncrypted);
- assertEquals(false, atKey.metadata.isHidden);
- assertEquals("publickey", atKey.name);
- assertEquals("@alice", atKey.sharedBy.toString());
+ AtKey atKey = Keys.keyBuilder().rawKey("public:publickey@alice").build();
+
+ Metadata metadata = atKey.metadata();
+ assertEquals(true, metadata.isPublic());
+ assertEquals(false, metadata.isEncrypted());
+ assertEquals(false, metadata.isHidden());
+ assertEquals("publickey", atKey.name());
+ assertEquals(createAtSign("@alice"), atKey.sharedBy());
}
@Test
@@ -35,26 +37,27 @@ public void fromStringTest1() throws AtException, JsonProcessingException {
+ "\"isBinary\":false,\"isEncrypted\":false,"
+ "\"dataSignature\":null,\"sharedKeyEnc\":null,\"pubKeyCS\":null}");
- AtKey atKey = Keys.fromString(KEY_NAME_STR, response);
+ AtKey atKey = fromString(KEY_NAME_STR, response);
assertEquals(KEY_NAME_STR, atKey.toString());
- assertEquals(true, atKey.metadata.isPublic);
- assertEquals("publickey", atKey.name);
- assertEquals("@bob", atKey.sharedBy.toString());
- assertEquals("2022-07-13T21:54:28.519Z", atKey.metadata.createdAt.toString());
- assertEquals("2022-07-13T21:54:28.519Z", atKey.metadata.updatedAt.toString());
- assertEquals("2022-07-13T21:54:28.519Z", atKey.metadata.availableAt.toString());
- assertNull(atKey.metadata.expiresAt);
- assertNull(atKey.metadata.refreshAt);
- assertEquals(0, atKey.metadata.ttl.intValue());
- assertEquals(0, atKey.metadata.ttb.intValue());
- assertNull(atKey.metadata.ttr);
- assertNull(atKey.metadata.ccd);
- assertEquals(false, atKey.metadata.isBinary);
- assertEquals(false, atKey.metadata.isEncrypted);
- assertNull(atKey.metadata.dataSignature);
- assertNull(atKey.metadata.sharedKeyEnc);
- assertNull(atKey.metadata.pubKeyCS);
+ Metadata metadata = atKey.metadata();
+ assertEquals(true, metadata.isPublic());
+ assertEquals("publickey", atKey.name());
+ assertEquals("@bob", atKey.sharedBy().toString());
+ assertEquals("2022-07-13T21:54:28.519Z", metadata.createdAt().toString());
+ assertEquals("2022-07-13T21:54:28.519Z", metadata.updatedAt().toString());
+ assertEquals("2022-07-13T21:54:28.519Z", metadata.availableAt().toString());
+ assertNull(metadata.expiresAt());
+ assertNull(metadata.refreshAt());
+ assertEquals(0, metadata.ttl().intValue());
+ assertEquals(0, metadata.ttb().intValue());
+ assertNull(metadata.ttr());
+ assertNull(metadata.ccd());
+ assertEquals(false, metadata.isBinary());
+ assertEquals(false, metadata.isEncrypted());
+ assertNull(metadata.dataSignature());
+ assertNull(metadata.sharedKeyEnc());
+ assertNull(metadata.pubKeyCS());
}
@Test
@@ -72,29 +75,38 @@ public void fromStringTest2() throws AtException, JsonProcessingException {
Secondary.Response response = new Secondary.Response();
response.setRawDataResponse(LLOOKUP_META_STR);
- AtKey atKey = Keys.fromString(KEY_NAME_STR, response);
+ AtKey atKey = fromString(KEY_NAME_STR, response);
assertEquals(KEY_NAME_STR, atKey.toString());
- assertEquals(false, atKey.metadata.isPublic);
- assertEquals("test", atKey.name);
- assertEquals("@bob", atKey.sharedBy.toString());
- assertEquals("2022-07-27T22:12:58.077Z", atKey.metadata.createdAt.toString());
- assertEquals("2022-07-27T22:12:58.077Z", atKey.metadata.updatedAt.toString());
- assertEquals("2022-07-27T22:12:58.077Z", atKey.metadata.availableAt.toString());
- assertEquals("2022-07-27T22:42:58.077Z", atKey.metadata.expiresAt.toString());
- assertNull(atKey.metadata.refreshAt);
- assertEquals(1800000, atKey.metadata.ttl.intValue());
- assertEquals(0, atKey.metadata.ttb.intValue());
- assertNull(atKey.metadata.ttr);
- assertNull(atKey.metadata.ccd);
- assertFalse(atKey.metadata.isBinary);
- assertTrue(atKey.metadata.isEncrypted);
+ Metadata metadata = atKey.metadata();
+ assertEquals(false, metadata.isPublic());
+ assertEquals("test", atKey.name());
+ assertEquals("@bob", atKey.sharedBy().toString());
+ assertEquals("2022-07-27T22:12:58.077Z", metadata.createdAt().toString());
+ assertEquals("2022-07-27T22:12:58.077Z", metadata.updatedAt().toString());
+ assertEquals("2022-07-27T22:12:58.077Z", metadata.availableAt().toString());
+ assertEquals("2022-07-27T22:42:58.077Z", metadata.expiresAt().toString());
+ assertNull(metadata.refreshAt());
+ assertEquals(1800000L, metadata.ttl());
+ assertEquals(0L, metadata.ttb());
+ assertNull(metadata.ttr());
+ assertNull(metadata.ccd());
+ assertFalse(metadata.isBinary());
+ assertTrue(metadata.isEncrypted());
// noinspection SpellCheckingInspection
assertEquals(
"oIq0kHvwQieVrhOs4dJLN61qNP73bNLLNPTRW7tAdapIZF3kSMrNVCcTAWWWyzb2Tyii51uZ7zlIYmHWuS4tIE0lMzrUeXGcfQhOrdjkrxf4qEceNR1qLa7tDjOAb8xuhf/zJ3yaen8NGswfKWwQluga/52SchFClrR99xEI93s=",
- atKey.metadata.dataSignature);
- assertNull(atKey.metadata.sharedKeyEnc);
- assertNull(atKey.metadata.pubKeyCS);
+ metadata.dataSignature());
+ assertNull(metadata.sharedKeyEnc());
+ assertNull(metadata.pubKeyCS());
}
+ public static AtKey fromString(String rawKey, Secondary.Response metadataResponse)
+ throws AtException, JsonProcessingException {
+ Metadata metadata = Metadata.fromJson(metadataResponse.getRawDataResponse());
+ return Keys.keyBuilder()
+ .rawKey(rawKey)
+ .metadata(metadata)
+ .build();
+ }
}
diff --git a/at_client/src/test/java/org/atsign/common/JsonTest.java b/at_client/src/test/java/org/atsign/common/JsonTest.java
new file mode 100644
index 00000000..1f350c22
--- /dev/null
+++ b/at_client/src/test/java/org/atsign/common/JsonTest.java
@@ -0,0 +1,7 @@
+package org.atsign.common;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+class JsonTest {
+
+}
diff --git a/at_client/src/test/java/org/atsign/common/KeyStringUtilTest.java b/at_client/src/test/java/org/atsign/common/KeyStringUtilTest.java
deleted file mode 100644
index 8de5799d..00000000
--- a/at_client/src/test/java/org/atsign/common/KeyStringUtilTest.java
+++ /dev/null
@@ -1,510 +0,0 @@
-package org.atsign.common;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
-import static org.junit.jupiter.api.Assertions.*;
-
-import org.atsign.client.util.KeyStringUtil;
-import org.atsign.client.util.KeyStringUtil.KeyType;
-import org.junit.jupiter.api.Test;
-
-public class KeyStringUtilTest {
- // https://docs.google.com/spreadsheets/d/1EOcF_vznBoKWXxRT8dbeG47RP7wnF30ubwXghganTlk/edit#gid=0
-
- // Row 4 Public key
- @Test
- public void publicKey() {
- String KEY_NAME = "public:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(null, keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- // Row 5 Public Hidden key
- @Test
- public void publicKey2() {
- String KEY_NAME = "public:_phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:_phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("_phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // Row 6 Public Hidden key
- @Test
- public void publicKey3() {
- String KEY_NAME = "public:__phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:__phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("__phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // Row 7A Public key and SharedWith populated
- public void publicKey4A() {
- String KEY_NAME = "public:@bob:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:@bob:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertEquals("@bob", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- // Row 7B Public key and SharedWith populated
- @Test
- public void publicKey4B() {
- String KEY_NAME = "public:@alice:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:@alice:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertEquals("@alice", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- }
-
- // Row 8 self key (sharedWith not populated)
- @Test
- public void selfKey1() {
- String KEY_NAME = "phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- // Row 9 Self key (sharedWith populated)
- @Test
- public void selfKey2() {
- String KEY_NAME = "@bob:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@bob:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertEquals("@bob", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- // Row 10 Self hidden key (sharedWith populated)
- @Test
- public void selfKey3() {
- String KEY_NAME = "@bob:_phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@bob:_phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("_phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertEquals("@bob", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // row 11 Self Hidden Key without sharedWith
- @Test
- public void selfKey4() {
- String KEY_NAME = "_phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("_phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("_phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PRIVATE_HIDDEN_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // Row 12 SharedKey
- @Test
- public void sharedKey1() {
- String KEY_NAME = "@bob:phone@alice";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@bob:phone@alice", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedWith());
- assertEquals("@alice", keyStringUtil.getSharedBy());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- // Row 13 Shared and hidden
- @Test
- public void sharedKey2() {
- String KEY_NAME = "@alice:_phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@alice:_phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("_phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertEquals("@alice", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // Row 14A Private keys
- @Test
- public void privateKey1() {
- String KEY_NAME = "private:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("private:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PRIVATE_HIDDEN_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- // Row 14B Private keys
- @Test
- public void privateKey2() {
- String KEY_NAME = "privatekey:phone@bob";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("privatekey:phone@bob", keyStringUtil.getFullKeyName());
- assertEquals("phone", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PRIVATE_HIDDEN_KEY, keyStringUtil.getKeyType());
- assertEquals("@bob", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertTrue(keyStringUtil.isHidden());
- }
-
- /**
- * 0: @farinataanxious:lemon@sportsunconscious
- * 1: @farinataanxious:shared_key@sportsunconscious
- * 2: @farinataanxious:test@sportsunconscious
- * 3: @sportsunconscious:shared_key@sportsunconscious
- * 4: @sportsunconscious:signing_privatekey@sportsunconscious
- * 5: public:publickey@farinataanxious
- * 6: public:publickey@sportsunconscious
- * 7: public:signing_publickey@sportsunconscious
- * 8: shared_key.farinataanxious@sportsunconscious
- * 9: shared_key.sportsunconscious@sportsunconscious
- */
- @Test
- public void suKey1() {
- String KEY_NAME = "@farinataanxious:lemon@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@farinataanxious:lemon@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("lemon", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertEquals("@farinataanxious", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey2() {
- String KEY_NAME = "@farinataanxious:shared_key@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@farinataanxious:shared_key@sportsunconscious", keyStringUtil.getFullKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertEquals("@farinataanxious", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey3() {
- String KEY_NAME = "@farinataanxious:test@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@farinataanxious:test@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("test", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertEquals("@farinataanxious", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey4() {
- String KEY_NAME = "@sportsunconscious:shared_key@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@sportsunconscious:shared_key@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey5() {
- String KEY_NAME = "@sportsunconscious:signing_privatekey@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@sportsunconscious:signing_privatekey@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("signing_privatekey", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey6() {
- String KEY_NAME = "public:publickey@farinataanxious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:publickey@farinataanxious", keyStringUtil.getFullKeyName());
- assertEquals("publickey", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@farinataanxious", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey7() {
- String KEY_NAME = "public:publickey@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("public:publickey@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("publickey", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.PUBLIC_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey8() {
- String KEY_NAME = "shared_key.farinataanxious@sportsunconscious";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("shared_key.farinataanxious@sportsunconscious", keyStringUtil.getFullKeyName());
- assertEquals("shared_key.farinataanxious", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@sportsunconscious", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void suKey9() {
- String KEY_NAME =
- "atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator",
- keyStringUtil.getFullKeyName());
- assertEquals("atconnections.hacktheleague.smoothalligator.at_contact.mospherepro", keyStringUtil.getKeyName());
- assertEquals("hacktheleague", keyStringUtil.getNamespace());
-
- }
-
- /**
- * smoothalligator
- * 0: @abbcservicesinc:shared_key@smoothalligator
- * 1: @denise:shared_key@smoothalligator
- * 2: @er_nobile_14:shared_key@smoothalligator
- * 3: @fascinatingsnow:shared_key@smoothalligator
- * 4: @hacktheleague:shared_key@smoothalligator
- * 5: @smoothalligator:signing_privatekey@smoothalligator
- * 6: @wildgreen:shared_key@smoothalligator
- * 7:
- * atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator
- * 8: atconnections.denise.smoothalligator.at_contact.mospherepro.denise@smoothalligator
- * 9:
- * atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator
- * 10: atconnections.wildgreen.smoothalligator.at_contact.mospherepro.wildgreen@smoothalligator
- * 11: @smoothalligator:shared_key@abbcservicesinc
- * 12: @smoothalligator:shared_key@denise
- * 13: @smoothalligator:shared_key@fascinatingsnow
- * 14: @smoothalligator:shared_key@wildgreen
- * 15: public:firstname.wavi.wavi@abbcservicesinc
- * 16: public:firstname.wavi.wavi@wildgreen
- * 17: public:image.wavi.wavi@abbcservicesinc
- * 18: public:image.wavi.wavi@denise
- * 19: public:image.wavi.wavi@wildgreen
- * 20: public:lastname.wavi.wavi@abbcservicesinc
- * 21: public:lastname.wavi.wavi@wildgreen
- * 22: public:publickey@abbcservicesinc
- * 23: public:publickey@denise
- * 24: public:publickey@er_nobile_14
- * 25: public:publickey@fascinatingsnow
- * 26: public:publickey@hacktheleague
- * 27: public:publickey@wildgreen
- * 28: public:email.wavi.wavi@smoothalligator
- * 29: public:field_order_of_self.wavi.wavi@smoothalligator
- * 30: public:firstname.wavi.wavi@smoothalligator
- * 31: public:following_by_self.at_follows.wavi.at_follows@smoothalligator
- * 32: public:lastname.wavi.wavi@smoothalligator
- * 33: public:privateaccount.wavi.wavi@smoothalligator
- * 34: public:publickey@smoothalligator
- * 35: public:signing_publickey@smoothalligator
- * 36: public:theme_color.wavi.wavi@smoothalligator
- * 37: publickey.fascinatingsnow.fascinatingsnow@smoothalligator
- * 38: senthistory_v2.mospherepro.mospherepro@smoothalligator
- * 39: shared_key.abbcservicesinc@smoothalligator
- * 40: shared_key.denise@smoothalligator
- * 41: shared_key.er_nobile_14@smoothalligator
- * 42: shared_key.fascinatingsnow@smoothalligator
- * 43: shared_key.hacktheleague@smoothalligator
- * 44: shared_key.wildgreen@smoothalligator
- */
-
- @Test
- public void saTest1() {
- String KEY_NAME = "@abbcservicesinc:shared_key@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@abbcservicesinc:shared_key@smoothalligator", keyStringUtil.getFullKeyName());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@smoothalligator", keyStringUtil.getSharedBy());
- assertEquals("@abbcservicesinc", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void saTest2() {
- String KEY_NAME = "@denise:shared_key@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@denise:shared_key@smoothalligator", keyStringUtil.getFullKeyName());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@smoothalligator", keyStringUtil.getSharedBy());
- assertEquals("@denise", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void saTest3() {
- String KEY_NAME = "@er_nobile_14:shared_key@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@er_nobile_14:shared_key@smoothalligator", keyStringUtil.getFullKeyName());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@smoothalligator", keyStringUtil.getSharedBy());
- assertEquals("@er_nobile_14", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- assertNull(keyStringUtil.getNamespace());
- }
-
- @Test
- public void saTest4() {
- String KEY_NAME = "@fascinatingsnow:shared_key@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("@fascinatingsnow:shared_key@smoothalligator", keyStringUtil.getFullKeyName());
- assertEquals("shared_key", keyStringUtil.getKeyName());
- assertNull(keyStringUtil.getNamespace());
- assertEquals(KeyType.SHARED_KEY, keyStringUtil.getKeyType());
- assertEquals("@smoothalligator", keyStringUtil.getSharedBy());
- assertEquals("@fascinatingsnow", keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void saTest7() {
- String KEY_NAME =
- "atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator";
- KeyStringUtil keyStringUtil = new KeyStringUtil(KEY_NAME);
- assertEquals("atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator",
- keyStringUtil.getFullKeyName());
- assertEquals("atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro", keyStringUtil.getKeyName());
- assertEquals("abbcservicesinc", keyStringUtil.getNamespace());
- assertEquals(KeyType.SELF_KEY, keyStringUtil.getKeyType());
- assertEquals("@smoothalligator", keyStringUtil.getSharedBy());
- assertNull(keyStringUtil.getSharedWith());
- assertFalse(keyStringUtil.isCached());
- assertFalse(keyStringUtil.isHidden());
- }
-
- @Test
- public void testGetNamespaceReturnsNullForKeyStringsWithNoNamespace() {
- assertNamespace("public:location@alice", null);
- assertNamespace("selfkey1@alice", null);
- assertNamespace("@bob:phone@alice", null);
-
- assertNamespace("public:_hiddenlocation@alice", null);
- assertNamespace("_hiddenselfkey1@alice", null);
- assertNamespace("@bob:__hiddenphone@alice", null);
-
- assertNamespace("cached:@bob:phone@alice", null);
- }
-
- @Test
- public void testGetNamespaceReturnsNullForReservedSharedKeyPrefix() {
- assertNamespace("shared_key.bob@alice", null);
- }
-
- @Test
- public void testGetNamespaceReturnsNamespaceForKeyStringWithNamespace() {
- assertNamespace("public:location.ns@alice", "ns");
- assertNamespace("public:a.location.ns@alice", "ns");
- assertNamespace("a.b.selfkey1.ns@alice", "ns");
- assertNamespace("@bob:a.phone.ns@alice", "ns");
- assertNamespace("@bob:a.b.c.phone.ns@alice", "ns");
-
- assertNamespace("public:_a.hiddenlocation.ns@alice", "ns");
- assertNamespace("_a.hiddenselfkey1.ns@alice", "ns");
- assertNamespace("@bob:__a.b.hiddenphone.ns@alice", "ns");
- }
-
- private static void assertNamespace(String fullKeyName, String expected) {
- KeyStringUtil util = new KeyStringUtil(fullKeyName);
- assertThat(util.getNamespace(), equalTo(expected));
- }
-
- private static void assertGetKeyNameAndGetNamespace(String fullKeyName,
- String expectedKeyName,
- String expectedNamespace) {
- KeyStringUtil util = new KeyStringUtil(fullKeyName);
- assertThat(util.getKeyName(), equalTo(expectedKeyName));
- assertThat(util.getNamespace(), equalTo(expectedNamespace));
- }
-
-
-}
diff --git a/at_client/src/test/java/org/atsign/common/KeysTest.java b/at_client/src/test/java/org/atsign/common/KeysTest.java
new file mode 100644
index 00000000..d1263354
--- /dev/null
+++ b/at_client/src/test/java/org/atsign/common/KeysTest.java
@@ -0,0 +1,1277 @@
+package org.atsign.common;
+
+import static org.atsign.common.AtSign.createAtSign;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.Test;
+
+class KeysTest {
+
+ @Test
+ void testPublicKeyBuilderThrowsExpectedExceptionWhenSharedByIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().build());
+ assertThat(ex.getMessage(), containsString("sharedBy is not set"));
+ }
+
+ @Test
+ void testPublicKeyBuilderThrowsExpectedExceptionWhenKeyNameIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).build());
+ assertThat(ex.getMessage(), containsString("name is not set"));
+ }
+
+ @Test
+ void testPublicKeyBuilderWithNoNamespaceCreatesExpectedKey() {
+ Keys.PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("public:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.FALSE)
+ .build()));
+ }
+
+ @Test
+ void testPublicKeyBuilderWithNamespaceCreatesExpectedKey() {
+ Keys.PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .namespace("ns")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("public:key1.ns@fred"));
+ }
+
+ @Test
+ void testPublicKeyBuilderWithAdditionalMetadataFieldsCreatesExpectedKey() {
+ Keys.PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.FALSE)
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build()));
+ }
+
+ @Test
+ void testPublicKeyBuilderWithMetadataFieldsOverridesCreatesExpectedKey() {
+ Keys.PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .isCached(true)
+ .isBinary(true)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.TRUE)
+ .isEncrypted(Boolean.FALSE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+ assertThat(key.toString(), equalTo("cached:public:key1@fred"));
+ }
+
+ @Test
+ void testKeyBuilderCreatesExpectedKeyForPublicKeys() {
+ Keys.AtKey key = Keys.keyBuilder().rawKey("public:key1@fred").build();
+
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("public:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.FALSE)
+ .build()));
+
+ key = Keys.keyBuilder().rawKey("cached:public:key1@fred").build();
+
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("cached:public:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.TRUE)
+ .isEncrypted(Boolean.FALSE)
+ .build()));
+
+ key = Keys.keyBuilder().rawKey("cached:public:_key1@fred").build();
+
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("_key1"));
+ assertThat(key.toString(), equalTo("cached:public:_key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.TRUE)
+ .isCached(Boolean.TRUE)
+ .isEncrypted(Boolean.FALSE)
+ .build()));
+
+ key = Keys.keyBuilder().rawKey("public:key1@fred").metadata(Metadata.builder().isEncrypted(true).build()).build();
+
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("public:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.TRUE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testSelfKeyBuilderThrowsExpectedExceptionWhenSharedByIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.selfKeyBuilder().build());
+ assertThat(ex.getMessage(), containsString("sharedBy is not set"));
+ }
+
+ @Test
+ void testSelfKeyBuilderThrowsExpectedExceptionWhenKeyNameIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.selfKeyBuilder().sharedBy(createAtSign("fred")).build());
+ assertThat(ex.getMessage(), containsString("name is not set"));
+ }
+
+ @Test
+ void testSelfKeyBuilderWithNoNamespaceCreatesExpectedKey() {
+ Keys.SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testSelfKeyBuilderWithNamespaceCreatesExpectedKey() {
+ Keys.SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .namespace("ns")
+ .build();
+
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.toString(), equalTo("key1.ns@fred"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ }
+
+ @Test
+ void testSelfKeyBuilderWithSharedWithCreatesExpectedKey() {
+ Keys.SelfKey key = Keys.selfKeyBuilder()
+ .sharedWith(createAtSign("fred"))
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .namespace("ns")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("fred")));
+ assertThat(key.toString(), equalTo("@fred:key1.ns@fred"));
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ }
+
+ @Test
+ void testSelfKeyBuilderWithAdditionalMetadataFieldsCreatesExpectedKey() {
+ Keys.SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build()));
+ }
+
+ @Test
+ void testSelfKeyBuilderWithMetadataFieldsOverridesCreatesExpectedKey() {
+ Keys.SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .isBinary(true)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testKeyBuilderCreatesExpectedSelfKey() {
+ Keys.AtKey key = Keys.keyBuilder()
+ .rawKey("key1@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.toString(), equalTo("key1@fred"));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+
+ key = Keys.keyBuilder()
+ .rawKey("key1.ns@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.toString(), equalTo("key1.ns@fred"));
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+
+ key = Keys.keyBuilder()
+ .rawKey("@fred:key1.ns@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("fred")));
+ assertThat(key.toString(), equalTo("@fred:key1.ns@fred"));
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+
+ key = Keys.keyBuilder()
+ .rawKey("@fred:key1.ns@fred")
+ .metadata(Metadata.builder().isBinary(true).build())
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+
+ }
+
+ @Test
+ void testSharedKeyBuilderThrowsExpectedExceptionWhenSharedByIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.sharedKeyBuilder().build());
+ assertThat(ex.getMessage(), containsString("sharedBy is not set"));
+ }
+
+ @Test
+ void testSharedKeyBuilderThrowsExpectedExceptionWhenKeyNameIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.sharedKeyBuilder().sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin")).build());
+ assertThat(ex.getMessage(), containsString("name is not set"));
+ }
+
+ @Test
+ void testSharedKeyBuilderThrowsExpectedExceptionWhenSharedKeyWithIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.sharedKeyBuilder().sharedBy(createAtSign("fred")).name("key1")
+ .build());
+ assertThat(ex.getMessage(), containsString("sharedWith is not set"));
+ }
+
+ @Test
+ void testSharedKeyBuilderThrowsExpectedExceptionWhenRawKeyAndOtherFieldsSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.sharedKeyBuilder().name("key1").rawKey("colin@:key1@fred")
+ .build());
+ assertThat(ex.getMessage(), containsString("both rawKey and other fields set"));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithNoNamespaceCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithRawKeyNoNamespaceCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .rawKey("@colin:key1@fred")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithCachedRawKeyCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .rawKey("cached:@colin:key1@fred")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("cached:@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.TRUE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithNamespaceCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .namespace("ns")
+ .build();
+
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.toString(), equalTo("@colin:key1.ns@fred"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithRawKeyWithNamespaceCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .rawKey("@colin:key1.ns@fred")
+ .build();
+
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.toString(), equalTo("@colin:key1.ns@fred"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithAdditionalMetadataFieldsCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .ttl(1000L)
+ .ttb(2000L)
+ .ttr(3000L)
+ .build()));
+ }
+
+ @Test
+ void testSharedKeyBuilderWithMetadataFieldsOverridesCreatesExpectedKey() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .isBinary(true)
+ .build();
+
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+ }
+
+ @Test
+ void testKeyBuilderCreatesExpectedSharedKey() {
+ Keys.AtKey key = Keys.keyBuilder()
+ .rawKey("@colin:key1@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+
+ key = Keys.keyBuilder()
+ .rawKey("cached:@colin:key1@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("cached:@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.TRUE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+
+ key = Keys.keyBuilder()
+ .rawKey("@colin:_key1@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("_key1"));
+ assertThat(key.toString(), equalTo("@colin:_key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.TRUE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .build()));
+
+ key = Keys.keyBuilder()
+ .rawKey("@colin:key1@fred")
+ .metadata(Metadata.builder().isBinary(true).build())
+ .build();
+
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.sharedWith(), equalTo(createAtSign("colin")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("@colin:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.FALSE)
+ .isCached(Boolean.FALSE)
+ .isEncrypted(Boolean.TRUE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+
+ }
+
+ @Test
+ void testUpdateMissingMetadataWorksAsExpected() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .isBinary(true)
+ .ttl(1000L)
+ .build();
+
+ Metadata metadata = Metadata.builder()
+ .ttl(2000L)
+ .ttb(3000L)
+ .isBinary(false)
+ .build();
+
+ key.updateMissingMetadata(metadata);
+
+ assertThat(key.metadata().ttl(), equalTo(1000L));
+ assertThat(key.metadata().ttb(), equalTo(3000L));
+ assertThat(key.metadata().isBinary(), equalTo(true));
+ }
+
+ @Test
+ void testOverwriteMetadataWorksAsExpected() {
+ Keys.SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .sharedWith(createAtSign("colin"))
+ .name("key1")
+ .isBinary(true)
+ .ttl(1000L)
+ .build();
+
+ Metadata metadata = Metadata.builder()
+ .ttl(2000L)
+ .ttb(3000L)
+ .isBinary(false)
+ .build();
+
+ key.overwriteMetadata(metadata);
+
+ assertThat(key.metadata().ttl(), equalTo(2000L));
+ assertThat(key.metadata().ttb(), equalTo(3000L));
+ assertThat(key.metadata().isBinary(), equalTo(false));
+ }
+
+ @Test
+ void testPrivateHiddenKeyBuilderThrowsExpectedExceptionWhenSharedByIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.privateHiddenKeyBuilder().build());
+ assertThat(ex.getMessage(), containsString("sharedBy is not set"));
+ }
+
+ @Test
+ void testPrivateHiddenKeyBuilderThrowsExpectedExceptionWhenKeyNameIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.privateHiddenKeyBuilder().sharedBy(createAtSign("fred"))
+ .build());
+ assertThat(ex.getMessage(), containsString("name is not set"));
+ }
+
+ @Test
+ void testPrivateHiddenKeyBuilderWithNoNamespaceCreatesExpectedKey() {
+ Keys.PrivateHiddenKey key = Keys.privateHiddenKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .rawKey("private:key1@fred")
+ .build();
+
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("private:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.TRUE)
+ .isCached(Boolean.FALSE)
+ .build()));
+ }
+
+ @Test
+ void testPrivateHiddenKeyBuilderWithNamespaceCreatesExpectedKey() {
+ Keys.PrivateHiddenKey key = Keys.privateHiddenKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key1")
+ .namespace("ns")
+ .rawKey("private:key1.ns@fred")
+ .build();
+
+ assertThat(key.name(), equalTo("key1.ns"));
+ assertThat(key.toString(), equalTo("private:key1.ns@fred"));
+ assertThat(key.namespace(), equalTo("ns"));
+ assertThat(key.nameWithoutNamespace(), equalTo("key1"));
+ }
+
+ @Test
+ void testKeyBuilderCreatesExpectedPrivateHiddenKey() {
+ Keys.AtKey key = Keys.keyBuilder()
+ .rawKey("private:key1@fred")
+ .build();
+
+ assertThat(key, instanceOf(Keys.PrivateHiddenKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("private:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.TRUE)
+ .isCached(Boolean.FALSE)
+ .build()));
+
+ key = Keys.keyBuilder()
+ .rawKey("private:key1@fred")
+ .metadata(Metadata.builder().isBinary(true).build())
+ .build();
+
+ assertThat(key, instanceOf(Keys.PrivateHiddenKey.class));
+ assertThat(key.sharedBy(), equalTo(createAtSign("fred")));
+ assertThat(key.name(), equalTo("key1"));
+ assertThat(key.toString(), equalTo("private:key1@fred"));
+ assertThat(key.metadata(), equalTo(Metadata.builder()
+ .isPublic(Boolean.FALSE)
+ .isHidden(Boolean.TRUE)
+ .isCached(Boolean.FALSE)
+ .isBinary(Boolean.TRUE)
+ .build()));
+ }
+
+ //
+ // Migrated KeyStringUtilTest.java
+ //
+
+ @Test
+ public void testKeyBuilderWithPublicKeyRawKey() throws Exception {
+ Keys.AtKey key = Keys.keyBuilder().rawKey("public:phone@bob").build();
+
+ assertThat(key.toString(), equalTo("public:phone@bob"));
+
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ // Row 5 Public Hidden key
+ @Test
+ public void publicKey2() throws Exception {
+ String KEY_NAME = "public:_phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.toString(), equalTo("public:_phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("_phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ }
+
+ // Row 6 Public Hidden key
+ @Test
+ public void publicKey3() throws Exception {
+ String KEY_NAME = "public:__phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.toString(), equalTo("public:__phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("__phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ }
+
+ // Row 7A Public key and SharedWith populated
+ public void publicKey4A() throws Exception {
+ String KEY_NAME = "public:@bob:phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("public:@bob:phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith().toString(), equalTo("@bob"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ // Row 7B Public key and SharedWith populated
+ // TODO: query this scenario
+ @Test
+ public void publicKey4B() throws Exception {
+ String KEY_NAME = "public:@alice:phone@bob";
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class, () -> Keys.keyBuilder().rawKey(KEY_NAME).build());
+ assertThat(ex.getMessage(), containsString("does NOT match any raw key parser"));
+ }
+
+ // Row 8 self key (sharedWith not populated)
+ @Test
+ public void selfKey1() throws Exception {
+ String KEY_NAME = "phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ // Row 9 Self key (sharedWith populated)
+ @Test
+ public void selfKey2() throws Exception {
+ String KEY_NAME = "@bob:phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@bob:phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith().toString(), equalTo("@bob"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ // Row 10 Self hidden key (sharedWith populated)
+ @Test
+ public void selfKey3() throws Exception {
+ String KEY_NAME = "@bob:_phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@bob:_phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("_phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith().toString(), equalTo("@bob"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ }
+
+ // row 11 Self Hidden Key without sharedWith
+ @Test
+ public void selfKey4() throws Exception {
+ String KEY_NAME = "_phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("_phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("_phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ }
+
+ // Row 12 SharedKey
+ @Test
+ public void sharedKey1() throws Exception {
+ String KEY_NAME = "@bob:phone@alice";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@bob:phone@alice"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedWith().toString(), equalTo("@bob"));
+ assertThat(key.sharedBy().toString(), equalTo("@alice"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ // Row 13 Shared and hidden
+ @Test
+ public void sharedKey2() throws Exception {
+ String KEY_NAME = "@alice:_phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@alice:_phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("_phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith().toString(), equalTo("@alice"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ }
+
+ // Row 14A Private keys
+ // TODO: query this scenario
+ @Test
+ public void privateKey1() throws Exception {
+ String KEY_NAME = "private:phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("private:phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PrivateHiddenKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ assertThat(key.metadata().isPublic(), is(false));
+ }
+
+ // Row 14B Private keys
+ // TODO: query this scenario
+ @Test
+ public void privateKey2() throws Exception {
+ String KEY_NAME = "privatekey:phone@bob";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("privatekey:phone@bob"));
+ assertThat(key.nameWithoutNamespace(), equalTo("phone"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PrivateHiddenKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@bob"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(true));
+ assertThat(key.metadata().isPublic(), is(false));
+ }
+
+ /**
+ * 0: @farinataanxious:lemon@sportsunconscious
+ * 1: @farinataanxious:shared_key@sportsunconscious
+ * 2: @farinataanxious:test@sportsunconscious
+ * 3: @sportsunconscious:shared_key@sportsunconscious
+ * 4: @sportsunconscious:signing_privatekey@sportsunconscious
+ * 5: public:publickey@farinataanxious
+ * 6: public:publickey@sportsunconscious
+ * 7: public:signing_publickey@sportsunconscious
+ * 8: shared_key.farinataanxious@sportsunconscious
+ * 9: shared_key.sportsunconscious@sportsunconscious
+ */
+ @Test
+ public void suKey1() throws Exception {
+ String KEY_NAME = "@farinataanxious:lemon@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@farinataanxious:lemon@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("lemon"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith().toString(), equalTo("@farinataanxious"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey2() throws Exception {
+ String KEY_NAME = "@farinataanxious:shared_key@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@farinataanxious:shared_key@sportsunconscious"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith().toString(), equalTo("@farinataanxious"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey3() throws Exception {
+ String KEY_NAME = "@farinataanxious:test@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@farinataanxious:test@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("test"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith().toString(), equalTo("@farinataanxious"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey4() throws Exception {
+ String KEY_NAME = "@sportsunconscious:shared_key@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@sportsunconscious:shared_key@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey5() throws Exception {
+ String KEY_NAME = "@sportsunconscious:signing_privatekey@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@sportsunconscious:signing_privatekey@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("signing_privatekey"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey6() throws Exception {
+ String KEY_NAME = "public:publickey@farinataanxious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("public:publickey@farinataanxious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("publickey"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@farinataanxious"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey7() throws Exception {
+ String KEY_NAME = "public:publickey@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("public:publickey@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("publickey"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.PublicKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey8() throws Exception {
+ String KEY_NAME = "shared_key.farinataanxious@sportsunconscious";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("shared_key.farinataanxious@sportsunconscious"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key.farinataanxious"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@sportsunconscious"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void suKey9() throws Exception {
+ String KEY_NAME =
+ "atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertEquals("atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator",
+ key.toString());
+ assertThat(key.nameWithoutNamespace(),
+ equalTo("atconnections.hacktheleague.smoothalligator.at_contact.mospherepro"));
+ assertThat(key.namespace(), equalTo("hacktheleague"));
+
+ }
+
+ /**
+ * smoothalligator
+ * 0: @abbcservicesinc:shared_key@smoothalligator
+ * 1: @denise:shared_key@smoothalligator
+ * 2: @er_nobile_14:shared_key@smoothalligator
+ * 3: @fascinatingsnow:shared_key@smoothalligator
+ * 4: @hacktheleague:shared_key@smoothalligator
+ * 5: @smoothalligator:signing_privatekey@smoothalligator
+ * 6: @wildgreen:shared_key@smoothalligator
+ * 7:
+ * atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator
+ * 8: atconnections.denise.smoothalligator.at_contact.mospherepro.denise@smoothalligator
+ * 9:
+ * atconnections.hacktheleague.smoothalligator.at_contact.mospherepro.hacktheleague@smoothalligator
+ * 10: atconnections.wildgreen.smoothalligator.at_contact.mospherepro.wildgreen@smoothalligator
+ * 11: @smoothalligator:shared_key@abbcservicesinc
+ * 12: @smoothalligator:shared_key@denise
+ * 13: @smoothalligator:shared_key@fascinatingsnow
+ * 14: @smoothalligator:shared_key@wildgreen
+ * 15: public:firstname.wavi.wavi@abbcservicesinc
+ * 16: public:firstname.wavi.wavi@wildgreen
+ * 17: public:image.wavi.wavi@abbcservicesinc
+ * 18: public:image.wavi.wavi@denise
+ * 19: public:image.wavi.wavi@wildgreen
+ * 20: public:lastname.wavi.wavi@abbcservicesinc
+ * 21: public:lastname.wavi.wavi@wildgreen
+ * 22: public:publickey@abbcservicesinc
+ * 23: public:publickey@denise
+ * 24: public:publickey@er_nobile_14
+ * 25: public:publickey@fascinatingsnow
+ * 26: public:publickey@hacktheleague
+ * 27: public:publickey@wildgreen
+ * 28: public:email.wavi.wavi@smoothalligator
+ * 29: public:field_order_of_self.wavi.wavi@smoothalligator
+ * 30: public:firstname.wavi.wavi@smoothalligator
+ * 31: public:following_by_self.at_follows.wavi.at_follows@smoothalligator
+ * 32: public:lastname.wavi.wavi@smoothalligator
+ * 33: public:privateaccount.wavi.wavi@smoothalligator
+ * 34: public:publickey@smoothalligator
+ * 35: public:signing_publickey@smoothalligator
+ * 36: public:theme_color.wavi.wavi@smoothalligator
+ * 37: publickey.fascinatingsnow.fascinatingsnow@smoothalligator
+ * 38: senthistory_v2.mospherepro.mospherepro@smoothalligator
+ * 39: shared_key.abbcservicesinc@smoothalligator
+ * 40: shared_key.denise@smoothalligator
+ * 41: shared_key.er_nobile_14@smoothalligator
+ * 42: shared_key.fascinatingsnow@smoothalligator
+ * 43: shared_key.hacktheleague@smoothalligator
+ * 44: shared_key.wildgreen@smoothalligator
+ */
+
+ @Test
+ public void saTest1() throws Exception {
+ String KEY_NAME = "@abbcservicesinc:shared_key@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@abbcservicesinc:shared_key@smoothalligator"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@smoothalligator"));
+ assertThat(key.sharedWith().toString(), equalTo("@abbcservicesinc"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void saTest2() throws Exception {
+ String KEY_NAME = "@denise:shared_key@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@denise:shared_key@smoothalligator"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@smoothalligator"));
+ assertThat(key.sharedWith().toString(), equalTo("@denise"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void saTest3() throws Exception {
+ String KEY_NAME = "@er_nobile_14:shared_key@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@er_nobile_14:shared_key@smoothalligator"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@smoothalligator"));
+ assertThat(key.sharedWith().toString(), equalTo("@er_nobile_14"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ assertThat(key.namespace(), nullValue());
+ }
+
+ @Test
+ public void saTest4() throws Exception {
+ String KEY_NAME = "@fascinatingsnow:shared_key@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertThat(key.toString(), equalTo("@fascinatingsnow:shared_key@smoothalligator"));
+ assertThat(key.nameWithoutNamespace(), equalTo("shared_key"));
+ assertThat(key.namespace(), nullValue());
+ assertThat(key, instanceOf(Keys.SharedKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@smoothalligator"));
+ assertThat(key.sharedWith().toString(), equalTo("@fascinatingsnow"));
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void saTest7() throws Exception {
+ String KEY_NAME =
+ "atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator";
+ Keys.AtKey key = Keys.keyBuilder().rawKey(KEY_NAME).build();
+ assertEquals("atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro.abbcservicesinc@smoothalligator",
+ key.toString());
+ assertThat(key.nameWithoutNamespace(),
+ equalTo("atconnections.abbcservicesinc.smoothalligator.at_contact.mospherepro"));
+ assertThat(key.namespace(), equalTo("abbcservicesinc"));
+ assertThat(key, instanceOf(Keys.SelfKey.class));
+ assertThat(key.sharedBy().toString(), equalTo("@smoothalligator"));
+ assertThat(key.sharedWith(), nullValue());
+ assertThat(key.metadata().isCached(), is(false));
+ assertThat(key.metadata().isHidden(), is(false));
+ }
+
+ @Test
+ public void testGetNamespaceReturnsNullForKeyStringsWithNoNamespace() throws Exception {
+ assertNamespace("public:location@alice", null);
+ assertNamespace("selfkey1@alice", null);
+ assertNamespace("@bob:phone@alice", null);
+
+ assertNamespace("public:_hiddenlocation@alice", null);
+ assertNamespace("_hiddenselfkey1@alice", null);
+ assertNamespace("@bob:__hiddenphone@alice", null);
+
+ assertNamespace("cached:@bob:phone@alice", null);
+ }
+
+ @Test
+ public void testGetNamespaceReturnsNullForReservedSharedKeyPrefix() throws Exception {
+ assertNamespace("shared_key.bob@alice", null);
+ }
+
+ @Test
+ public void testGetNamespaceReturnsNamespaceForKeyStringWithNamespace() throws Exception {
+ assertNamespace("public:location.ns@alice", "ns");
+ assertNamespace("public:a.location.ns@alice", "ns");
+ assertNamespace("a.b.selfkey1.ns@alice", "ns");
+ assertNamespace("@bob:a.phone.ns@alice", "ns");
+ assertNamespace("@bob:a.b.c.phone.ns@alice", "ns");
+
+ assertNamespace("public:_a.hiddenlocation.ns@alice", "ns");
+ assertNamespace("_a.hiddenselfkey1.ns@alice", "ns");
+ assertNamespace("@bob:__a.b.hiddenphone.ns@alice", "ns");
+ }
+
+ //
+ // migrated from AtClientValidationTest
+ //
+
+ @Test
+ public void testInvalidKeyNameCauseExceptionsToBeThron() {
+
+ Exception ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).name("").build());
+ assertThat(ex.getMessage(), equalTo("key name is blank"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).name("test@").build());
+ assertThat(ex.getMessage(), equalTo("illegal characters in key name"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).name("te st").build());
+ assertThat(ex.getMessage(), equalTo("illegal characters in key name"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).name("te:st").build());
+ assertThat(ex.getMessage(), equalTo("illegal characters in key name"));
+ }
+
+ @Test
+ public void testPublicKeyInvalidMetadataThrowsException() {
+ Exception ex = assertThrows(IllegalArgumentException.class, () -> Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(-1L)
+ .ttb(0L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttl cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(-1L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttb cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(0L)
+ .ttr(-2L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttr cannot be < -1"));
+ }
+
+ @Test
+ public void testSelfKeyInvalidMetadataThrowsException() {
+ Exception ex = assertThrows(IllegalArgumentException.class, () -> Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(-1L)
+ .ttb(0L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttl cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(-1L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttb cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.selfKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(0L)
+ .ttr(-2L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttr cannot be < -1"));
+ }
+
+ @Test
+ public void testSharedKeyInvalidMetadataThrowsException() {
+ Exception ex = assertThrows(IllegalArgumentException.class, () -> Keys.sharedKeyBuilder()
+ .sharedWith(createAtSign("colin"))
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(-1L)
+ .ttb(0L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttl cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.sharedKeyBuilder()
+ .sharedWith(createAtSign("colin"))
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(-1L)
+ .ttr(-1L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttb cannot be negative"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> Keys.sharedKeyBuilder()
+ .sharedWith(createAtSign("colin"))
+ .sharedBy(createAtSign("fred"))
+ .name("key")
+ .ttl(0L)
+ .ttb(0L)
+ .ttr(-2L)
+ .build());
+ assertThat(ex.getMessage(), equalTo("ttr cannot be < -1"));
+ }
+
+ private static void assertNamespace(String fullKeyName, String expected) {
+ Keys.AtKey key = Keys.keyBuilder().rawKey(fullKeyName).build();
+ assertThat(key.namespace(), equalTo(expected));
+ }
+
+}
diff --git a/at_client/src/test/java/org/atsign/common/KeysUtilTest.java b/at_client/src/test/java/org/atsign/common/KeysUtilTest.java
index 21fe86c6..e541ff58 100644
--- a/at_client/src/test/java/org/atsign/common/KeysUtilTest.java
+++ b/at_client/src/test/java/org/atsign/common/KeysUtilTest.java
@@ -30,10 +30,11 @@ public void testSaveKeysFile() throws Exception {
assertFalse(expected.exists());
// Given a Map of keys (like Onboard creates)
- AtKeys keys = new AtKeys()
- .setEncryptKeyPair(generateRSAKeyPair())
- .setApkamKeyPair(generateRSAKeyPair())
- .setSelfEncryptKey(generateAESKeyBase64());
+ AtKeys keys = AtKeys.builder()
+ .encryptKeyPair(generateRSAKeyPair())
+ .apkamKeyPair(generateRSAKeyPair())
+ .selfEncryptKey(generateAESKeyBase64())
+ .build();
// When we call KeysUtil.saveKeys
KeysUtil.saveKeys(testAtSign, keys);
@@ -45,10 +46,11 @@ public void testSaveKeysFile() throws Exception {
@Test
public void testLoadKeysFile() throws Exception {
// Given a correctly formatted keys file in the canonical location
- AtKeys keys = new AtKeys()
- .setEncryptKeyPair(generateRSAKeyPair())
- .setApkamKeyPair(generateRSAKeyPair())
- .setSelfEncryptKey(generateAESKeyBase64());
+ AtKeys keys = AtKeys.builder()
+ .encryptKeyPair(generateRSAKeyPair())
+ .apkamKeyPair(generateRSAKeyPair())
+ .selfEncryptKey(generateAESKeyBase64())
+ .build();
KeysUtil.saveKeys(testAtSign, keys);
// When we call KeysUtil.loadKeys
@@ -60,10 +62,11 @@ public void testLoadKeysFile() throws Exception {
@Test
public void testLoadKeysFileLegacy() throws Exception {
- AtKeys keys = new AtKeys()
- .setEncryptKeyPair(generateRSAKeyPair())
- .setApkamKeyPair(generateRSAKeyPair())
- .setSelfEncryptKey(generateAESKeyBase64());
+ AtKeys keys = AtKeys.builder()
+ .encryptKeyPair(generateRSAKeyPair())
+ .apkamKeyPair(generateRSAKeyPair())
+ .selfEncryptKey(generateAESKeyBase64())
+ .build();
KeysUtil.saveKeys(testAtSign, keys);
File expected = KeysUtil.getKeysFile(testAtSign, KeysUtil.expectedKeysFilesLocation);
diff --git a/at_client/src/test/java/org/atsign/common/MetadataTest.java b/at_client/src/test/java/org/atsign/common/MetadataTest.java
new file mode 100644
index 00000000..3fe98762
--- /dev/null
+++ b/at_client/src/test/java/org/atsign/common/MetadataTest.java
@@ -0,0 +1,453 @@
+package org.atsign.common;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import org.junit.jupiter.api.Test;
+
+import java.time.OffsetDateTime;
+import java.time.ZoneOffset;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.*;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+class MetadataTest {
+
+ @Test
+ void testToStringReturnsEmptyStringWhenAllNull() {
+ Metadata md = Metadata.builder().build();
+ assertThat(md.toString(), is(""));
+ }
+
+ @Test
+ void testToStringIncludesTtlWhenSet() {
+ Metadata md = Metadata.builder().ttl(500L).build();
+ assertThat(md.toString(), containsString(":ttl:500"));
+ }
+
+ @Test
+ void testToStringIncludesTtbWhenSet() {
+ Metadata md = Metadata.builder().ttb(200L).build();
+ assertThat(md.toString(), containsString(":ttb:200"));
+ }
+
+ @Test
+ void testToStringIncludesTtrWhenSet() {
+ Metadata md = Metadata.builder().ttr(100L).build();
+ assertThat(md.toString(), containsString(":ttr:100"));
+ }
+
+ @Test
+ void testToStringIncludesCcdWhenSet() {
+ Metadata md = Metadata.builder().ccd(true).build();
+ assertThat(md.toString(), containsString(":ccd:true"));
+ }
+
+ @Test
+ void testToStringIncludesDataSignatureWhenSet() {
+ Metadata md = Metadata.builder().dataSignature("sig123").build();
+ assertThat(md.toString(), containsString(":dataSignature:sig123"));
+ }
+
+ @Test
+ void testToStringIncludesSharedKeyStatusWhenSet() {
+ Metadata md = Metadata.builder().sharedKeyStatus("cached").build();
+ assertThat(md.toString(), containsString(":sharedKeyStatus:cached"));
+ }
+
+ @Test
+ void testToStringIncludesSharedKeyEncWhenSet() {
+ Metadata md = Metadata.builder().sharedKeyEnc("encKey").build();
+ assertThat(md.toString(), containsString(":sharedKeyEnc:encKey"));
+ }
+
+ @Test
+ void testToStringIncludesPubKeyCSWhenSet() {
+ Metadata md = Metadata.builder().pubKeyCS("checksum").build();
+ assertThat(md.toString(), containsString(":pubKeyCS:checksum"));
+ }
+
+ @Test
+ void testToStringIncludesIsBinaryWhenSet() {
+ Metadata md = Metadata.builder().isBinary(false).build();
+ assertThat(md.toString(), containsString(":isBinary:false"));
+ }
+
+ @Test
+ void testToStringIncludesIsEncryptedWhenSet() {
+ Metadata md = Metadata.builder().isEncrypted(true).build();
+ assertThat(md.toString(), containsString(":isEncrypted:true"));
+ }
+
+ @Test
+ void testToStringIncludesEncodingWhenSet() {
+ Metadata md = Metadata.builder().encoding("base64").build();
+ assertThat(md.toString(), containsString(":encoding:base64"));
+ }
+
+ @Test
+ void testToStringIncludesIvNonceWhenSet() {
+ Metadata md = Metadata.builder().ivNonce("nonce42").build();
+ assertThat(md.toString(), containsString(":ivNonce:nonce42"));
+ }
+
+ @Test
+ void testToStringOmitsFieldsNotSet() {
+ Metadata md = Metadata.builder().ttl(1L).build();
+ String s = md.toString();
+ assertThat(s, not(containsString(":ttb:")));
+ assertThat(s, not(containsString(":ttr:")));
+ assertThat(s, not(containsString(":encoding:")));
+ }
+
+ @Test
+ void testFromJsonParsesBasicFields() throws JsonProcessingException {
+ String json = "{\"ttl\":300,\"isPublic\":true,\"encoding\":\"base64\"}";
+ Metadata md = Metadata.fromJson(json);
+
+ assertThat(md.ttl(), is(300L));
+ assertThat(md.isPublic(), is(true));
+ assertThat(md.encoding(), is("base64"));
+ }
+
+ @Test
+ void testFromJsonEmptyObjectProducesAllNullFields() throws JsonProcessingException {
+ Metadata md = Metadata.fromJson("{}");
+ assertThat(md.ttl(), is(nullValue()));
+ assertThat(md.isPublic(), is(nullValue()));
+ assertThat(md.encoding(), is(nullValue()));
+ }
+
+ @Test
+ void testFromJsonInvalidJsonThrowsException() {
+ assertThrows(JsonProcessingException.class, () -> Metadata.fromJson("not-json"));
+ }
+
+ @Test
+ void testMergeMd1FieldsTakePriorityOverMd2() {
+ Metadata md1 = Metadata.builder()
+ .ttl(1L).ttb(2L).ttr(3L).ccd(true)
+ .isPublic(true).isHidden(true).isCached(true)
+ .isEncrypted(true).isBinary(true).namespaceAware(true)
+ .dataSignature("ds1").sharedKeyStatus("sks1").sharedKeyEnc("ske1")
+ .pubKeyCS("pkcs1").encoding("utf8").ivNonce("iv1")
+ .build();
+
+ Metadata md2 = Metadata.builder()
+ .ttl(99L).ttb(99L).ttr(99L).ccd(false)
+ .isPublic(false).isHidden(false).isCached(false)
+ .isEncrypted(false).isBinary(false).namespaceAware(false)
+ .dataSignature("ds2").sharedKeyStatus("sks2").sharedKeyEnc("ske2")
+ .pubKeyCS("pkcs2").encoding("ascii").ivNonce("iv2")
+ .build();
+
+ Metadata merged = Metadata.merge(md1, md2);
+
+ assertThat(merged.ttl(), is(1L));
+ assertThat(merged.ttb(), is(2L));
+ assertThat(merged.ttr(), is(3L));
+ assertThat(merged.ccd(), is(true));
+ assertThat(merged.isPublic(), is(true));
+ assertThat(merged.isHidden(), is(true));
+ assertThat(merged.isCached(), is(true));
+ assertThat(merged.isEncrypted(), is(true));
+ assertThat(merged.isBinary(), is(true));
+ assertThat(merged.namespaceAware(), is(true));
+ assertThat(merged.dataSignature(), is("ds1"));
+ assertThat(merged.sharedKeyStatus(), is("sks1"));
+ assertThat(merged.sharedKeyEnc(), is("ske1"));
+ assertThat(merged.pubKeyCS(), is("pkcs1"));
+ assertThat(merged.encoding(), is("utf8"));
+ assertThat(merged.ivNonce(), is("iv1"));
+ }
+
+ @Test
+ void testMergeMd2FieldsUsedWhenMd1FieldsAreNull() {
+ Metadata md1 = Metadata.builder().build();
+
+ OffsetDateTime now = OffsetDateTime.now(ZoneOffset.UTC);
+ Metadata md2 = Metadata.builder()
+ .ttl(1L).ttb(2L).ttr(3L).ccd(true)
+ .isPublic(true).isHidden(true).isCached(true)
+ .isEncrypted(true).isBinary(true).namespaceAware(true)
+ .dataSignature("ds2").sharedKeyStatus("sks2").sharedKeyEnc("ske2")
+ .pubKeyCS("pkcs2").encoding("ascii").ivNonce("iv2")
+ .availableAt(now).expiresAt(now).refreshAt(now)
+ .createdAt(now).updatedAt(now)
+ .build();
+
+ Metadata merged = Metadata.merge(md1, md2);
+
+ assertThat(merged.ttl(), is(1L));
+ assertThat(merged.ttb(), is(2L));
+ assertThat(merged.ttr(), is(3L));
+ assertThat(merged.ccd(), is(true));
+ assertThat(merged.isPublic(), is(true));
+ assertThat(merged.isHidden(), is(true));
+ assertThat(merged.isCached(), is(true));
+ assertThat(merged.isEncrypted(), is(true));
+ assertThat(merged.isBinary(), is(true));
+ assertThat(merged.namespaceAware(), is(true));
+ assertThat(merged.dataSignature(), is("ds2"));
+ assertThat(merged.sharedKeyStatus(), is("sks2"));
+ assertThat(merged.sharedKeyEnc(), is("ske2"));
+ assertThat(merged.pubKeyCS(), is("pkcs2"));
+ assertThat(merged.encoding(), is("ascii"));
+ assertThat(merged.ivNonce(), is("iv2"));
+ assertThat(merged.availableAt(), is(now));
+ assertThat(merged.expiresAt(), is(now));
+ assertThat(merged.refreshAt(), is(now));
+ assertThat(merged.createdAt(), is(now));
+ assertThat(merged.updatedAt(), is(now));
+ }
+
+ @Test
+ void testMergeFieldRemainsNullWhenBothMd1AndMd2AreNull() {
+ Metadata merged = Metadata.merge(Metadata.builder().build(), Metadata.builder().build());
+
+ assertThat(merged.ttl(), is(nullValue()));
+ assertThat(merged.ttb(), is(nullValue()));
+ assertThat(merged.ttr(), is(nullValue()));
+ assertThat(merged.ccd(), is(nullValue()));
+ assertThat(merged.isPublic(), is(nullValue()));
+ assertThat(merged.isHidden(), is(nullValue()));
+ assertThat(merged.isCached(), is(nullValue()));
+ assertThat(merged.isEncrypted(), is(nullValue()));
+ assertThat(merged.isBinary(), is(nullValue()));
+ assertThat(merged.namespaceAware(), is(nullValue()));
+ assertThat(merged.dataSignature(), is(nullValue()));
+ assertThat(merged.sharedKeyStatus(), is(nullValue()));
+ assertThat(merged.sharedKeyEnc(), is(nullValue()));
+ assertThat(merged.pubKeyCS(), is(nullValue()));
+ assertThat(merged.encoding(), is(nullValue()));
+ assertThat(merged.ivNonce(), is(nullValue()));
+ assertThat(merged.availableAt(), is(nullValue()));
+ assertThat(merged.expiresAt(), is(nullValue()));
+ assertThat(merged.refreshAt(), is(nullValue()));
+ assertThat(merged.createdAt(), is(nullValue()));
+ assertThat(merged.updatedAt(), is(nullValue()));
+ }
+
+ @Test
+ void testSetTtlIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setTtlIfNotNull(b, 42L), is(true));
+ assertThat(b.build().ttl(), is(42L));
+ }
+
+ @Test
+ void testSetTtlIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().ttl(42L);
+ assertThat(Metadata.setTtlIfNotNull(b, null), is(false));
+ assertThat(b.build().ttl(), is(42L));
+ }
+
+ @Test
+ void testSetTtbIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setTtbIfNotNull(b, 10L), is(true));
+ assertThat(b.build().ttb(), is(10L));
+ }
+
+ @Test
+ void testSetTtbIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().ttb(10L);
+ assertThat(Metadata.setTtbIfNotNull(b, null), is(false));
+ assertThat(b.build().ttb(), is(10L));
+ }
+
+ @Test
+ void testSetTtrIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setTtrIfNotNull(b, 5L), is(true));
+ assertThat(b.build().ttr(), is(5L));
+ }
+
+ @Test
+ void testSetTtrIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().ttr(5L);
+ assertThat(Metadata.setTtrIfNotNull(b, null), is(false));
+ assertThat(b.build().ttr(), is(5L));
+ }
+
+ @Test
+ void testSetCcdIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setCcdIfNotNull(b, false), is(true));
+ assertThat(b.build().ccd(), is(false));
+ }
+
+ @Test
+ void testSetCcdIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().ccd(true);
+ assertThat(Metadata.setCcdIfNotNull(b, null), is(false));
+ assertThat(b.build().ccd(), is(true));
+ }
+
+ @Test
+ void testSetIsPublicIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIsPublicIfNotNull(b, true), is(true));
+ assertThat(b.build().isPublic(), is(true));
+ }
+
+ @Test
+ void testSetIsPublicIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().isPublic(true);
+ assertThat(Metadata.setIsPublicIfNotNull(b, null), is(false));
+ assertThat(b.build().isPublic(), is(true));
+ }
+
+ @Test
+ void testSetIsHiddenIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIsHiddenIfNotNull(b, true), is(true));
+ assertThat(b.build().isHidden(), is(true));
+ }
+
+ @Test
+ void testSetIsHiddenIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().isHidden(true);
+ assertThat(Metadata.setIsHiddenIfNotNull(b, null), is(false));
+ assertThat(b.build().isHidden(), is(true));
+ }
+
+ @Test
+ void testSetIsCachedIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIsCachedIfNotNull(b, false), is(true));
+ assertThat(b.build().isCached(), is(false));
+ }
+
+ @Test
+ void testSetIsCachedIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().isCached(true);
+ assertThat(Metadata.setIsCachedIfNotNull(b, null), is(false));
+ assertThat(b.build().isCached(), is(true));
+ }
+
+ @Test
+ void testSetIsBinaryIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIsBinaryIfNotNull(b, true), is(true));
+ assertThat(b.build().isBinary(), is(true));
+ }
+
+ @Test
+ void testSetIsBinaryIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().isBinary(true);
+ assertThat(Metadata.setIsBinaryIfNotNull(b, null), is(false));
+ assertThat(b.build().isBinary(), is(true));
+ }
+
+ @Test
+ void testSetIsEncryptedIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIsEncryptedIfNotNull(b, false), is(true));
+ assertThat(b.build().isEncrypted(), is(false));
+ }
+
+ @Test
+ void testSetIsEncryptedIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().isEncrypted(true);
+ assertThat(Metadata.setIsEncryptedIfNotNull(b, null), is(false));
+ assertThat(b.build().isEncrypted(), is(true));
+ }
+
+ @Test
+ void testSetNamespaceAwareIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setNamespaceAwareIfNotNull(b, true), is(true));
+ assertThat(b.build().namespaceAware(), is(true));
+ }
+
+ @Test
+ void testSetNamespaceAwareIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().namespaceAware(true);
+ assertThat(Metadata.setNamespaceAwareIfNotNull(b, null), is(false));
+ assertThat(b.build().namespaceAware(), is(true));
+ }
+
+ @Test
+ void testSetDataSignatureIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setDataSignatureIfNotNull(b, "sig"), is(true));
+ assertThat(b.build().dataSignature(), is("sig"));
+ }
+
+ @Test
+ void testSetDataSignatureIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().dataSignature("sig");
+ assertThat(Metadata.setDataSignatureIfNotNull(b, null), is(false));
+ assertThat(b.build().dataSignature(), is("sig"));
+ }
+
+ @Test
+ void testSetSharedKeyStatusIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setSharedKeyStatusIfNotNull(b, "ok"), is(true));
+ assertThat(b.build().sharedKeyStatus(), is("ok"));
+ }
+
+ @Test
+ void testSetSharedKeyStatusIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().sharedKeyStatus("ok");
+ assertThat(Metadata.setSharedKeyStatusIfNotNull(b, null), is(false));
+ assertThat(b.build().sharedKeyStatus(), is("ok"));
+ }
+
+ @Test
+ void testSetSharedKeyEncIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setSharedKeyEncIfNotNull(b, "encKey"), is(true));
+ assertThat(b.build().sharedKeyEnc(), is("encKey"));
+ }
+
+ @Test
+ void testSetSharedKeyEncIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().sharedKeyEnc("encKey");
+ assertThat(Metadata.setSharedKeyEncIfNotNull(b, null), is(false));
+ assertThat(b.build().sharedKeyEnc(), is("encKey"));
+ }
+
+ @Test
+ void testSetPubKeyCSIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setPubKeyCSIfNotNull(b, "checksum"), is(true));
+ assertThat(b.build().pubKeyCS(), is("checksum"));
+ }
+
+ @Test
+ void testSetPubKeyCSIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().pubKeyCS("checksum");
+ assertThat(Metadata.setPubKeyCSIfNotNull(b, null), is(false));
+ assertThat(b.build().pubKeyCS(), is("checksum"));
+ }
+
+ @Test
+ void testSetEncodingIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setEncodingIfNotNull(b, "utf8"), is(true));
+ assertThat(b.build().encoding(), is("utf8"));
+ }
+
+ @Test
+ void testSetEncodingIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().encoding("utf8");
+ assertThat(Metadata.setEncodingIfNotNull(b, null), is(false));
+ assertThat(b.build().encoding(), is("utf8"));
+ }
+
+ @Test
+ void testSetIvNonceIfNotNullReturnsTrueAndSetsValueWhenNotNull() {
+ Metadata.MetadataBuilder b = Metadata.builder();
+ assertThat(Metadata.setIvNonceIfNotNull(b, "iv99"), is(true));
+ assertThat(b.build().ivNonce(), is("iv99"));
+ }
+
+ @Test
+ void testSetIvNonceIfNotNullReturnsFalseAndDoesNotOverwriteExistingValueWhenNull() {
+ Metadata.MetadataBuilder b = Metadata.builder().ivNonce("iv99");
+ assertThat(Metadata.setIvNonceIfNotNull(b, null), is(false));
+ assertThat(b.build().ivNonce(), is("iv99"));
+ }
+}
diff --git a/at_client/src/test/java/org/atsign/common/ResponseTransformerTest.java b/at_client/src/test/java/org/atsign/common/ResponseTransformerTest.java
index caefc7c3..a69cf88c 100644
--- a/at_client/src/test/java/org/atsign/common/ResponseTransformerTest.java
+++ b/at_client/src/test/java/org/atsign/common/ResponseTransformerTest.java
@@ -12,7 +12,7 @@
import static org.junit.jupiter.api.Assertions.*;
public class ResponseTransformerTest {
- final ObjectMapper mapper = new ObjectMapper();
+ final ObjectMapper mapper = Json.MAPPER;
final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS'Z'");
@Test
@@ -59,25 +59,25 @@ public void llookupAllResponseTransformerTest() throws JsonProcessingException {
assertEquals(
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCz9nTBDDLxLgSxYu4+mDF3anWuTlKysXBBLsp3glrBP9xEXDx4muOHuHZIzuNvFlsjcCDF/mLSAJcvbxUoTsOQp+QD5XMhlNS9TWGsmNks7KHylNEhcqo2Va7RZxNS6MZBRacl+OusnebVKdOXDnbuevoED5fSklOz7mvdm9Mb2wIDAQAB",
model.data);
- assertNull(model.metaData.createdBy);
- assertNull(model.metaData.updatedBy);
+ assertNull(model.metaData.createdBy());
+ assertNull(model.metaData.updatedBy());
- assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.createdAt));
- assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.updatedAt));
- assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.availableAt));
- assertNull(model.metaData.expiresAt);
- assertNull(model.metaData.refreshAt);
- assertEquals("active", model.metaData.status);
- assertEquals(0, (int) model.metaData.version);
- assertEquals(0, (int) model.metaData.ttl);
- assertEquals(0, (int) model.metaData.ttb);
- assertNull(model.metaData.ttr);
- assertNull(model.metaData.ccd);
- assertFalse(model.metaData.isBinary);
- assertFalse(model.metaData.isEncrypted);
- assertNull(model.metaData.dataSignature);
- assertNull(model.metaData.sharedKeyEnc);
- assertNull(model.metaData.pubKeyCS);
- assertNull(model.metaData.encoding);
+ assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.createdAt()));
+ assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.updatedAt()));
+ assertEquals("2022-08-12 01:50:15.398Z", dateTimeFormatter.format(model.metaData.availableAt()));
+ assertNull(model.metaData.expiresAt());
+ assertNull(model.metaData.refreshAt());
+ assertEquals("active", model.metaData.status());
+ assertEquals(0, (int) model.metaData.version());
+ assertEquals(0, model.metaData.ttl());
+ assertEquals(0, model.metaData.ttb());
+ assertNull(model.metaData.ttr());
+ assertNull(model.metaData.ccd());
+ assertFalse(model.metaData.isBinary());
+ assertFalse(model.metaData.isEncrypted());
+ assertNull(model.metaData.dataSignature());
+ assertNull(model.metaData.sharedKeyEnc());
+ assertNull(model.metaData.pubKeyCS());
+ assertNull(model.metaData.encoding());
}
}
diff --git a/at_client/src/test/java/org/atsign/common/VerbBuildersTest.java b/at_client/src/test/java/org/atsign/common/VerbBuildersTest.java
index a690603f..1a683003 100644
--- a/at_client/src/test/java/org/atsign/common/VerbBuildersTest.java
+++ b/at_client/src/test/java/org/atsign/common/VerbBuildersTest.java
@@ -1,291 +1,550 @@
package org.atsign.common;
+import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.atsign.client.util.EnrollmentId.createEnrollmentId;
+import static org.atsign.common.AtSign.createAtSign;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.*;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.atsign.client.api.AtKeyNames;
import org.atsign.common.Keys.PublicKey;
import org.atsign.common.Keys.SelfKey;
import org.atsign.common.Keys.SharedKey;
-import org.atsign.common.VerbBuilders.PlookupVerbBuilder.Type;
-import org.atsign.common.VerbBuilders.*;
+import org.atsign.common.VerbBuilders.EnrollOperation;
+import org.atsign.common.VerbBuilders.LookupOperation;
+import org.atsign.common.VerbBuilders.NotifyOperation;
+import org.atsign.common.VerbBuilders.UpdateCommandBuilder;
import org.junit.jupiter.api.Test;
public class VerbBuildersTest {
@Test
- public void fromVerbBuilderTest() {
- FromVerbBuilder builder;
- String command;
+ public void testFromBuilderGeneratesExpectedOutput() {
- builder = new FromVerbBuilder();
- builder.setAtSign("@bob");
- command = builder.build(); // "from:@bob"
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.fromCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("atSign not set"));
+
+ String command = VerbBuilders.fromCommandBuilder()
+ .atSign(createAtSign("@bob"))
+ .build();
assertEquals("from:@bob", command);
}
@Test
- public void cramVerbBuilderTest() {
- CRAMVerbBuilder builder;
- String command;
+ public void testCramBuilderGeneratesExpectedOutput() {
+
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.cramCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("digest not set"));
- builder = new CRAMVerbBuilder();
- builder.setDigest("digest");
- command = builder.build(); // "cram:digest"
+ String command = VerbBuilders.cramCommandBuilder()
+ .digest("digest")
+ .build();
assertEquals("cram:digest", command);
}
@Test
- public void polVerbBuilderTest() {
- POLVerbBuilder builder;
- String command;
-
- builder = new POLVerbBuilder();
- command = builder.build(); // "pol"
+ public void testPolBuilderGeneratesExpectedOutput() {
+ String command = VerbBuilders.polCommandBuilder().build();
assertEquals("pol", command);
}
@Test
- public void pkamVerbBuilderTest() {
- PKAMVerbBuilder builder;
- String command;
+ public void testPkamBuilderGeneratesExpectedOutput() {
- builder = new PKAMVerbBuilder();
- builder.setDigest("digest");
- command = builder.build(); // "pkam:digest"
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.pkamCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("digest not set"));
+
+ String command = VerbBuilders.pkamCommandBuilder()
+ .digest("digest")
+ .build();
assertEquals("pkam:digest", command);
}
@Test
- public void updateVerbBuilderTest() {
- UpdateVerbBuilder builder;
+ public void testPkamBuilderGeneratesExpectedOutputWhenEnrollmentIdIsSet() {
+
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.pkamCommandBuilder()
+ .digest("digest")
+ .enrollmentId(createEnrollmentId("12345-6789"))
+ .signingAlgo("RSA")
+ .build());
+ assertThat(ex.getMessage(), containsString("hashingAlgo not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.pkamCommandBuilder()
+ .digest("digest")
+ .enrollmentId(createEnrollmentId("12345-6789"))
+ .hashingAlgo("SHA")
+ .build());
+ assertThat(ex.getMessage(), containsString("signingAlgo not set"));
+
+ String command = VerbBuilders.pkamCommandBuilder()
+ .digest("digest")
+ .enrollmentId(createEnrollmentId("12345-6789"))
+ .signingAlgo("RSA")
+ .hashingAlgo("SHA")
+ .build();
+ assertEquals("pkam:signingAlgo:RSA:hashingAlgo:SHA:enrollmentId:12345-6789:digest", command);
+ }
+
+ @Test
+ public void testUpdateBuilderThrowsExceptionsWhenMandatoryFieldsAreNotSet() {
+
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.updateCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.updateCommandBuilder().keyName("test").build());
+ assertThat(ex.getMessage(), containsString("sharedBy not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.updateCommandBuilder().keyName("test").sharedBy(createAtSign("fred")).build());
+ assertThat(ex.getMessage(), containsString("value not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.updateCommandBuilder().isPublic(true).rawKey("@colin:key1@fred").build());
+ assertThat(ex.getMessage(), containsString("both rawKeys and isHidden, isPublic isCached set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.updateCommandBuilder().keyName("test").rawKey("@colin:key1@fred").build());
+ assertThat(ex.getMessage(), containsString("both rawKeys and key fields set"));
+ }
+
+ @Test
+ public void testUpdateBuilderMetadataSettersOverrideKeyMetadata() {
+ PublicKey key = Keys.publicKeyBuilder().sharedBy(createAtSign("fred")).name("test").build();
+ UpdateCommandBuilder builder = VerbBuilders.updateCommandBuilder().key(key).value("x");
+
+ builder = VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).value("x");
+ assertThat(builder.isPublic(true).build(),
+ equalTo("update:public:test@fred x"));
+ assertThat(builder.isPublic(false).build(),
+ equalTo("update:test@fred x"));
+
+ builder = VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).value("x");
+ assertThat(builder.isHidden(true).build(),
+ equalTo("update:_test@fred x"));
+ assertThat(builder.isHidden(false).build(),
+ equalTo("update:test@fred x"));
+
+ builder = VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).value("x");
+ assertThat(builder.isCached(true).build(),
+ equalTo("update:cached:test@fred x"));
+ assertThat(builder.isCached(false).build(),
+ equalTo("update:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.ttl(SECONDS.toMillis(1)).build(),
+ equalTo("update:ttl:1000:public:test@fred x"));
+ assertThat(builder.ttl(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.ttb(SECONDS.toMillis(2)).build(),
+ equalTo("update:ttb:2000:public:test@fred x"));
+ assertThat(builder.ttb(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.ttr(SECONDS.toMillis(3)).build(),
+ equalTo("update:ttr:3000:public:test@fred x"));
+ assertThat(builder.ttr(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.ccd(true).build(),
+ equalTo("update:ccd:true:public:test@fred x"));
+ assertThat(builder.ccd(false).build(),
+ equalTo("update:ccd:false:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.isBinary(true).build(),
+ equalTo("update:isBinary:true:public:test@fred x"));
+ assertThat(builder.isBinary(false).build(),
+ equalTo("update:isBinary:false:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.isEncrypted(true).build(),
+ equalTo("update:isEncrypted:true:public:test@fred x"));
+ assertThat(builder.isEncrypted(false).build(),
+ equalTo("update:isEncrypted:false:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.dataSignature("XYZ").build(),
+ equalTo("update:dataSignature:XYZ:public:test@fred x"));
+ assertThat(builder.dataSignature(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.sharedKeyEnc("abcdef").build(),
+ equalTo("update:sharedKeyEnc:abcdef:public:test@fred x"));
+ assertThat(builder.sharedKeyEnc(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.pubKeyCS("xxxx").build(),
+ equalTo("update:pubKeyCS:xxxx:public:test@fred x"));
+ assertThat(builder.pubKeyCS(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.encoding("en").build(),
+ equalTo("update:encoding:en:public:test@fred x"));
+ assertThat(builder.encoding(null).build(),
+ equalTo("update:public:test@fred x"));
+
+ builder =
+ VerbBuilders.updateCommandBuilder().keyName(key.name()).sharedBy(key.sharedBy()).isPublic(true).value("x");
+ assertThat(builder.ivNonce("abc123op").build(),
+ equalTo("update:ivNonce:abc123op:public:test@fred x"));
+ assertThat(builder.ivNonce(null).build(),
+ equalTo("update:public:test@fred x"));
+ }
+
+ @Test
+ public void testUpdateBuilderThrowsExceptionIfMutuallyExclusiveFieldsHaveBeenSet() {
+ PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(createAtSign("fred"))
+ .name("test")
+ .build();
+
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> {
+ VerbBuilders.updateCommandBuilder()
+ .key(key)
+ .sharedBy(key.sharedBy())
+ .ccd(true)
+ .value("x")
+ .build();
+ });
+ assertThat(ex.getMessage(), containsString("both key and key fields set"));
+
+ }
+
+ @Test
+ public void testUpdateBuilderGeneratesExpectedOutput() {
String command;
// self key
- builder = new UpdateVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@bob");
- builder.setValue("my Value 123");
- command = builder.build(); // "update:test@bob my Value 123"
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@bob"))
+ .value("my Value 123")
+ .build();
assertEquals("update:test@bob my Value 123", command);
// self key but shared with self
- builder = new UpdateVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@bob");
- builder.setSharedWith("@bob");
- builder.setValue("My value 123");
- command = builder.build(); // "update:@alice:test@bob My value 123"
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("bob"))
+ .sharedWith(createAtSign("bob"))
+ .value("My value 123")
+ .build();
assertEquals("update:@bob:test@bob My value 123", command);
// public key
- builder = new UpdateVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@bob");
- builder.setIsPublic(true);
- builder.setValue("my Value 123");
- command = builder.build(); // "update:public:publickey@bob my Value 123"
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("bob"))
+ .isPublic(true)
+ .value("my Value 123")
+ .build();
assertEquals("update:public:publickey@bob my Value 123", command);
// cached public key
- builder = new UpdateVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- builder.setIsPublic(true);
- builder.setIsCached(true);
- builder.setValue("my Value 123");
- command = builder.build(); // "update:cached:public:publickey@alice my Value 123"
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("alice"))
+ .isPublic(true)
+ .isCached(true)
+ .value("my Value 123")
+ .build();
assertEquals("update:cached:public:publickey@alice my Value 123", command);
// shared key
- builder = new UpdateVerbBuilder();
- builder.setKeyName("sharedkey");
- builder.setSharedBy("@bob");
- builder.setSharedWith("@alice");
- builder.setValue("my Value 123");
- command = builder.build(); // "update:@alice:sharedkey@bob my Value 123"
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName("sharedkey")
+ .sharedBy(createAtSign("@bob"))
+ .sharedWith(createAtSign("@alice"))
+ .value("my Value 123")
+ .build();
assertEquals("update:@alice:sharedkey@bob my Value 123", command);
// with shared key
- builder = new UpdateVerbBuilder();
- SharedKey sk1 = new KeyBuilders.SharedKeyBuilder(new AtSign("@bob"), new AtSign("@alice")).key("test").build();
- sk1.metadata.isBinary = true;
- sk1.metadata.ttl = 1000 * 60 * 10; // 10 minutes
- builder.with(sk1, "myBinaryValue123456");
- command = builder.build(); // update:ttl:600000:isBinary:true:isEncrypted:true:@alice:test@bob myBinaryValue123456
+ SharedKey sk1 = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .sharedWith(new AtSign("@alice"))
+ .name("test")
+ .ttl(TimeUnit.MINUTES.toMillis(10))
+ .isBinary(true)
+ .build();
+ command = VerbBuilders.updateCommandBuilder()
+ .key(sk1)
+ .value("myBinaryValue123456")
+ .build();
assertEquals("update:ttl:600000:isBinary:true:isEncrypted:true:@alice:test@bob myBinaryValue123456", command);
// with public key
- builder = new UpdateVerbBuilder();
- PublicKey pk1 = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key("test").build();
- pk1.metadata.isCached = true;
- builder.with(pk1, "myValue123");
- command = builder.build(); // update:cached:public:test@bob myValue123
- assertEquals("update:isBinary:false:isEncrypted:false:cached:public:test@bob myValue123", command);
+ PublicKey pk1 = Keys.publicKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .name("test")
+ .isCached(true)
+ .build();
+ command = VerbBuilders.updateCommandBuilder()
+ .key(pk1)
+ .value("myValue123")
+ .build();
+ assertEquals("update:isEncrypted:false:cached:public:test@bob myValue123", command);
// with self key
- builder = new UpdateVerbBuilder();
- SelfKey sk2 = new KeyBuilders.SelfKeyBuilder(new AtSign("@bob")).key("test").build();
- sk2.metadata.ttl = 1000 * 60 * 10; // 10 minutes
- builder.with(sk2, "myValue123");
- command = builder.build(); // update:ttl:600000:test@bob myValue123
- assertEquals("update:ttl:600000:isBinary:false:isEncrypted:true:test@bob myValue123", command);
+ SelfKey sk2 = Keys.selfKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .name("test")
+ .ttl(TimeUnit.MINUTES.toMillis(10))
+ .build();
+ command = VerbBuilders.updateCommandBuilder()
+ .key(sk2)
+ .value("myValue123")
+ .build();
+ assertEquals("update:ttl:600000:isEncrypted:true:test@bob myValue123", command);
// with self key (shared with self)
- builder = new UpdateVerbBuilder();
- AtSign bob = new AtSign("@bob");
- SelfKey sk3 = new KeyBuilders.SelfKeyBuilder(bob, bob).key("test").build();
- sk3.metadata.ttl = 1000 * 60 * 10; // 10 minutes
- builder.with(sk3, "myValue123");
- command = builder.build(); // update:ttl:600000:@bob:test@bob myValue123
- assertEquals("update:ttl:600000:isBinary:false:isEncrypted:true:@bob:test@bob myValue123", command);
+ AtSign bob = createAtSign("@bob");
+ SelfKey sk3 = Keys.selfKeyBuilder()
+ .sharedBy(bob)
+ .sharedWith(bob)
+ .name("test")
+ .ttl(TimeUnit.MINUTES.toMillis(10))
+ .build();
+ command = VerbBuilders.updateCommandBuilder()
+ .key(sk3)
+ .value("myValue123")
+ .build();
+ assertEquals("update:ttl:600000:isEncrypted:true:@bob:test@bob myValue123", command);
// private hidden key
// TODO with private hidden key when implemented
}
@Test
- public void testUpdateVerbBuilderForPublicKeyWithNamespace() {
- PublicKey key = new KeyBuilders.PublicKeyBuilder(new AtSign("@alice"))
- .key("test")
+ public void testUpdateBuilderGeneratesExpectedOutputForPublicKeyWithNamespace() {
+ PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- UpdateVerbBuilder builder = new UpdateVerbBuilder();
- builder.with(key, "testvalue");
+ String command = VerbBuilders.updateCommandBuilder()
+ .key(key)
+ .value("testvalue")
+ .build();
- assertThat(builder.build(), equalTo("update:isBinary:false:isEncrypted:false:public:test.testns@alice testvalue"));
+ assertThat(command, equalTo("update:isEncrypted:false:public:test.testns@alice testvalue"));
}
@Test
- public void testUpdateVerbBuilderForSelfKeyWithNamespace() {
- SelfKey key = new KeyBuilders.SelfKeyBuilder(new AtSign("@alice"))
- .key("test")
+ public void testUpdateBuilderGeneratesExpectedOutputForSelfKeyWithNamespace() {
+ SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- UpdateVerbBuilder builder = new UpdateVerbBuilder();
- builder.with(key, "testvalue");
+ String command = VerbBuilders.updateCommandBuilder()
+ .key(key)
+ .value("testvalue")
+ .build();
- assertThat(builder.build(), equalTo("update:isBinary:false:isEncrypted:true:test.testns@alice testvalue"));
+ assertThat(command, equalTo("update:isEncrypted:true:test.testns@alice testvalue"));
}
@Test
- public void testUpdateVerbBuilderForSharedKeyWithNamespace() {
- SharedKey key = new KeyBuilders.SharedKeyBuilder(new AtSign("@alice"), new AtSign("@bob"))
- .key("test")
+ public void testUpdateBuilderGeneratesExpectedOutputForSharedKeyWithNamespace() {
+ SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .sharedWith(new AtSign("@bob"))
+ .name("test")
.namespace("testns")
.build();
- UpdateVerbBuilder builder = new UpdateVerbBuilder();
- builder.with(key, "testvalue");
+ String command = VerbBuilders.updateCommandBuilder()
+ .key(key)
+ .value("testvalue")
+ .build();
- assertThat(builder.build(), equalTo("update:isBinary:false:isEncrypted:true:@bob:test.testns@alice testvalue"));
+ assertThat(command, equalTo("update:isEncrypted:true:@bob:test.testns@alice testvalue"));
}
@Test
- public void llookupVerbBuilderTest() {
- LlookupVerbBuilder builder;
+ public void testUpdateBuilderGeneratesExpectedOutputForSharedEncryption() {
+ AtSign sharedBy = createAtSign("sharedBy");
+ AtSign sharedWith = createAtSign("sharedWith");
+
+ String command = VerbBuilders.updateCommandBuilder()
+ .keyName(AtKeyNames.toSharedByMeKeyName(sharedWith))
+ .sharedBy(sharedBy)
+ .value("XXXX")
+ .build();
+
+ assertThat(command, equalTo("update:shared_key.sharedWith@sharedBy XXXX"));
+
+ command = VerbBuilders.updateCommandBuilder()
+ .keyName(AtKeyNames.SHARED_KEY)
+ .sharedBy(sharedBy)
+ .sharedWith(sharedWith)
+ .ttr(TimeUnit.HOURS.toMillis(24))
+ .value("XXXX")
+ .build();
+
+ assertThat(command, equalTo("update:ttr:86400000:@sharedWith:shared_key@sharedBy XXXX"));
+ }
+
+ @Test
+ public void testUpdateBuilderGeneratesExpectedOutputForPublicEncyrptionKey() {
+ String command = VerbBuilders.updateCommandBuilder()
+ .sharedBy(createAtSign("fred"))
+ .keyName(AtKeyNames.PUBLIC_ENCRYPT)
+ .isPublic(true)
+ .value("XXXX")
+ .build();
+ assertThat(command, equalTo("update:public:publickey@fred XXXX"));
+ }
+
+ @Test
+ public void testLlookupBuilderGeneratesExpectedOutput() {
String command;
// Type.NONE self key
- builder = new LlookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- command = builder.build(); // "llookup:test@alice"
+ command = VerbBuilders.llookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .build();
assertEquals("llookup:test@alice", command);
// Type.METADATA self key
- builder = new LlookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setType(LlookupVerbBuilder.Type.METADATA);
- command = builder.build(); // "llookup:meta:test@alice"
+ command = VerbBuilders.llookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.meta)
+ .build();
assertEquals("llookup:meta:test@alice", command);
// hidden self key, meta
- builder = new LlookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setType(LlookupVerbBuilder.Type.METADATA);
- builder.setIsHidden(true);
- command = builder.build(); // "llookup:meta:_test@alice"
+ command = VerbBuilders.llookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.meta)
+ .isHidden(true)
+ .build();
assertEquals("llookup:meta:_test@alice", command);
// Type.ALL public cached key
- builder = new LlookupVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- builder.setIsCached(true);
- builder.setIsPublic(true);
- builder.setType(LlookupVerbBuilder.Type.ALL);
- command = builder.build(); // "llookup:cached:public:publickey@alice:all"
+ command = VerbBuilders.llookupCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .isCached(true)
+ .isPublic(true)
+ .operation(LookupOperation.all)
+ .build();
assertEquals("llookup:all:cached:public:publickey@alice", command);
// no key name
- assertThrows(IllegalArgumentException.class, () -> {
- LlookupVerbBuilder b = new LlookupVerbBuilder();
- b = new LlookupVerbBuilder();
- b.setSharedBy("@alice");
- b.build();
- });
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.llookupCommandBuilder()
+ .sharedBy(createAtSign("@alice")).build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
// no shared by
- assertThrows(IllegalArgumentException.class, () -> {
- LlookupVerbBuilder b = new LlookupVerbBuilder();
- b = new LlookupVerbBuilder();
- b.setKeyName("test");
- b.build();
- });
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.llookupCommandBuilder().keyName("test").build());
+ assertThat(ex.getMessage(), containsString("sharedBy not set"));
- // no key name and no shared by
- assertThrows(IllegalArgumentException.class, () -> {
- LlookupVerbBuilder b = new LlookupVerbBuilder();
- b.build();
- });
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.llookupCommandBuilder().keyName("test").rawKey("public:publickey@alice")
+ .build());
+ assertThat(ex.getMessage(), containsString("both rawKey and key fields are set"));
// with public key
- builder = new LlookupVerbBuilder();
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key("publickey").build();
- builder.with(pk, LlookupVerbBuilder.Type.METADATA);
- command = builder.build(); // "llookup:meta:public:publickey@bob"
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(new AtSign("@bob")).name("publickey").build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(pk)
+ .operation(LookupOperation.meta)
+ .build();
+ assertEquals("llookup:meta:public:publickey@bob", command);
+ command = VerbBuilders.llookupCommandBuilder()
+ .rawKey("public:publickey@bob")
+ .operation(LookupOperation.meta)
+ .build();
assertEquals("llookup:meta:public:publickey@bob", command);
// with shared key
- builder = new LlookupVerbBuilder();
- SharedKey sk = new KeyBuilders.SharedKeyBuilder(new AtSign("@bob"), new AtSign("@alice")).key("sharedkey").build();
- builder.with(sk, LlookupVerbBuilder.Type.NONE);
- command = builder.build(); // "llookup:@alice:sharedkey@bob"
+ SharedKey sk = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .sharedWith(new AtSign("@alice"))
+ .name("sharedkey")
+ .build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(sk)
+ .operation(LookupOperation.none)
+ .build();
assertEquals("llookup:@alice:sharedkey@bob", command);
// with self key
- builder = new LlookupVerbBuilder();
- SelfKey selfKey1 = new KeyBuilders.SelfKeyBuilder(new AtSign("@bob")).key("test").build();
- builder.with(selfKey1, LlookupVerbBuilder.Type.ALL);
- command = builder.build(); // "llookup:all:test@bob"
+ SelfKey selfKey1 = Keys.selfKeyBuilder().sharedBy(new AtSign("@bob")).name("test").build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(selfKey1)
+ .operation(LookupOperation.all)
+ .build(); // "llookup:all:test@bob"
assertEquals("llookup:all:test@bob", command);
// with self key (shared with self)
- builder = new LlookupVerbBuilder();
AtSign as = new AtSign("@bob");
- SelfKey selfKey2 = new KeyBuilders.SelfKeyBuilder(as, as).key("test").build();
- builder.with(selfKey2, LlookupVerbBuilder.Type.ALL);
- command = builder.build(); // "llookup:all:@bob:test@bob"
+ SelfKey selfKey2 = Keys.selfKeyBuilder().sharedBy(as).sharedWith(as).name("test").build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(selfKey2)
+ .operation(LookupOperation.all)
+ .build();
assertEquals("llookup:all:@bob:test@bob", command);
-
// with cached public key
- builder = new LlookupVerbBuilder();
- PublicKey pk2 = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key("publickey").build();
- pk2.metadata.isCached = true;
- builder.with(pk2, LlookupVerbBuilder.Type.ALL);
- command = builder.build(); // "llookup:all:cached:public:publickey@bob"
+ PublicKey pk2 = Keys.publicKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .name("publickey")
+ .isCached(true)
+ .build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(pk2)
+ .operation(LookupOperation.all)
+ .build();
assertEquals("llookup:all:cached:public:publickey@bob", command);
// with cached shared key
- builder = new LlookupVerbBuilder();
- SharedKey sk2 = new KeyBuilders.SharedKeyBuilder(new AtSign("@bob"), new AtSign("@alice")).key("sharedkey").build();
- sk2.metadata.isCached = true;
- builder.with(sk2, LlookupVerbBuilder.Type.NONE);
- command = builder.build(); // "llookup:cached:@alice:sharedkey@bob"
+ SharedKey sk2 = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@bob"))
+ .sharedWith(new AtSign("@alice"))
+ .name("sharedkey")
+ .isCached(true)
+ .build();
+ command = VerbBuilders.llookupCommandBuilder()
+ .key(sk2)
+ .operation(LookupOperation.none)
+ .build();
assertEquals("llookup:cached:@alice:sharedkey@bob", command);
// with private hidden key
@@ -294,492 +553,798 @@ public void llookupVerbBuilderTest() {
}
@Test
- public void testLlookupVerbBuilderFoPublicKeyWithNamespace() {
- PublicKey key = new KeyBuilders.PublicKeyBuilder(new AtSign("@alice"))
- .key("test")
+ public void testLlookupBuilderGeneratesExpectedOutputForPublicKeyWithNamespace() {
+ PublicKey key = Keys.publicKeyBuilder().sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- LlookupVerbBuilder builder = new LlookupVerbBuilder();
- builder.with(key, LlookupVerbBuilder.Type.METADATA);
-
- assertThat(builder.build(), equalTo("llookup:meta:public:test.testns@alice"));
+ String command = VerbBuilders.llookupCommandBuilder()
+ .key(key)
+ .operation(LookupOperation.meta)
+ .build();
+ assertThat(command, equalTo("llookup:meta:public:test.testns@alice"));
}
@Test
- public void testLlookupVerbBuilderForSelfKeyWithNamespace() {
- SelfKey key = new KeyBuilders.SelfKeyBuilder(new AtSign("@alice"))
- .key("test")
+ public void testLlookupBuilderGeneratesExpectedOutputForSelfKeyWithNamespace() {
+ SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- LlookupVerbBuilder builder = new LlookupVerbBuilder();
- builder.with(key, LlookupVerbBuilder.Type.METADATA);
-
- assertThat(builder.build(), equalTo("llookup:meta:test.testns@alice"));
+ String command = VerbBuilders.llookupCommandBuilder()
+ .key(key)
+ .operation(LookupOperation.meta)
+ .build();
+ assertThat(command, equalTo("llookup:meta:test.testns@alice"));
}
@Test
- public void testLlookupVerbBuilderForSharedKeyWithNamespace() {
- SharedKey key = new KeyBuilders.SharedKeyBuilder(new AtSign("@alice"), new AtSign("@bob"))
- .key("test")
+ public void testLlookupBuilderGeneratesExpectedOutputForSharedKeyWithNamespace() {
+ SharedKey key = Keys.sharedKeyBuilder().sharedBy(new AtSign("@alice"))
+ .sharedWith(new AtSign("@bob"))
+ .name("test")
.namespace("testns")
.build();
- LlookupVerbBuilder builder = new LlookupVerbBuilder();
- builder.with(key, LlookupVerbBuilder.Type.METADATA);
-
- assertThat(builder.build(), equalTo("llookup:meta:@bob:test.testns@alice"));
+ String command = VerbBuilders.llookupCommandBuilder()
+ .key(key)
+ .operation(LookupOperation.meta)
+ .build();
+ assertThat(command, equalTo("llookup:meta:@bob:test.testns@alice"));
}
@Test
public void lookupVerbBuilderTest() {
- LookupVerbBuilder builder;
String command;
// Type.NONE
- builder = new LookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- command = builder.build(); // "lookup:test@alice"
+ command = VerbBuilders.lookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .build();
+ assertEquals("lookup:test@alice", command);
+ command = VerbBuilders.lookupCommandBuilder()
+ .rawKey("test@alice")
+ .build();
assertEquals("lookup:test@alice", command);
// Type.METADATA
- builder = new LookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setType(LookupVerbBuilder.Type.METADATA);
- command = builder.build(); // "lookup:meta:test@alice"
+ command = VerbBuilders.lookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.meta)
+ .build();
assertEquals("lookup:meta:test@alice", command);
// Type.ALL
- builder = new LookupVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setType(LookupVerbBuilder.Type.ALL);
- command = builder.build(); // "lookup:test@alice"
+ command = VerbBuilders.lookupCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.all)
+ .build(); // "lookup:test@alice"
assertEquals("lookup:all:test@alice", command);
// no key name
- assertThrows(IllegalArgumentException.class, () -> {
- LookupVerbBuilder b = new LookupVerbBuilder();
- b = new LookupVerbBuilder();
- b.setSharedBy("@alice");
- b.build();
- });
-
- // no sharedWith
- assertThrows(IllegalArgumentException.class, () -> {
- LookupVerbBuilder b = new LookupVerbBuilder();
- b = new LookupVerbBuilder();
- b.setKeyName("test");
- b.build();
- });
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.lookupCommandBuilder().sharedBy(createAtSign("@alice")).build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
- // no key name and no shared with
- assertThrows(IllegalArgumentException.class, () -> {
- LookupVerbBuilder b = new LookupVerbBuilder();
- b.build();
- });
+ // no sharedBy
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.lookupCommandBuilder().keyName("test").build());
+ assertThat(ex.getMessage(), containsString("sharedBy not set"));
// with shared key
- builder = new LookupVerbBuilder();
- SharedKey sk =
- new KeyBuilders.SharedKeyBuilder(new AtSign("@sharedby"), new AtSign("@sharedwith")).key("test").build();
- builder.with(sk, LookupVerbBuilder.Type.METADATA);
- command = builder.build(); // "lookup:meta:test@sharedby"
+ SharedKey sk = Keys.sharedKeyBuilder().sharedBy(new AtSign("@sharedby"))
+ .sharedWith(new AtSign("@sharedwith"))
+ .name("test")
+ .build();
+ command = VerbBuilders.lookupCommandBuilder()
+ .key(sk)
+ .operation(LookupOperation.meta)
+ .build();
assertEquals("lookup:meta:test@sharedby", command);
}
@Test
public void testLookupVerbBuilderForSharedKeyWithNamespace() {
- SharedKey key = new KeyBuilders.SharedKeyBuilder(new AtSign("@alice"), new AtSign("@bob"))
- .key("test")
+ SharedKey key = Keys.sharedKeyBuilder().sharedBy(new AtSign("@alice"))
+ .sharedWith(new AtSign("@bob"))
+ .name("test")
.namespace("testns")
.build();
- LookupVerbBuilder builder = new LookupVerbBuilder();
- builder.with(key, LookupVerbBuilder.Type.METADATA);
-
- assertThat(builder.build(), equalTo("lookup:meta:test.testns@alice"));
+ String command = VerbBuilders.lookupCommandBuilder()
+ .key(key)
+ .operation(LookupOperation.meta)
+ .build();
+ assertThat(command, equalTo("lookup:meta:test.testns@alice"));
}
@Test
public void plookupVerbBuilderTest() {
- PlookupVerbBuilder builder;
String command;
// Type.NONE
- builder = new PlookupVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- command = builder.build(); // "plookup:publickey@alice"
+ command = VerbBuilders.plookupCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .build(); // "plookup:publickey@alice"
+ assertEquals("plookup:publickey@alice", command);
+ command = VerbBuilders.plookupCommandBuilder()
+ .rawKey("publickey@alice")
+ .build(); // "plookup:publickey@alice"
assertEquals("plookup:publickey@alice", command);
// Type.METADATA
- builder = new PlookupVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- builder.setType(PlookupVerbBuilder.Type.METADATA);
- command = builder.build(); // "plookup:meta:publickey@alice"
+ command = VerbBuilders.plookupCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.meta)
+ .build();
assertEquals("plookup:meta:publickey@alice", command);
// Type.ALL
- builder = new PlookupVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- builder.setType(PlookupVerbBuilder.Type.ALL);
- command = builder.build(); // "plookup:all:publickey@alice"
+ command = VerbBuilders.plookupCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.all)
+ .build();
assertEquals("plookup:all:publickey@alice", command);
// no key
- assertThrows(IllegalArgumentException.class, () -> {
- PlookupVerbBuilder b = new PlookupVerbBuilder();
- b.setSharedBy("@alice");
- b.setType(Type.ALL);
- b.build();
- });
-
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.plookupCommandBuilder().sharedBy(createAtSign("@alice"))
+ .operation(LookupOperation.all)
+ .build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
// no shared by
- assertThrows(IllegalArgumentException.class, () -> {
- PlookupVerbBuilder b = new PlookupVerbBuilder();
- b.setKeyName("publickey");
- b.setType(Type.ALL);
- b.build();
- });
-
- // no key and no shared by
- assertThrows(IllegalArgumentException.class, () -> {
- PlookupVerbBuilder b = new PlookupVerbBuilder();
- b.setType(Type.ALL);
- b.build();
- });
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.plookupCommandBuilder().keyName("publickey").operation(LookupOperation.all)
+ .build());
+ assertThat(ex.getMessage(), containsString("sharedBy not set"));
// with
- builder = new PlookupVerbBuilder();
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key("publickey").build();
- builder.with(pk, Type.ALL);
- command = builder.build(); // "plookup:all:publickey@bob"
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(new AtSign("@bob")).name("publickey").build();
+ command = VerbBuilders.plookupCommandBuilder()
+ .key(pk)
+ .operation(LookupOperation.all)
+ .build();
assertEquals("plookup:all:publickey@bob", command);
// bypasscache true
- builder = new PlookupVerbBuilder();
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- builder.setBypassCache(true);
- builder.setType(Type.ALL);
- command = builder.build(); // "plookup:bypassCache:true:all:publickey@alice"
+ command = VerbBuilders.plookupCommandBuilder()
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .bypassCache(true)
+ .operation(LookupOperation.all)
+ .build();
assertEquals("plookup:bypassCache:true:all:publickey@alice", command);
}
@Test
public void testPlookupVerbBuilderForPublicKeyWithNamespace() {
- PublicKey key = new KeyBuilders.PublicKeyBuilder(new AtSign("@alice"))
- .key("test")
+ PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- PlookupVerbBuilder builder = new PlookupVerbBuilder();
- builder.with(key, PlookupVerbBuilder.Type.METADATA);
-
- assertThat(builder.build(), equalTo("plookup:meta:test.testns@alice"));
+ String command = VerbBuilders.plookupCommandBuilder()
+ .key(key)
+ .operation(LookupOperation.meta)
+ .build();
+ assertThat(command, equalTo("plookup:meta:test.testns@alice"));
}
@Test
public void deleteVerbBuilderTest() {
- DeleteVerbBuilder builder;
String command;
// delete a public key
- builder = new DeleteVerbBuilder();
- builder.setIsPublic(true);
- builder.setKeyName("publickey");
- builder.setSharedBy("@alice");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .isPublic(true)
+ .keyName("publickey")
+ .sharedBy(createAtSign("@alice"))
+ .build();
+ assertEquals("delete:public:publickey@alice", command);
+ command = VerbBuilders.deleteCommandBuilder()
+ .rawKey("public:publickey@alice")
+ .build();
assertEquals("delete:public:publickey@alice", command);
// delete a cached public key
- builder = new DeleteVerbBuilder();
- builder.setIsCached(true);
- builder.setIsPublic(true);
- builder.setKeyName("publickey");
- builder.setSharedBy("@bob");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .isCached(true)
+ .isPublic(true)
+ .keyName("publickey")
+ .sharedBy(createAtSign("@bob"))
+ .build();
assertEquals("delete:cached:public:publickey@bob", command);
// delete a self key
- builder = new DeleteVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .build();
assertEquals("delete:test@alice", command);
// delete a hidden self key
- builder = new DeleteVerbBuilder();
- builder.setIsHidden(true);
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .isHidden(true)
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .build();
assertEquals("delete:_test@alice", command);
// delete a shared key
- builder = new DeleteVerbBuilder();
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setSharedWith("@bob");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .sharedWith(createAtSign("@bob"))
+ .build();
assertEquals("delete:@bob:test@alice", command);
// delete a cached shared key
- builder = new DeleteVerbBuilder();
- builder.setIsCached(true);
- builder.setKeyName("test");
- builder.setSharedBy("@alice");
- builder.setSharedWith("@bob");
- command = builder.build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .isCached(true)
+ .keyName("test")
+ .sharedBy(createAtSign("@alice"))
+ .sharedWith(createAtSign("@bob"))
+ .build();
assertEquals("delete:cached:@bob:test@alice", command);
// missing key name
- assertThrows(IllegalArgumentException.class, () -> {
- DeleteVerbBuilder b = new DeleteVerbBuilder();
- b.setSharedBy("@alice");
- b.setSharedWith("@bob");
- b.build();
- });
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.deleteCommandBuilder()
+ .sharedBy(createAtSign("@alice"))
+ .sharedWith(createAtSign("@bob"))
+ .build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
// missing shared by
- assertThrows(IllegalArgumentException.class, () -> {
- DeleteVerbBuilder b = new DeleteVerbBuilder();
- b.setKeyName("test");
- b.build();
- });
-
- // missing key name and shared by
- assertThrows(IllegalArgumentException.class, () -> {
- DeleteVerbBuilder b = new DeleteVerbBuilder();
- b.build();
- });
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.deleteCommandBuilder().keyName("test").build());
+ assertThat(ex.getMessage(), containsString("sharedBy not set"));
// with self key
- builder = new DeleteVerbBuilder();
- SelfKey selfKey = new KeyBuilders.SelfKeyBuilder(new AtSign("@alice")).key("test").build();
- builder.with(selfKey);
- command = builder.build();
+ SelfKey selfKey = Keys.selfKeyBuilder().sharedBy(new AtSign("@alice")).name("test").build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .key(selfKey)
+ .build();
assertEquals("delete:test@alice", command);
// with public key
- builder = new DeleteVerbBuilder();
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key("publickey").build();
- builder.with(pk);
- command = builder.build();
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(new AtSign("@bob")).name("publickey").build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .key(pk)
+ .build();
// with shared key
- builder = new DeleteVerbBuilder();
- SharedKey sk = new KeyBuilders.SharedKeyBuilder(new AtSign("@alice"), new AtSign("@bob")).key("test").build();
- builder.with(sk);
- command = builder.build();
+ SharedKey sk = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .sharedWith(new AtSign("@bob"))
+ .name("test")
+ .build();
+ command = VerbBuilders.deleteCommandBuilder()
+ .key(sk)
+ .build();
assertEquals("delete:@bob:test@alice", command);
-
}
@Test
public void testDeleteVerbBuilderForPublicKeyWithNamespace() {
- PublicKey key = new KeyBuilders.PublicKeyBuilder(new AtSign("@alice"))
- .key("test")
+ PublicKey key = Keys.publicKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- DeleteVerbBuilder builder = new DeleteVerbBuilder();
- builder.with(key);
-
- assertThat(builder.build(), equalTo("delete:public:test.testns@alice"));
+ String command = VerbBuilders.deleteCommandBuilder()
+ .key(key)
+ .build();
+ assertThat(command, equalTo("delete:public:test.testns@alice"));
}
@Test
public void testDeleteVerbBuilderForSelfKeyWithNamespace() {
- SelfKey key = new KeyBuilders.SelfKeyBuilder(new AtSign("@alice"))
- .key("test")
+ SelfKey key = Keys.selfKeyBuilder()
+ .sharedBy(new AtSign("@alice"))
+ .name("test")
.namespace("testns")
.build();
- DeleteVerbBuilder builder = new DeleteVerbBuilder();
- builder.with(key);
-
- assertThat(builder.build(), equalTo("delete:test.testns@alice"));
+ String command = VerbBuilders.deleteCommandBuilder()
+ .key(key)
+ .build();
+ assertThat(command, equalTo("delete:test.testns@alice"));
}
@Test
public void testDeleteVerbBuilderForSharedKeyWithNamespace() {
- SharedKey key = new KeyBuilders.SharedKeyBuilder(new AtSign("@alice"), new AtSign("@bob"))
- .key("test")
+ SharedKey key = Keys.sharedKeyBuilder()
+ .sharedBy(new AtSign("@alice")).sharedWith(new AtSign("@bob"))
+ .name("test")
.namespace("testns")
.build();
- DeleteVerbBuilder builder = new DeleteVerbBuilder();
- builder.with(key);
-
- assertThat(builder.build(), equalTo("delete:@bob:test.testns@alice"));
+ String command = VerbBuilders.deleteCommandBuilder()
+ .key(key)
+ .build();
+ assertThat(command, equalTo("delete:@bob:test.testns@alice"));
}
@Test
public void scanVerbBuilderTest() {
// Test not setting any parameters
- ScanVerbBuilder scanVerbBuilder = new ScanVerbBuilder();
- String command = scanVerbBuilder.build();
+ String command = VerbBuilders.scanCommandBuilder().build();
assertEquals("scan", command);
// Test setting just regex
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setRegex("*.public");
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder().regex("*.public")
+ .build();
assertEquals("scan *.public", command);
// Test setting just fromAtSign
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setFromAtSign("@other");
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .fromAtSign(createAtSign("@other"))
+ .build();
assertEquals("scan:@other", command);
// Test seting just showHidden
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setShowHidden(true);
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .showHidden(true)
+ .build();
assertEquals("scan:showHidden:true", command);
// Test setting regex & fromAtSign
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setRegex("*.public");
- scanVerbBuilder.setFromAtSign("@other");
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .regex("*.public")
+ .fromAtSign(createAtSign("@other"))
+ .build();
assertEquals("scan:@other *.public", command);
// Test setting regex & showHidden
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setRegex("*.public");
- scanVerbBuilder.setShowHidden(true);
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .regex("*.public")
+ .showHidden(true)
+ .build();
assertEquals("scan:showHidden:true *.public", command);
// Test setting fromAtSign & showHidden
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setFromAtSign("@other");
- scanVerbBuilder.setShowHidden(true);
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .fromAtSign(createAtSign("@other"))
+ .showHidden(true)
+ .build();
assertEquals("scan:showHidden:true:@other", command);
// Test setting regex & fromAtSign & showHidden
- scanVerbBuilder = new ScanVerbBuilder();
- scanVerbBuilder.setRegex("*.public");
- scanVerbBuilder.setFromAtSign("@other");
- scanVerbBuilder.setShowHidden(true);
- command = scanVerbBuilder.build();
+ command = VerbBuilders.scanCommandBuilder()
+ .regex("*.public")
+ .fromAtSign(createAtSign("@other"))
+ .showHidden(true)
+ .build();
assertEquals("scan:showHidden:true:@other *.public", command);
}
@Test
- public void notifyTextBuilderTest() {
+ public void testNotifyTextBuilderGeneratesTheExpectedOutput() {
// Test not setting any parameters
- final NotifyTextVerbBuilder builderWithNoFieldsSet = new NotifyTextVerbBuilder();
- assertThrows(IllegalArgumentException.class, builderWithNoFieldsSet::build,
- "Recipient @sign and text are mandatory. Expecting a IllegalArgumentException being thrown.");
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class, () -> VerbBuilders.notifyTextCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("recipient not set"));
// Test not setting the text
- final NotifyTextVerbBuilder builderWithTextFieldUnset = new NotifyTextVerbBuilder();
- builderWithTextFieldUnset.setRecipientAtSign("@test");
- assertThrows(IllegalArgumentException.class, builderWithTextFieldUnset::build,
- "Text is mandatory. Expecting a IllegalArgumentException being thrown.");
-
- NotifyTextVerbBuilder notifyTextBuilder = new NotifyTextVerbBuilder();
- notifyTextBuilder.setText("Hi");
- notifyTextBuilder.setRecipientAtSign("@test");
- String expectedResult = "notify:messageType:text:@test:Hi";
- assertEquals(expectedResult, notifyTextBuilder.build());
-
- // test not setting an '@' sign to the recipients at sign and expect it to be
- // appended properly
- notifyTextBuilder = new NotifyTextVerbBuilder();
- notifyTextBuilder.setText("Hello");
- notifyTextBuilder.setRecipientAtSign("test");
- expectedResult = "notify:messageType:text:@test:Hello";
- assertEquals(expectedResult, notifyTextBuilder.build());
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.notifyTextCommandBuilder().recipient(createAtSign("@somebody")).build());
+ assertThat(ex.getMessage(), containsString("text not set"));
+ String command = VerbBuilders.notifyTextCommandBuilder()
+ .recipient(createAtSign("@test"))
+ .text("Hi")
+ .build();
+ assertEquals("notify:messageType:text:@test:Hi", command);
}
@Test
public void notifyKeyChangeBuilderTest() {
// Test not setting any parameters
- final NotifyKeyChangeBuilder builderWithNoArgsSet = new NotifyKeyChangeBuilder();
- assertThrows(IllegalArgumentException.class, builderWithNoArgsSet::build,
- "Mandatory fields are not set. Expecting a IllegalArgumentException being thrown.");
-
- // Test not setting the key
- final NotifyKeyChangeBuilder builderWithNoKeySet = new NotifyKeyChangeBuilder();
- builderWithNoKeySet.setOperation("update");
- builderWithNoKeySet.setSenderAtSign("@sender");
- builderWithNoKeySet.setRecipientAtSign("@recipient");
- assertThrows(IllegalArgumentException.class, builderWithNoKeySet::build,
- "Key is mandatory. Expecting a IllegalArgumentException being thrown.");
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .sender(createAtSign("sender"))
+ .recipient(createAtSign("recipient"))
+ .build());
+ assertThat(ex.getMessage(), containsString("key not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.notifyKeyChangeCommandBuilder().key("key").build());
+ assertThat(ex.getMessage(), containsString("operation not set"));
// Test setting the value when ttr has been set
- final NotifyKeyChangeBuilder builderWithTrrSetButNoValue = new NotifyKeyChangeBuilder();
- builderWithTrrSetButNoValue.setOperation("update");
- builderWithTrrSetButNoValue.setSenderAtSign("@sender");
- builderWithTrrSetButNoValue.setRecipientAtSign("@recipient");
- builderWithTrrSetButNoValue.setKey("phone");
- builderWithTrrSetButNoValue.setTtr(10000);
- assertThrows(IllegalArgumentException.class, builderWithTrrSetButNoValue::build,
- "Value is mandatory if ttr has been set. Expecting a IllegalArgumentException being thrown.");
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .sender(createAtSign("sender"))
+ .recipient(createAtSign("recipient"))
+ .key("phone")
+ .ttr(10000L)
+ .build());
+ assertThat(ex.getMessage(), containsString("value not set (mandatory when ttr is set)"));
// Test setting invalid ttr
- final NotifyKeyChangeBuilder builderWithNegativeTrrSetButNoValue = new NotifyKeyChangeBuilder();
- builderWithNegativeTrrSetButNoValue.setOperation("update");
- builderWithNegativeTrrSetButNoValue.setSenderAtSign("@sender");
- builderWithNegativeTrrSetButNoValue.setRecipientAtSign("@recipient");
- builderWithNegativeTrrSetButNoValue.setKey("phone");
- builderWithNegativeTrrSetButNoValue.setTtr(-100);
- assertThrows(IllegalArgumentException.class, builderWithNegativeTrrSetButNoValue::build,
- "Value is mandatory if ttr has been set. Expecting a IllegalArgumentException being thrown.");
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .sender(createAtSign("sender"))
+ .recipient(createAtSign("recipient"))
+ .key("phone")
+ .ttr(-100L)
+ .build());
+ assertThat(ex.getMessage(), containsString("ttr < -1"));
// test command
- NotifyKeyChangeBuilder notifyKeyChangeBuilder = new NotifyKeyChangeBuilder();
- notifyKeyChangeBuilder.setOperation("update");
- notifyKeyChangeBuilder.setSenderAtSign("@sender");
- notifyKeyChangeBuilder.setRecipientAtSign("@recipient");
- notifyKeyChangeBuilder.setKey("phone");
- // Expect build to throw Illegal argument exception for not setting the text
- String command = notifyKeyChangeBuilder.build();
- String expectedResult = "notify:update:messageType:key:@recipient:phone@sender";
- assertEquals(expectedResult, command);
+ String command = VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .sender(createAtSign("sender"))
+ .recipient(createAtSign("recipient"))
+ .key("phone")
+ .build();
+ assertEquals("notify:update:messageType:key:@recipient:phone@sender", command);
// test command with a fully formed key
- notifyKeyChangeBuilder = new NotifyKeyChangeBuilder();
- notifyKeyChangeBuilder.setOperation("update");
- notifyKeyChangeBuilder.setKey("@recipient:phone@sender");
- // Expect build to throw Illegal argument exception for not setting the text
- command = notifyKeyChangeBuilder.build();
- expectedResult = "notify:update:messageType:key:@recipient:phone@sender";
- assertEquals(expectedResult, command);
+ command = VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .key("@recipient:phone@sender")
+ .build();
+ assertEquals("notify:update:messageType:key:@recipient:phone@sender", command);
// test command when ttr and value are present
- notifyKeyChangeBuilder = new NotifyKeyChangeBuilder();
- notifyKeyChangeBuilder.setOperation("update");
- notifyKeyChangeBuilder.setKey("@recipient:phone@sender");
- notifyKeyChangeBuilder.setTtr(1000);
- notifyKeyChangeBuilder.setValue("cache_me");
- // Expect build to throw Illegal argument exception for not setting the text
- command = notifyKeyChangeBuilder.build();
- expectedResult = "notify:update:messageType:key:ttr:1000:@recipient:phone@sender:cache_me";
- assertEquals(expectedResult, command);
-
+ command = VerbBuilders.notifyKeyChangeCommandBuilder()
+ .operation(NotifyOperation.update)
+ .key("@recipient:phone@sender")
+ .ttr(1000L)
+ .value("cache_me")
+ .build();
+ assertEquals("notify:update:messageType:key:ttr:1000:@recipient:phone@sender:cache_me", command);
}
@Test
public void notificationStatusVerbBuilderTest() {
// Test not setting any parameters
- final NotificationStatusVerbBuilder builderWithNoFieldsSet = new NotificationStatusVerbBuilder();
- assertThrows(IllegalArgumentException.class, builderWithNoFieldsSet::build,
- "Mandatory fields are not set. Expecting a IllegalArgumentException being thrown.");
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class, () -> VerbBuilders.notifyStatusCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("notificationId not set"));
+
+ String command = VerbBuilders.notifyStatusCommandBuilder()
+ .notificationId("n1234").build();
+ assertEquals("notify:status:n1234", command);
+ }
+
+ @Test
+ void testEnrollThrowExceptionIfOperationIsNotSet() {
+ IllegalArgumentException ex =
+ assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("operation not set"));
+ }
+
+ @Test
+ void testEnrollListReturnsExpectedCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.list)
+ .build();
+
+ assertThat(result, is("enroll:list"));
+ }
+
+ @Test
+ void testEnrollListWithStatusProducesCommandWithStatusFilter() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.list)
+ .status("pending")
+ .build();
+
+ assertThat(result, is("enroll:list{\"enrollmentStatusFilter\":[\"pending\"]}"));
+ }
+
+ @Test
+ void testEnrollApproveThrowsIfFieldsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .encryptPrivateKey("privKey")
+ .encryptPrivateKeyIv("privKeyIv")
+ .selfEncryptKey("selfKey")
+ .selfEncryptKeyIv("selfKeyIv")
+ .build());
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .encryptPrivateKeyIv("privKeyIv")
+ .selfEncryptKey("selfKey")
+ .selfEncryptKeyIv("selfKeyIv")
+ .build());
+ assertThat(ex.getMessage(), containsString("encryptPrivateKey not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .encryptPrivateKey("privKey")
+ .selfEncryptKey("selfKey")
+ .selfEncryptKeyIv("selfKeyIv")
+ .build());
+
+ assertThat(ex.getMessage(), containsString("encryptPrivateKeyIv not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .encryptPrivateKey("privKey")
+ .encryptPrivateKeyIv("privKeyIv")
+ .selfEncryptKeyIv("selfKeyIv")
+ .build());
+
+ assertThat(ex.getMessage(), containsString("selfEncryptKey not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .encryptPrivateKey("privKey")
+ .encryptPrivateKeyIv("privKeyIv")
+ .selfEncryptKey("selfKey")
+ .build());
+
+ assertThat(ex.getMessage(), containsString("selfEncryptKeyIv not set"));
+
+ }
+
+ @Test
+ void testEnrollApproveWithAllRequiredParamsReturnsExpectedCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.approve)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .encryptPrivateKey("privKey")
+ .encryptPrivateKeyIv("privKeyIv")
+ .selfEncryptKey("selfKey")
+ .selfEncryptKeyIv("selfKeyIv")
+ .build();
+
+ assertThat(result, is("enroll:approve{" +
+ "\"enrollmentId\":\"abc123\"," +
+ "\"encryptedDefaultEncryptionPrivateKey\":\"privKey\"," +
+ "\"encPrivateKeyIV\":\"privKeyIv\"," +
+ "\"encryptedDefaultSelfEncryptionKey\":\"selfKey\"," +
+ "\"selfEncKeyIV\":\"selfKeyIv\"" +
+ "}"));
+ }
+
+ @Test
+ void testEnrollFetchThrowsExpectedExceptionWhenFieldsAreNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.fetch)
+ .build());
+
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+ }
+
+ @Test
+ void testEnrollFetchWithEnrollmentIdReturnsExpectedCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.fetch)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .build();
- final NotificationStatusVerbBuilder notificationStatusVerbBuilder = new NotificationStatusVerbBuilder();
- notificationStatusVerbBuilder.setNotificationId("n1234");
- String expectedResult = "notify:status:n1234";
- assertEquals(expectedResult, notificationStatusVerbBuilder.build());
+ assertThat(result, is("enroll:fetch{\"enrollmentId\":\"abc123\"}"));
+ }
+
+ @Test
+ void testEnrollDenyThrowExceptionIfEnrollmentIdIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.deny)
+ .build());
+
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+ }
+
+ @Test
+ void testEnrollDenyWithEnrollmentIdProducesCorrectCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.deny)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .build();
+
+ assertThat(result, is("enroll:deny{\"enrollmentId\":\"abc123\"}"));
+ }
+
+ @Test
+ void testEnrollRevokeThrowExceptionIfEnrollmentIdIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.revoke)
+ .build());
+
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+ }
+
+ @Test
+ void testEnrollRevokeWithEnrollmentIdProducesCorrectCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.revoke)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .build();
+
+ assertThat(result, is("enroll:revoke{\"enrollmentId\":\"abc123\"}"));
+ }
+
+ @Test
+ void testEnrollUnrevokeThrowExceptionIfEnrollmentIdIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.unrevoke)
+ .build());
+
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+ }
+
+ @Test
+ void testEnrollUnrevokeWithEnrollmentIdProducesCorrectCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.unrevoke)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .build();
+
+ assertThat(result, is("enroll:unrevoke{\"enrollmentId\":\"abc123\"}"));
+ }
+
+ @Test
+ void testEnrollDeleteThrowExceptionIfEnrollmentIdIsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.delete)
+ .build());
+ assertThat(ex.getMessage(), containsString("enrollmentId not set"));
+ }
+
+ @Test
+ void testEnrollDeleteWithEnrollmentIdProducesCorrectCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.delete)
+ .enrollmentId(createEnrollmentId("abc123"))
+ .build();
+
+ assertThat(result, is("enroll:delete{\"enrollmentId\":\"abc123\"}"));
+ }
+
+ @Test
+ void testEnrollRequestThrowExceptionIfFieldsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("appName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("")
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("appName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("myApp")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("deviceName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("myApp")
+ .deviceName("")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("deviceName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("myApp")
+ .deviceName("myDevice")
+ .build());
+ assertThat(ex.getMessage(), containsString("apkamPublicKey not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .otp("")
+ .appName("myApp")
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("otp not set"));
+
+ ex = assertThrows(IllegalArgumentException.class, () -> VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .otp("AZ19")
+ .appName("myApp")
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .build());
+ assertThat(ex.getMessage(), containsString("namespaces not set"));
+ }
+
+ @Test
+ void testInitialEnrollRequestReturnsExpectedCommand() {
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("myApp")
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .build();
+
+ assertThat(result, is("enroll:request{" +
+ "\"appName\":\"myApp\"," +
+ "\"deviceName\":\"myDevice\"," +
+ "\"apkamPublicKey\":\"pubKey\"" +
+ "}"));
+ }
+
+ @Test
+ void testSubsequentEnrollRequestReturnsExpectedCommand() {
+ Map namespaces = new LinkedHashMap<>();
+ namespaces.put("ns1", "rw");
+
+ String result = VerbBuilders.enrollCommandBuilder()
+ .operation(EnrollOperation.request)
+ .appName("myApp")
+ .deviceName("myDevice")
+ .apkamPublicKey("pubKey")
+ .apkamSymmetricKey("symKey")
+ .otp("123456")
+ .namespaces(namespaces)
+ .ttl(86400000L)
+ .build();
+
+ assertThat(result, is("enroll:request{" +
+ "\"appName\":\"myApp\"," +
+ "\"deviceName\":\"myDevice\"," +
+ "\"apkamPublicKey\":\"pubKey\"," +
+ "\"encryptedAPKAMSymmetricKey\":\"symKey\"," +
+ "\"otp\":\"123456\"," +
+ "\"namespaces\":{\"ns1\":\"rw\"}," +
+ "\"apkamKeysExpiryInMillis\":86400000" +
+ "}"));
+ }
+
+ @Test
+ public void testOtpBuilderGeneratesExpectedOutput() {
+ String command = VerbBuilders.otpCommandBuilder().build();
+ assertEquals("otp:get", command);
+ }
+
+ @Test
+ void testKeysBuilderThrowsExceptionIfFieldsNotSet() {
+ IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.keysCommandBuilder().build());
+ assertThat(ex.getMessage(), containsString("operation not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.keysCommandBuilder().operation(VerbBuilders.KeysOperation.get).build());
+ assertThat(ex.getMessage(), containsString("keyName not set"));
+
+ ex = assertThrows(IllegalArgumentException.class,
+ () -> VerbBuilders.keysCommandBuilder()
+ .operation(VerbBuilders.KeysOperation.delete)
+ .keyName("private:_secret@fred")
+ .build());
+ assertThat(ex.getMessage(), containsString("delete not supported"));
+ }
+
+
+ @Test
+ void testKeysBuilderReturnsExpectedCommand() {
+ String command = VerbBuilders.keysCommandBuilder()
+ .operation(VerbBuilders.KeysOperation.get)
+ .keyName("private:_secret@fred")
+ .build();
+ assertThat(command, equalTo("keys:get:keyName:private:_secret@fred"));
}
}
diff --git a/at_client/src/test/java/org/atsign/cucumber/steps/GetAtKeysSteps.java b/at_client/src/test/java/org/atsign/cucumber/steps/GetAtKeysSteps.java
index 264c4d4c..1f1cdb7d 100644
--- a/at_client/src/test/java/org/atsign/cucumber/steps/GetAtKeysSteps.java
+++ b/at_client/src/test/java/org/atsign/cucumber/steps/GetAtKeysSteps.java
@@ -11,7 +11,6 @@
import org.atsign.client.api.AtClient;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
import io.cucumber.datatable.DataTable;
@@ -210,12 +209,14 @@ private void dumpKeys(AtClient atClient, List headings, boolean fetchMet
private String lookupStringValue(AtClient atClient, Keys.AtKey key) {
try {
- if (key.sharedWith != null) {
- return atClient.get(new KeyBuilders.SharedKeyBuilder(key.sharedBy, key.sharedWith).key(key.name).build()).get();
- } else if (key.metadata.isPublic) {
- return atClient.get(new KeyBuilders.PublicKeyBuilder(key.sharedBy).key(key.name).build()).get();
+ if (key instanceof Keys.SharedKey) {
+ return atClient.get((Keys.SharedKey) key).get();
+ } else if (key instanceof Keys.PublicKey) {
+ return atClient.get((Keys.PublicKey) key).get();
+ } else if (key instanceof Keys.SelfKey) {
+ return atClient.get((Keys.SelfKey) key).get();
} else {
- return atClient.get(new KeyBuilders.SelfKeyBuilder(key.sharedBy).key(key.name).build()).get();
+ return key.getClass().getSimpleName();
}
} catch (Exception e) {
return e.getMessage();
@@ -233,88 +234,88 @@ private List toDataTableRow(List headings, Keys.AtKey k, String
row.add(value);
break;
case "name":
- row.add(k.name);
+ row.add(k.nameWithoutNamespace());
break;
case "namespace":
- row.add(k.getNamespace());
+ row.add(k.namespace());
break;
case "sharedby":
- row.add(k.sharedBy != null ? k.sharedBy.withoutPrefix() : null);
+ row.add(withoutPrefix(k.sharedBy()));
break;
case "sharedwith":
- row.add(k.sharedWith != null ? k.sharedWith.withoutPrefix() : null);
+ row.add(withoutPrefix(k.sharedWith()));
break;
case "ttl":
- row.add(k.metadata != null ? String.valueOf(k.metadata.ttl) : null);
+ row.add(toString(k.metadata().ttl()));
break;
case "ttb":
- row.add(k.metadata != null ? String.valueOf(k.metadata.ttb) : null);
+ row.add(toString(k.metadata().ttb()));
break;
case "ttr":
- row.add(k.metadata != null ? String.valueOf(k.metadata.ttr) : null);
+ row.add(toString(k.metadata().ttb()));
break;
case "ccd":
- row.add(k.metadata != null ? String.valueOf(k.metadata.ccd) : null);
+ row.add(toString(k.metadata().ccd()));
break;
case "createdby":
- row.add(k.metadata != null ? k.metadata.createdBy : null);
+ row.add(toString(k.metadata().createdBy()));
break;
case "updatedby":
- row.add(k.metadata != null ? k.metadata.updatedBy : null);
+ row.add(toString(k.metadata().updatedBy()));
break;
case "availableat":
- row.add(k.metadata != null ? String.valueOf(k.metadata.availableAt) : null);
+ row.add(toString(k.metadata().availableAt()));
break;
case "expiresat":
- row.add(k.metadata != null ? String.valueOf(k.metadata.expiresAt) : null);
+ row.add(toString(k.metadata().expiresAt()));
break;
case "refreshat":
- row.add(k.metadata != null ? String.valueOf(k.metadata.refreshAt) : null);
+ row.add(toString(k.metadata().refreshAt()));
break;
case "createdat":
- row.add(k.metadata != null ? String.valueOf(k.metadata.createdAt) : null);
+ row.add(toString(k.metadata().createdAt()));
break;
case "updatedat":
- row.add(k.metadata != null ? String.valueOf(k.metadata.updatedAt) : null);
+ row.add(toString(k.metadata().updatedAt()));
break;
case "status":
- row.add(k.metadata != null ? k.metadata.status : null);
+ row.add(toString(k.metadata().status()));
break;
case "version":
- row.add(k.metadata != null ? String.valueOf(k.metadata.version) : null);
+ row.add(toString(k.metadata().version()));
break;
case "datasignature":
- row.add(k.metadata != null ? k.metadata.dataSignature : null);
+ row.add(toString(k.metadata().dataSignature()));
break;
case "sharedkeystatus":
- row.add(k.metadata != null ? k.metadata.sharedKeyStatus : null);
+ row.add(toString(k.metadata().sharedKeyStatus()));
break;
case "ispublic":
- row.add(k.metadata != null ? String.valueOf(k.metadata.isPublic) : null);
+ row.add(toString(k.metadata().isPublic()));
break;
case "isencrypted":
- row.add(k.metadata != null ? String.valueOf(k.metadata.isEncrypted) : null);
+ row.add(toString(k.metadata().isEncrypted()));
break;
case "ishidden":
- row.add(k.metadata != null ? String.valueOf(k.metadata.isHidden) : null);
+ row.add(toString(k.metadata().isHidden()));
break;
case "namespaceaware":
- row.add(k.metadata != null ? String.valueOf(k.metadata.namespaceAware) : null);
+ row.add(toString(k.metadata().namespaceAware()));
break;
case "isbinary":
- row.add(k.metadata != null ? String.valueOf(k.metadata.isBinary) : null);
+ row.add(toString(k.metadata().isBinary()));
break;
case "iscached":
- row.add(k.metadata != null ? String.valueOf(k.metadata.isCached) : null);
+ row.add(toString(k.metadata().isCached()));
break;
case "sharedkeyenc":
- row.add(k.metadata != null ? k.metadata.sharedKeyEnc : null);
+ row.add(toString(k.metadata().sharedKeyEnc()));
break;
case "pubkeycs":
- row.add(k.metadata != null ? k.metadata.pubKeyCS : null);
+ row.add(toString(k.metadata().pubKeyCS()));
break;
case "encoding":
- row.add(k.metadata != null ? k.metadata.encoding : null);
+ row.add(toString(k.metadata().encoding()));
break;
default:
throw new IllegalArgumentException(heading + " not recognised as a key or key metadata field");
@@ -337,4 +338,12 @@ private List> getAtKeysAsListOfMaps(AtClient client, String
return actual;
}
+ private static String withoutPrefix(AtSign atSign) {
+ return atSign != null ? atSign.withoutPrefix() : null;
+ }
+
+ private static String toString(Object o) {
+ return o != null ? o.toString() : null;
+ }
+
}
diff --git a/at_client/src/test/java/org/atsign/cucumber/steps/PublicAtKeySteps.java b/at_client/src/test/java/org/atsign/cucumber/steps/PublicAtKeySteps.java
index 2dc611a8..12ca8568 100644
--- a/at_client/src/test/java/org/atsign/cucumber/steps/PublicAtKeySteps.java
+++ b/at_client/src/test/java/org/atsign/cucumber/steps/PublicAtKeySteps.java
@@ -7,9 +7,7 @@
import java.util.regex.Matcher;
import org.atsign.client.api.AtClient;
-import org.atsign.client.util.KeyStringUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
import io.cucumber.java.en.Then;
@@ -205,20 +203,20 @@ private void deleteKeyValue(AtClient atClient, AtSign owner, String name) throws
}
private Keys.PublicKey toKey(AtSign sharedBy, String s) {
- KeyBuilders.PublicKeyBuilder builder = new KeyBuilders.PublicKeyBuilder(sharedBy);
- Matcher matcher = KeyStringUtil.createNamespaceQualifiedKeyNameMatcher(s);
+ Keys.PublicKeyBuilder builder = Keys.publicKeyBuilder()
+ .sharedBy(sharedBy)
+ .ttl(context.getKeyTtl());
+ Matcher matcher = Keys.createNamespaceQualifiedKeyNameMatcher(s);
if (matcher.matches()) {
if (context.isNamespaceSet()) {
throw new IllegalArgumentException("context has namespace set, intention is ambiguous");
}
- builder.namespace(matcher.group(2)).key(matcher.group(1));
+ builder.namespace(matcher.group(2)).name(matcher.group(1));
} else if (context.isNamespaceSet()) {
- builder.namespace(context.getNamespace()).key(s);
+ builder.namespace(context.getNamespace()).name(s);
} else {
- builder.key(s);
+ builder.name(s);
}
- Keys.PublicKey key = builder.build();
- key.metadata.ttl = (int) context.getKeyTtl();
- return key;
+ return builder.build();
}
}
diff --git a/at_client/src/test/java/org/atsign/cucumber/steps/SelfAtKeySteps.java b/at_client/src/test/java/org/atsign/cucumber/steps/SelfAtKeySteps.java
index d6ecf162..4594a193 100644
--- a/at_client/src/test/java/org/atsign/cucumber/steps/SelfAtKeySteps.java
+++ b/at_client/src/test/java/org/atsign/cucumber/steps/SelfAtKeySteps.java
@@ -7,9 +7,7 @@
import java.util.regex.Matcher;
import org.atsign.client.api.AtClient;
-import org.atsign.client.util.KeyStringUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
import io.cucumber.java.en.Then;
@@ -150,20 +148,20 @@ private void deleteKeyValue(AtClient atClient, AtSign atSign, String name) throw
}
private Keys.SelfKey createKey(AtSign owner, String s) {
- KeyBuilders.SelfKeyBuilder builder = new KeyBuilders.SelfKeyBuilder(owner);
- Matcher matcher = KeyStringUtil.createNamespaceQualifiedKeyNameMatcher(s);
+ Keys.SelfKeyBuilder builder = Keys.selfKeyBuilder()
+ .sharedBy(owner)
+ .ttl(context.getKeyTtl());
+ Matcher matcher = Keys.createNamespaceQualifiedKeyNameMatcher(s);
if (matcher.matches()) {
if (context.isNamespaceSet()) {
throw new IllegalArgumentException("context has namespace set, intention is ambiguous");
}
- builder.namespace(matcher.group(2)).key(matcher.group(1));
+ builder.namespace(matcher.group(2)).name(matcher.group(1));
} else if (context.isNamespaceSet()) {
- builder.namespace(context.getNamespace()).key(s);
+ builder.namespace(context.getNamespace()).name(s);
} else {
- builder.key(s);
+ builder.name(s);
}
- Keys.SelfKey key = builder.build();
- key.metadata.ttl = (int) context.getKeyTtl();
- return key;
+ return builder.build();
}
}
diff --git a/at_client/src/test/java/org/atsign/cucumber/steps/SharedAtKeySteps.java b/at_client/src/test/java/org/atsign/cucumber/steps/SharedAtKeySteps.java
index 624c92f7..a65fe116 100644
--- a/at_client/src/test/java/org/atsign/cucumber/steps/SharedAtKeySteps.java
+++ b/at_client/src/test/java/org/atsign/cucumber/steps/SharedAtKeySteps.java
@@ -6,9 +6,7 @@
import java.util.regex.Matcher;
import org.atsign.client.api.AtClient;
-import org.atsign.client.util.KeyStringUtil;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
import org.atsign.common.Keys;
import io.cucumber.java.en.Then;
@@ -206,21 +204,22 @@ private void deleteKeyValue(AtClient atClient, AtSign sharedBy, String name, AtS
}
private Keys.SharedKey createKey(AtSign sharedBy, String s, AtSign sharedWith) {
- KeyBuilders.SharedKeyBuilder builder = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith);
- Matcher matcher = KeyStringUtil.createNamespaceQualifiedKeyNameMatcher(s);
+ Keys.SharedKeyBuilder builder = Keys.sharedKeyBuilder()
+ .sharedBy(sharedBy)
+ .sharedWith(sharedWith)
+ .ttl(context.getKeyTtl());
+ Matcher matcher = Keys.createNamespaceQualifiedKeyNameMatcher(s);
if (matcher.matches()) {
if (context.isNamespaceSet()) {
throw new IllegalArgumentException("context has namespace set, intention is ambiguous");
}
- builder.namespace(matcher.group(2)).key(matcher.group(1));
+ builder.namespace(matcher.group(2)).name(matcher.group(1));
} else if (context.isNamespaceSet()) {
- builder.namespace(context.getNamespace()).key(s);
+ builder.namespace(context.getNamespace()).name(s);
} else {
- builder.key(s);
+ builder.name(s);
}
- Keys.SharedKey key = builder.build();
- key.metadata.ttl = (int) context.getKeyTtl();
- return key;
+ return builder.build();
}
}
diff --git a/at_client/src/test/resources/features/SelfKey.feature b/at_client/src/test/resources/features/SelfKey.feature
index 0165a5ec..d12e3d33 100644
--- a/at_client/src/test/resources/features/SelfKey.feature
+++ b/at_client/src/test/resources/features/SelfKey.feature
@@ -31,7 +31,6 @@ Feature: AtClient API tests for SelfKeys
| test@gary |
Scenario: SelfKeys are invisible to other at signs
- And dump keys
And AtClient.put for SelfKey test and value "hello world"
Then @colin AtClient.getAtKeys for ".+" does NOT contain
| test@gary |
diff --git a/at_client/src/test/resources/features/SharedKey.feature b/at_client/src/test/resources/features/SharedKey.feature
index 25fec692..bae5448b 100644
--- a/at_client/src/test/resources/features/SharedKey.feature
+++ b/at_client/src/test/resources/features/SharedKey.feature
@@ -52,3 +52,9 @@ Feature: AtClient API test for SharedKeys
And @colin AtClient.put for SharedKey message.ns shared with @gary and value "hi gary it's colin"
Then @colin AtClient.get for SharedKey message.ns shared by @gary returns value that matches "hi colin it's gary"
And @gary AtClient.get for SharedKey message.ns shared by @colin returns value that matches "hi gary it's colin"
+
+ Scenario: SharedKey get returns expected value for "Shared With" atsign after change
+ When AtClient.put for SharedKey test shared with @colin and value "hello world"
+ And @colin AtClient.get for SharedKey test shared by @gary returns value that matches "hello world"
+ And AtClient.put for SharedKey test shared with @colin and value "goodbye cruel world"
+ Then @colin AtClient.get for SharedKey test shared by @gary returns value that matches "goodbye cruel world"
diff --git a/at_shell/src/main/java/org/atsign/client/cli/REPL.java b/at_shell/src/main/java/org/atsign/client/cli/REPL.java
index 90d4f4d1..38931828 100644
--- a/at_shell/src/main/java/org/atsign/client/cli/REPL.java
+++ b/at_shell/src/main/java/org/atsign/client/cli/REPL.java
@@ -12,7 +12,6 @@
import org.atsign.client.api.AtEvents.AtEventType;
import org.atsign.client.api.Secondary;
import org.atsign.client.util.ArgsUtil;
-import org.atsign.client.util.KeyStringUtil;
import org.atsign.client.util.KeysUtil;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
@@ -100,21 +99,17 @@ public void repl() throws AtException {
printHelpInstructions();
} else if ("get".equals(verb)) {
String fullKeyName = parts[1];
- KeyStringUtil keyStringUtil = new KeyStringUtil(fullKeyName);
- KeyStringUtil.KeyType keyType = keyStringUtil.getKeyType();
- if (keyType.equals(KeyStringUtil.KeyType.PUBLIC_KEY)) {
- PublicKey pk = (PublicKey) Keys.fromString(fullKeyName);
- String value = client.get(pk).get();
+ Keys.AtKey key = Keys.keyBuilder().rawKey(fullKeyName).build();
+ if (key instanceof PublicKey) {
+ String value = client.get((PublicKey) key).get();
System.out.println(" => \033[31m" + value + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SELF_KEY)) {
- SelfKey sk = (SelfKey) Keys.fromString(fullKeyName);
- String value = client.get(sk).get();
+ } else if (key instanceof SelfKey) {
+ String value = client.get((SelfKey) key).get();
System.out.println(" => \033[31m" + value + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SHARED_KEY)) {
- SharedKey sk = Keys.SharedKey.fromString(fullKeyName);
- String value = client.get(sk).get();
+ } else if (key instanceof SharedKey) {
+ String value = client.get((SharedKey) key).get();
System.out.println(" => \033[31m" + value + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.PRIVATE_HIDDEN_KEY)) {
+ } else if (key instanceof Keys.PrivateHiddenKey) {
throw new UnsupportedOperationException("PrivateHiddenKey is not implemented yet");
} else {
throw new AtInvalidSyntaxException("Could not evaluate the key type of: " + fullKeyName);
@@ -122,21 +117,17 @@ public void repl() throws AtException {
} else if ("put".equals(verb)) {
String fullKeyName = parts[1];
String value = command.substring(verb.length() + fullKeyName.length() + 2).trim();
- KeyStringUtil keyStringUtil = new KeyStringUtil(fullKeyName);
- KeyStringUtil.KeyType keyType = keyStringUtil.getKeyType();
- if (keyType.equals(KeyStringUtil.KeyType.PUBLIC_KEY)) {
- PublicKey pk = (PublicKey) Keys.fromString(fullKeyName);
- String data = client.put(pk, value).get();
+ Keys.AtKey key = Keys.keyBuilder().rawKey(fullKeyName).build();
+ if (key instanceof PublicKey) {
+ String data = client.put((PublicKey) key, value).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SELF_KEY)) {
- SelfKey sk = (SelfKey) Keys.fromString(fullKeyName);
- String data = client.put(sk, value).get();
+ } else if (key instanceof SelfKey) {
+ String data = client.put((SelfKey) key, value).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SHARED_KEY)) {
- SharedKey sk = Keys.SharedKey.fromString(fullKeyName);
- String data = client.put(sk, value).get();
+ } else if (key instanceof SharedKey) {
+ String data = client.put((SharedKey) key, value).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.PRIVATE_HIDDEN_KEY)) {
+ } else if (key instanceof Keys.PrivateHiddenKey) {
throw new UnsupportedOperationException("PrivateHiddenKey is not implemented yet");
} else {
throw new AtIllegalArgumentException("Could not evaluate the key type of: " + fullKeyName);
@@ -150,21 +141,17 @@ public void repl() throws AtException {
System.out.println(" => \033[31m" + value + "\033[0m");
} else if ("delete".equals(verb)) {
String fullKeyName = parts[1];
- KeyStringUtil keyStringUtil = new KeyStringUtil(fullKeyName);
- KeyStringUtil.KeyType keyType = keyStringUtil.getKeyType();
- if (keyType.equals(KeyStringUtil.KeyType.PUBLIC_KEY)) {
- PublicKey pk = (PublicKey) Keys.fromString(fullKeyName);
- String data = client.delete(pk).get();
+ Keys.AtKey key = Keys.keyBuilder().rawKey(fullKeyName).build();
+ if (key instanceof PublicKey) {
+ String data = client.delete((PublicKey) key).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SELF_KEY)) {
- SelfKey sk = (SelfKey) Keys.fromString(fullKeyName);
- String data = client.delete(sk).get();
+ } else if (key instanceof SelfKey) {
+ String data = client.delete((SelfKey) key).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.SHARED_KEY)) {
- SharedKey sk = Keys.SharedKey.fromString(fullKeyName);
- String data = client.delete(sk).get();
+ } else if (key instanceof SharedKey) {
+ String data = client.delete((SharedKey) key).get();
System.out.println(" => \033[31m" + data + "\033[0m");
- } else if (keyType.equals(KeyStringUtil.KeyType.PRIVATE_HIDDEN_KEY)) {
+ } else if (key instanceof Keys.PrivateHiddenKey) {
throw new UnsupportedOperationException("PrivateHiddenKey is not implemented yet");
} else {
throw new AtIllegalArgumentException("Could not evaluate the key type of: " + fullKeyName);
@@ -214,7 +201,7 @@ public void handleEvent(AtEventType eventType, Map eventData) {
String decryptedValue;
switch (eventType) {
case decryptedUpdateNotification:
- sharedKey = Keys.SharedKey.fromString((String) eventData.get("key"));
+ sharedKey = Keys.sharedKeyBuilder().rawKey((String) eventData.get("key")).build();
value = (String) eventData.get("value");
decryptedValue = (String) eventData.get("decryptedValue");
System.out.println(" => Notification ==> \033[31m Key: [" + sharedKey + "] ==> EncryptedValue [" + value
@@ -227,7 +214,7 @@ public void handleEvent(AtEventType eventType, Map eventData) {
break;
case updateNotification:
try {
- sharedKey = Keys.SharedKey.fromString((String) eventData.get("key"));
+ sharedKey = Keys.sharedKeyBuilder().rawKey((String) eventData.get("key")).build();
String encryptedValue = (String) eventData.get("value");
decryptedValue = client.get(sharedKey).get();
System.out.println(" => Notification ==> \033[31m Key: [" + sharedKey + "] ==> EncryptedValue ["
diff --git a/examples/src/main/java/org/atsign/examples/PublicKeyDeleteExample.java b/examples/src/main/java/org/atsign/examples/PublicKeyDeleteExample.java
index c299bae0..3ee3a1ca 100644
--- a/examples/src/main/java/org/atsign/examples/PublicKeyDeleteExample.java
+++ b/examples/src/main/java/org/atsign/examples/PublicKeyDeleteExample.java
@@ -8,7 +8,7 @@
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.PublicKey;
public class PublicKeyDeleteExample {
@@ -28,7 +28,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create public key
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(atSign).key(KEY_NAME).build();
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(atSign).name(KEY_NAME).build();
// 5. delete the key
String response = atClient.delete(pk).get();
diff --git a/examples/src/main/java/org/atsign/examples/PublicKeyGetBypassCacheExample.java b/examples/src/main/java/org/atsign/examples/PublicKeyGetBypassCacheExample.java
index 6854d018..21ad8494 100644
--- a/examples/src/main/java/org/atsign/examples/PublicKeyGetBypassCacheExample.java
+++ b/examples/src/main/java/org/atsign/examples/PublicKeyGetBypassCacheExample.java
@@ -6,7 +6,7 @@
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.PublicKey;
import org.atsign.common.options.GetRequestOptions;
@@ -28,7 +28,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create the key
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(new AtSign("@bob")).key(KEY_NAME).build();
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(new AtSign("@bob")).name(KEY_NAME).build();
// 5. get the value associated with the key
String response = atClient.get(pk, (GetRequestOptions) new GetRequestOptions().bypassCache(true).build()).get();
diff --git a/examples/src/main/java/org/atsign/examples/PublicKeyGetExample.java b/examples/src/main/java/org/atsign/examples/PublicKeyGetExample.java
index b983f5b6..a904e83d 100644
--- a/examples/src/main/java/org/atsign/examples/PublicKeyGetExample.java
+++ b/examples/src/main/java/org/atsign/examples/PublicKeyGetExample.java
@@ -6,7 +6,7 @@
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.PublicKey;
import static org.atsign.client.util.KeysUtil.loadKeys;
@@ -27,7 +27,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create the key
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(atSign).key(KEY_NAME).build();
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(atSign).name(KEY_NAME).build();
// 5. get the value associated with the key
String response = atClient.get(pk).get();
diff --git a/examples/src/main/java/org/atsign/examples/PublicKeyPutExample.java b/examples/src/main/java/org/atsign/examples/PublicKeyPutExample.java
index 6464a33f..067e22ae 100644
--- a/examples/src/main/java/org/atsign/examples/PublicKeyPutExample.java
+++ b/examples/src/main/java/org/atsign/examples/PublicKeyPutExample.java
@@ -1,16 +1,16 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.PublicKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class PublicKeyPutExample {
public static void main(String[] args) {
@@ -29,7 +29,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create a new public key
- PublicKey pk = new KeyBuilders.PublicKeyBuilder(atSign).key(KEY_NAME).build();
+ PublicKey pk = Keys.publicKeyBuilder().sharedBy(atSign).name(KEY_NAME).build();
// 5. put the key
String response = atClient.put(pk, VALUE).get();
diff --git a/examples/src/main/java/org/atsign/examples/SelfKeyDeleteExample.java b/examples/src/main/java/org/atsign/examples/SelfKeyDeleteExample.java
index efb0d508..5b5c97e1 100644
--- a/examples/src/main/java/org/atsign/examples/SelfKeyDeleteExample.java
+++ b/examples/src/main/java/org/atsign/examples/SelfKeyDeleteExample.java
@@ -1,16 +1,16 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SelfKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SelfKeyDeleteExample {
public static void main(String[] args) {
@@ -28,7 +28,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create self key
- SelfKey sk = new KeyBuilders.SelfKeyBuilder(atSign).key(KEY_NAME).build();
+ SelfKey sk = Keys.selfKeyBuilder().sharedBy(atSign).name(KEY_NAME).build();
// 5. delete the key
String response = atClient.delete(sk).get();
diff --git a/examples/src/main/java/org/atsign/examples/SelfKeyGetExample.java b/examples/src/main/java/org/atsign/examples/SelfKeyGetExample.java
index b8b0aee4..edf82c04 100644
--- a/examples/src/main/java/org/atsign/examples/SelfKeyGetExample.java
+++ b/examples/src/main/java/org/atsign/examples/SelfKeyGetExample.java
@@ -1,17 +1,17 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SelfKey;
import org.atsign.common.Metadata;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SelfKeyGetExample {
public static void main(String[] args) {
@@ -29,12 +29,12 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create selfkey
- SelfKey sk = new KeyBuilders.SelfKeyBuilder(atSign).key(KEY_NAME).build();
+ SelfKey sk = Keys.selfKeyBuilder().sharedBy(atSign).name(KEY_NAME).build();
// 5. get the key
String response = atClient.get(sk).get();
System.out.println(response);
- _printMetadata(sk.metadata);
+ _printMetadata(sk.metadata());
} catch (AtException | IOException | InterruptedException | ExecutionException e) {
System.err.println("Failed to connect to remote server " + e);
@@ -44,26 +44,24 @@ public static void main(String[] args) {
private static void _printMetadata(Metadata metadata) {
- System.out.println("ttl: " + metadata.ttl);
- System.out.println("ttb: " + metadata.ttb);
- System.out.println("ttr: " + metadata.ttr);
- System.out.println("ccd: " + metadata.ccd);
- System.out.println("availableAt: " + (metadata.availableAt != null ? metadata.availableAt.toString() : "null"));
- System.out.println("expiresAt: " + (metadata.expiresAt != null ? metadata.expiresAt.toString() : "null"));
- System.out.println("refreshAt: " + (metadata.refreshAt != null ? metadata.refreshAt.toString() : "null"));
- System.out.println("createdAt: " + (metadata.createdAt != null ? metadata.createdAt.toString() : "null"));
- System.out.println("updatedAt: " + (metadata.updatedAt != null ? metadata.updatedAt.toString() : "null"));
- System.out.println("dataSignature: " + metadata.dataSignature);
- System.out.println("sharedKeyStatus: " + metadata.sharedKeyStatus);
- System.out.println("isPublic: " + metadata.isPublic);
- System.out.println("isEncrypted: " + metadata.isEncrypted);
- System.out.println("isHidden: " + metadata.isHidden);
- System.out.println("namespaceAware: " + metadata.namespaceAware);
- System.out.println("isBinary: " + metadata.isBinary);
- System.out.println("isCached: " + metadata.isCached);
- System.out.println("sharedKeyEnc: " + metadata.sharedKeyEnc);
- System.out.println("pubKeyCS: " + metadata.pubKeyCS);
+ System.out.println("ttl: " + metadata.ttl());
+ System.out.println("ttb: " + metadata.ttb());
+ System.out.println("ttr: " + metadata.ttr());
+ System.out.println("ccd: " + metadata.ccd());
+ System.out.println("availableAt: " + (metadata.availableAt() != null ? metadata.availableAt().toString() : "null"));
+ System.out.println("expiresAt: " + (metadata.expiresAt() != null ? metadata.expiresAt().toString() : "null"));
+ System.out.println("refreshAt: " + (metadata.refreshAt() != null ? metadata.refreshAt().toString() : "null"));
+ System.out.println("createdAt: " + (metadata.createdAt() != null ? metadata.createdAt().toString() : "null"));
+ System.out.println("updatedAt: " + (metadata.updatedAt() != null ? metadata.updatedAt().toString() : "null"));
+ System.out.println("dataSignature: " + metadata.dataSignature());
+ System.out.println("sharedKeyStatus: " + metadata.sharedKeyStatus());
+ System.out.println("isPublic: " + metadata.isPublic());
+ System.out.println("isEncrypted: " + metadata.isEncrypted());
+ System.out.println("isHidden: " + metadata.isHidden());
+ System.out.println("namespaceAware: " + metadata.namespaceAware());
+ System.out.println("isBinary: " + metadata.isBinary());
+ System.out.println("isCached: " + metadata.isCached());
+ System.out.println("sharedKeyEnc: " + metadata.sharedKeyEnc());
+ System.out.println("pubKeyCS: " + metadata.pubKeyCS());
}
-
-
}
diff --git a/examples/src/main/java/org/atsign/examples/SelfKeyPutExample.java b/examples/src/main/java/org/atsign/examples/SelfKeyPutExample.java
index cbd1c8d0..c4d377b2 100644
--- a/examples/src/main/java/org/atsign/examples/SelfKeyPutExample.java
+++ b/examples/src/main/java/org/atsign/examples/SelfKeyPutExample.java
@@ -1,16 +1,17 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SelfKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SelfKeyPutExample {
public static void main(String[] args) {
@@ -21,7 +22,7 @@ public static void main(String[] args) {
String KEY_NAME = "test";
String VALUE = "I hate pineapple on pizza!!!";
- int ttl = 30 * 60 * 1000;
+ long ttl = TimeUnit.SECONDS.toMillis(30);
// 2. create AtSign object
@@ -31,8 +32,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, atSign, loadKeys(atSign), VERBOSE)) {
// 4. create selfkey
- SelfKey sk = new KeyBuilders.SelfKeyBuilder(atSign).key(KEY_NAME).build();
- sk.metadata.ttl = ttl;
+ SelfKey sk = Keys.selfKeyBuilder().sharedBy(atSign).name(KEY_NAME).ttl(ttl).build();
// 5. put the key
String response = atClient.put(sk, VALUE).get();
diff --git a/examples/src/main/java/org/atsign/examples/SharedKeyDeleteExample.java b/examples/src/main/java/org/atsign/examples/SharedKeyDeleteExample.java
index d3d6b188..dd8e57c6 100644
--- a/examples/src/main/java/org/atsign/examples/SharedKeyDeleteExample.java
+++ b/examples/src/main/java/org/atsign/examples/SharedKeyDeleteExample.java
@@ -1,16 +1,16 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SharedKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SharedKeyDeleteExample {
/// Delete a SharedKey that you shared with another atSign, the key must be on your own secondary server (belonging to the sharedBy atSign)
@@ -30,7 +30,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, sharedBy, loadKeys(sharedBy), VERBOSE)) {
// 4. create SharedKey instance
- SharedKey sk = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key(KEY_NAME).build();
+ SharedKey sk = Keys.sharedKeyBuilder().sharedBy(sharedBy).sharedWith(sharedWith).name(KEY_NAME).build();
// 5. delete the key
String response = atClient.delete(sk).get();
diff --git a/examples/src/main/java/org/atsign/examples/SharedKeyGetOtherExample.java b/examples/src/main/java/org/atsign/examples/SharedKeyGetOtherExample.java
index e0695f42..9ab6e8e5 100644
--- a/examples/src/main/java/org/atsign/examples/SharedKeyGetOtherExample.java
+++ b/examples/src/main/java/org/atsign/examples/SharedKeyGetOtherExample.java
@@ -1,16 +1,16 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SharedKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SharedKeyGetOtherExample {
/// Get the SharedKey sharedBy another person and sharedWith you
public static void main(String[] args) {
@@ -30,7 +30,7 @@ public static void main(String[] args) {
// 4. create SharedKey instance
// key is sharedBy the other person and sharedWith you.
- SharedKey sk = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key(KEY_NAME).build();
+ SharedKey sk = Keys.sharedKeyBuilder().sharedBy(sharedBy).sharedWith(sharedWith).name(KEY_NAME).build();
// 5. get the key
String response = atClient.get(sk).get();
diff --git a/examples/src/main/java/org/atsign/examples/SharedKeyGetSelfExample.java b/examples/src/main/java/org/atsign/examples/SharedKeyGetSelfExample.java
index d950364c..8012f449 100644
--- a/examples/src/main/java/org/atsign/examples/SharedKeyGetSelfExample.java
+++ b/examples/src/main/java/org/atsign/examples/SharedKeyGetSelfExample.java
@@ -1,16 +1,16 @@
package org.atsign.examples;
+import static org.atsign.client.util.KeysUtil.loadKeys;
+
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.atsign.client.api.AtClient;
import org.atsign.common.AtException;
import org.atsign.common.AtSign;
-import org.atsign.common.KeyBuilders;
+import org.atsign.common.Keys;
import org.atsign.common.Keys.SharedKey;
-import static org.atsign.client.util.KeysUtil.loadKeys;
-
public class SharedKeyGetSelfExample {
/// Get a SharedKey that you created and shared with another atSign
public static void main(String[] args) {
@@ -29,7 +29,7 @@ public static void main(String[] args) {
try (AtClient atClient = AtClient.withRemoteSecondary(ROOT_URL, sharedBy, loadKeys(sharedBy), VERBOSE)) {
// 4. create SharedKey instance
- SharedKey sk = new KeyBuilders.SharedKeyBuilder(sharedBy, sharedWith).key(KEY_NAME).build();
+ SharedKey sk = Keys.sharedKeyBuilder().sharedBy(sharedBy).sharedWith(sharedWith).name(KEY_NAME).build();
// 5. get the key
String response = atClient.get(sk).get();
diff --git a/lombok.config b/lombok.config
new file mode 100644
index 00000000..7a21e880
--- /dev/null
+++ b/lombok.config
@@ -0,0 +1 @@
+lombok.addLombokGeneratedAnnotation = true
diff --git a/pom.xml b/pom.xml
index faba552b..9d3f6311 100644
--- a/pom.xml
+++ b/pom.xml
@@ -230,6 +230,9 @@
+
+ true
+