Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions at_client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ The latest snapshot version can be added as a maven dependency like this...
The SDK currently depends on the following

* Bouncycastle (encryption, decryption, and cryptography utilities)
* Netty (networking)
* Jackson (support for JSON and YAML encoding and decoding)
* Pico CLI (lightweight command line interface framework)
* Slf4j api (Simple logging facade that can be bound a variety of logging
Expand Down
4 changes: 4 additions & 0 deletions at_client/src/main/java/org/atsign/client/api/Metadata.java
Original file line number Diff line number Diff line change
Expand Up @@ -356,4 +356,8 @@ public static boolean setIvNonceIfNotNull(MetadataBuilder builder, String value)
return false;
}
}

public static boolean isBinary(Metadata metadata) {
return metadata.isBinary() != null && metadata.isBinary();
}
}
49 changes: 37 additions & 12 deletions at_client/src/main/java/org/atsign/client/impl/AtClientImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,10 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.atomic.AtomicBoolean;

import org.atsign.client.api.AtClient;
import org.atsign.client.api.AtCommandExecutor;
import org.atsign.client.api.*;
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.AtKeys;
import org.atsign.client.api.AtSign;
import org.atsign.client.api.Keys.AtKey;
import org.atsign.client.api.Keys.PublicKey;
import org.atsign.client.api.Keys.SelfKey;
Expand All @@ -28,6 +25,7 @@

import lombok.Builder;
import lombok.extern.slf4j.Slf4j;
import org.atsign.client.impl.util.Base2e15Utils;

/**
* Implementation of an {@link AtClient} which uses a {@link AtCommandExecutor} and
Expand Down Expand Up @@ -144,7 +142,7 @@ public CompletableFuture<String> get(SharedKey sharedKey) {

@Override
public CompletableFuture<byte[]> getBinary(SharedKey sharedKey) {
throw new UnsupportedOperationException("to be implemented");
return wrapAsync(() -> Base2e15Utils.decode(SharedKeyCommands.get(executor, atSign, keys, sharedKey, true)));
}

@Override
Expand All @@ -164,7 +162,7 @@ public CompletableFuture<String> get(SelfKey selfKey) {

@Override
public CompletableFuture<byte[]> getBinary(SelfKey selfKey) {
throw new UnsupportedOperationException("to be implemented");
return wrapAsync(() -> Base2e15Utils.decode(SelfKeyCommands.get(executor, atSign, keys, selfKey, true)));
}

@Override
Expand All @@ -189,12 +187,12 @@ public CompletableFuture<String> get(PublicKey publicKey, GetRequestOptions opti

@Override
public CompletableFuture<byte[]> getBinary(PublicKey publicKey) {
throw new UnsupportedOperationException("to be implemented");
return wrapAsync(() -> Base2e15Utils.decode(PublicKeyCommands.get(executor, atSign, publicKey, true, null)));
}

@Override
public CompletableFuture<byte[]> getBinary(PublicKey publicKey, GetRequestOptions options) {
throw new UnsupportedOperationException("to be implemented");
return wrapAsync(() -> Base2e15Utils.decode(PublicKeyCommands.get(executor, atSign, publicKey, true, options)));
}

@Override
Expand All @@ -209,17 +207,17 @@ public CompletableFuture<Void> delete(PublicKey publicKey) {

@Override
public CompletableFuture<Void> put(SharedKey sharedKey, byte[] value) {
throw new UnsupportedOperationException("to be implemented");
return put(setIsBinary(sharedKey), Base2e15Utils.encode(value));
}

@Override
public CompletableFuture<Void> put(SelfKey selfKey, byte[] value) {
throw new UnsupportedOperationException("to be implemented");
return put(setIsBinary(selfKey), Base2e15Utils.encode(value));
}

@Override
public CompletableFuture<Void> put(PublicKey publicKey, byte[] value) {
throw new UnsupportedOperationException("to be implemented");
return put(setIsBinary(publicKey), Base2e15Utils.encode(value));
}

@Override
Expand Down Expand Up @@ -284,7 +282,7 @@ private void onUpdateNotification(Map<String, Object> eventData) throws AtExcept
}

/**
* A runnable command which returns a value but can throw {@link AtException}s or execution
* A runnable command which returns a String value but can throw {@link AtException}s or execution
* exceptions
*/
public interface AtCommandThatReturnsString {
Expand All @@ -301,6 +299,25 @@ private static CompletableFuture<String> wrapAsync(AtCommandThatReturnsString co
});
}

/**
* A runnable command which returns a byte array value but can throw {@link AtException}s or
* execution
* exceptions
*/
public interface AtCommandThatReturnsByteArray {
byte[] run() throws AtException, ExecutionException, InterruptedException;
}

private static CompletableFuture<byte[]> wrapAsync(AtCommandThatReturnsByteArray command) {
return CompletableFuture.supplyAsync(() -> {
try {
return command.run();
} catch (Exception e) {
throw new CompletionException(e);
}
});
}

/**
* A runnable command which does NOT return a value but can throw {@link AtException}s or execution
* exceptions
Expand All @@ -319,4 +336,12 @@ private static CompletableFuture<Void> wrapAsync(AtCommandThatReturnsVoid comman
}
});
}

private static <T extends AtKey> T setIsBinary(T key) {
if (!Metadata.isBinary(key.metadata())) {
key.overwriteMetadata(key.metadata().toBuilder().isBinary(true).build());
}
return key;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import static org.atsign.client.impl.commands.DataResponses.matchDataInt;
import static org.atsign.client.impl.commands.DataResponses.matchLookupResponse;
import static org.atsign.client.impl.commands.ErrorResponses.throwExceptionIfError;
import static org.atsign.client.impl.common.Preconditions.checkTrue;
import static org.atsign.client.impl.util.EncryptionUtils.signSHA256RSA;

import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -34,10 +35,29 @@ public class PublicKeyCommands {
*/
public static String get(AtCommandExecutor executor, AtSign atSign, PublicKey key, GetRequestOptions options)
throws AtException {
return get(executor, atSign, key, false, options);
}

/**
* Get the String value associated with a public key.
*
* @param executor The {@link AtCommandExecutor} to use.
* @param atSign The AtSign that corresponds to the executor.
* @param key The {@link PublicKey}
* @param options If set then can be used to bypass caches.
* @return The associated value.
* @throws AtException If any of the commands fail or the key does not exist.
*/
public static String get(AtCommandExecutor executor,
AtSign atSign,
PublicKey key,
boolean expectBinary,
GetRequestOptions options)
throws AtException {
if (atSign.equals(key.sharedBy())) {
return getSharedByMe(executor, key);
return getSharedByMe(executor, key, expectBinary);
} else {
return getSharedByOther(executor, key, options);
return getSharedByOther(executor, key, expectBinary, options);
}
}

Expand All @@ -47,10 +67,14 @@ public static String get(AtCommandExecutor executor, AtSign atSign, PublicKey ke
*
* @param executor The {@link AtCommandExecutor} to use.
* @param key The {@link PublicKey}
* @param expectBinary If true then metadata will be checked
* @return The associated value.
* @throws AtException If any of the commands fail or the key does not exist.
*/
public static String getSharedByMe(AtCommandExecutor executor, PublicKey key) throws AtException {
public static String getSharedByMe(AtCommandExecutor executor,
PublicKey key,
boolean expectBinary)
throws AtException {
try {

// send a local lookup command and decode the response
Expand All @@ -61,6 +85,10 @@ public static String getSharedByMe(AtCommandExecutor executor, PublicKey key) th
String llookupResponse = executor.sendSync(llookupCommand);
LookupResponse response = matchLookupResponse(throwExceptionIfError(llookupResponse));

if (expectBinary) {
checkTrue(Metadata.isBinary(response.metaData), "metadata.isBinary not set to true");
}

// set isCached in metadata
if (response.key.contains("cached:")) {
Metadata metadata = response.metaData.toBuilder().isCached(true).build();
Expand All @@ -82,10 +110,15 @@ public static String getSharedByMe(AtCommandExecutor executor, PublicKey key) th
*
* @param executor The {@link AtCommandExecutor} to use.
* @param key The {@link PublicKey}
* @param expectBinary If true then metadata will be checked
* @param options If set then can be used to bypass caches.
* @return The associated value.
* @throws AtException If any of the commands fail or the key does not exist.
*/
public static String getSharedByOther(AtCommandExecutor executor, PublicKey key, GetRequestOptions options)
public static String getSharedByOther(AtCommandExecutor executor,
PublicKey key,
boolean expectBinary,
GetRequestOptions options)
throws AtException {
try {

Expand All @@ -98,6 +131,10 @@ public static String getSharedByOther(AtCommandExecutor executor, PublicKey key,
String plookupResponse = executor.sendSync(plookupCommand);
LookupResponse response = matchLookupResponse(throwExceptionIfError(plookupResponse));

if (expectBinary) {
checkTrue(Metadata.isBinary(response.metaData), "isBinary not set to true");
}

// set isCached in metadata
if (response.key.contains("cached:")) {
Metadata metadata = response.metaData.toBuilder().isCached(true).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import static org.atsign.client.impl.commands.DataResponses.matchLookupResponse;
import static org.atsign.client.impl.commands.ErrorResponses.throwExceptionIfError;
import static org.atsign.client.impl.common.Preconditions.checkNotNull;
import static org.atsign.client.impl.common.Preconditions.checkTrue;
import static org.atsign.client.impl.util.EncryptionUtils.*;

import java.util.concurrent.ExecutionException;
Expand All @@ -30,6 +31,26 @@ public class SelfKeyCommands {
* @throws AtException If any of the commands fail or the key does not exist.
*/
public static String get(AtCommandExecutor executor, AtSign atSign, AtKeys keys, SelfKey key) throws AtException {
return get(executor, atSign, keys, key, false);
}

/**
* Get the String value associated with a self key. The value will be decrypted with the AtSign's
* Self Encryption Key.
*
* @param executor The {@link AtCommandExecutor} to use.
* @param atSign The AtSign that corresponds to the executor.
* @param key The {@link Keys.SelfKey}
* @param expectBinary If true then metadata will be checked
* @return The associated value.
* @throws AtException If any of the commands fail or the key does not exist.
*/
public static String get(AtCommandExecutor executor,
AtSign atSign,
AtKeys keys,
SelfKey key,
boolean expectBinary)
throws AtException {
checkAtSignCanGet(atSign, key);
try {

Expand All @@ -38,6 +59,10 @@ public static String get(AtCommandExecutor executor, AtSign atSign, AtKeys keys,
String llookupResponse = executor.sendSync(llookupCommand);
LookupResponse response = matchLookupResponse(throwExceptionIfError(llookupResponse));

if (expectBinary) {
checkTrue(Metadata.isBinary(response.metaData), "metadata.isBinary not set to true");
}

// decrypt with my self encrypt key
String selfEncryptionKey = keys.getSelfEncryptKey();
String iv = checkNotNull(response.metaData.ivNonce(), "ivNonce is null");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package org.atsign.client.impl.commands;

import static org.atsign.client.api.AtKeyNames.toSharedByMeKeyName;
import static org.atsign.client.impl.commands.CommandBuilders.LookupOperation.all;
import static org.atsign.client.impl.commands.DataResponses.*;
import static org.atsign.client.impl.commands.ErrorResponses.throwExceptionIfError;
import static org.atsign.client.impl.commands.CommandBuilders.LookupOperation.all;
import static org.atsign.client.impl.common.Preconditions.checkNotNull;
import static org.atsign.client.impl.common.Preconditions.checkTrue;
import static org.atsign.client.impl.util.EncryptionUtils.*;

import java.util.concurrent.ExecutionException;
Expand Down Expand Up @@ -34,13 +35,30 @@ public class SharedKeyCommands {
* @throws AtException If any of the commands fail or the key does not exist.
*/

public static String get(AtCommandExecutor executor, AtSign atSign, AtKeys keys, SharedKey key)
public static String get(AtCommandExecutor executor, AtSign atSign, AtKeys keys, SharedKey key) throws AtException {
return get(executor, atSign, keys, key, false);
}

/**
* Get the String value associated with a shared key. The value will be encrypted with a specific
* key for the sharedBy-sharedWith relationship.
*
* @param executor The {@link AtCommandExecutor} to use.
* @param atSign The AtSign that corresponds to the executor.
* @param key The {@link Keys.SharedKey}
* @param expectedBinary If true then lookup metadata will be checked
* @return The associated value.
* @throws AtException If any of the commands fail or the key does not exist.
*/

public static String get(AtCommandExecutor executor, AtSign atSign, AtKeys keys, SharedKey key,
boolean expectedBinary)
throws AtException {
checkAtSignCanGet(atSign, key);
if (key.sharedBy().equals(atSign)) {
return getSharedByMe(executor, keys, key);
return getSharedByMe(executor, keys, key, expectedBinary);
} else if (key.sharedWith().equals(atSign)) {
return getSharedByOther(executor, keys, key);
return getSharedByOther(executor, keys, key, expectedBinary);
} else {
throw new IllegalArgumentException("the client atsign is neither the sharedBy or sharedWith");
}
Expand Down Expand Up @@ -85,13 +103,18 @@ public static void put(AtCommandExecutor executor, AtSign atSign, AtKeys keys, S
}
}

private static String getSharedByMe(AtCommandExecutor executor, AtKeys keys, SharedKey key) throws AtException {
private static String getSharedByMe(AtCommandExecutor executor, AtKeys keys, SharedKey key, boolean expectBinary)
throws AtException {
try {

// send local lookup command and decode
String llookupCommand = CommandBuilders.llookupCommandBuilder().key(key).operation(all).build();
LookupResponse llookupResponse = matchLookupResponse(throwExceptionIfError(executor.sendSync(llookupCommand)));

if (expectBinary) {
checkTrue(Metadata.isBinary(llookupResponse.metaData), "metadata.isBinary not set to true");
}

// get my encrypt key for sharedBy sharedWith
String aesKey = checkNotNull(getEncryptKeySharedByMe(executor, keys, key), key + " not found");

Expand All @@ -103,13 +126,18 @@ private static String getSharedByMe(AtCommandExecutor executor, AtKeys keys, Sha
}
}

private static String getSharedByOther(AtCommandExecutor executor, AtKeys keys, SharedKey key) throws AtException {
private static String getSharedByOther(AtCommandExecutor executor, AtKeys keys, SharedKey key, boolean expectBinary)
throws AtException {
try {

// send lookup command and decode
String lookupCommand = CommandBuilders.lookupCommandBuilder().key(key).operation(all).build();
LookupResponse lookupResponse = matchLookupResponse(throwExceptionIfError(executor.sendSync(lookupCommand)));

if (expectBinary) {
checkTrue(Metadata.isBinary(lookupResponse.metaData), "isBinary not set to true");
}

// get my encrypt key for sharedBy sharedWith
String shareEncryptionKey = getEncryptKeySharedByOther(executor, keys, key);

Expand Down
Loading
Loading