[#1] Define SDK main functional #1
28 changed files with 177 additions and 203 deletions
18
README.md
18
README.md
|
@ -21,18 +21,18 @@ neo-go wallet export -w <path_to_your_wallet> -d <address_from_p1>
|
|||
### Container
|
||||
|
||||
```java
|
||||
import info.FrostFS.sdk.enums.BasicAcl;
|
||||
import info.FrostFS.sdk.dto.container.Container;
|
||||
import info.FrostFS.sdk.dto.netmap.PlacementPolicy;
|
||||
import info.FrostFS.sdk.dto.netmap.Replica;
|
||||
import info.FrostFS.sdk.enums.BasicAcl;
|
||||
import info.FrostFS.sdk.jdo.ClientSettings;
|
||||
import info.FrostFS.sdk.services.FrostFSClient;
|
||||
|
||||
public class ContainerExample {
|
||||
|
||||
public void example() {
|
||||
Client client = new Client( < your_key >);
|
||||
GrpcClient grpcClient = new GrpcClient( < your_host >);
|
||||
FrostFSClient frostFSClient = new FrostFSClient(grpcClient, client);
|
||||
ClientSettings clientSettings = new ClientSettings(<your_key>, <your_host>);
|
||||
FrostFSClient frostFSClient = new FrostFSClient(clientSettings);
|
||||
|
||||
// Create container
|
||||
var placementPolicy = new PlacementPolicy(true, new Replica[]{new Replica(1)});
|
||||
|
@ -58,6 +58,7 @@ import info.FrostFS.sdk.dto.container.ContainerId;
|
|||
import info.FrostFS.sdk.dto.object.ObjectAttribute;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFilter;
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
import info.FrostFS.sdk.jdo.PutObjectParameters;
|
||||
import info.FrostFS.sdk.services.FrostFSClient;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
@ -66,9 +67,8 @@ import java.io.IOException;
|
|||
public class ObjectExample {
|
||||
|
||||
public void example() {
|
||||
Client client = new Client( < your_key >);
|
||||
GrpcClient grpcClient = new GrpcClient( < your_host >);
|
||||
FrostFSClient frostFSClient = new FrostFSClient(grpcClient, client);
|
||||
ClientSettings clientSettings = new ClientSettings(<your_key>, <your_host>);
|
||||
FrostFSClient frostFSClient = new FrostFSClient(clientSettings);
|
||||
|
||||
// Put object
|
||||
info.FrostFS.sdk.dto.object.ObjectId objectId;
|
||||
|
@ -76,7 +76,9 @@ public class ObjectExample {
|
|||
var cat = new ObjectHeader(
|
||||
containerId, ObjectType.REGULAR, new ObjectAttribute[]{new ObjectAttribute("Filename", "cat.jpg")}
|
||||
);
|
||||
objectId = frostFSClient.putObject(cat, fis);
|
||||
|
||||
var params = new PutObjectParameters(cat, fis);
|
||||
objectId = frostFSClient.putObject(params);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
package info.FrostFS.sdk;
|
||||
|
||||
import info.FrostFS.sdk.dto.container.Container;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.enums.BasicAcl;
|
||||
import info.FrostFS.sdk.enums.ObjectType;
|
||||
import info.FrostFS.sdk.dto.netmap.PlacementPolicy;
|
||||
import info.FrostFS.sdk.dto.netmap.Replica;
|
||||
import info.FrostFS.sdk.dto.object.ObjectAttribute;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFrostFS;
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
import info.FrostFS.sdk.dto.object.ObjectId;
|
||||
import info.FrostFS.sdk.services.FrostFSClient;
|
||||
import info.FrostFS.sdk.tools.ClientSettings;
|
||||
import info.FrostFS.sdk.tools.PutObjectParameters;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) throws Exception {
|
||||
ClientSettings clientSettings = new ClientSettings("KwHDAJ66o8FoLBjVbjP2sWBmgBMGjt7Vv4boA7xQrBoAYBE397Aq", "http://localhost:8080");
|
||||
FrostFSClient frostFSClient = new FrostFSClient(clientSettings);
|
||||
/*
|
||||
var res2 = frostFSClient.searchObjectsAsync(new ContainerId("EQGx2QeYHJb53uRwYGzcQaW191sZpdNrjutk6veUSV2R"));
|
||||
*/
|
||||
var placementPolicy = new PlacementPolicy(true, new Replica[]{new Replica(1)});
|
||||
var containerId = frostFSClient.createContainer(new Container(BasicAcl.PUBLIC_RW, placementPolicy));
|
||||
Thread.sleep(1000);
|
||||
|
||||
FileInputStream file = null;
|
||||
try {
|
||||
file = new FileInputStream("/home/ori/Desktop/cat.jpg");
|
||||
var cat = new ObjectHeader(containerId, ObjectType.REGULAR, Collections.singletonList(new ObjectAttribute("Filename", "cat3.jpg")));
|
||||
|
||||
var params = new PutObjectParameters(cat, file, false, 1024);
|
||||
var tty = frostFSClient.putObject(params);
|
||||
|
||||
System.out.println(1);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
|
||||
var res = frostFSClient.searchObjects(containerId);
|
||||
|
||||
ObjectFrostFS res3 = frostFSClient
|
||||
.getObject(new ContainerId("EQGx2QeYHJb53uRwYGzcQaW191sZpdNrjutk6veUSV2R"), new ObjectId("85orCLKSu3X1jGiTFmwmTUsBU88RBARNwuRwrEy5pyww"));
|
||||
|
||||
|
||||
var ttttt = frostFSClient.getNetworkSettings();
|
||||
Container container2 = frostFSClient.getContainer(new ContainerId("EQGx2QeYHJb53uRwYGzcQaW191sZpdNrjutk6veUSV2R"));
|
||||
|
||||
|
||||
|
||||
|
||||
Container container = frostFSClient.getContainer(containerId);
|
||||
List<ContainerId> containerIds = frostFSClient.listContainers();
|
||||
/*
|
||||
frostFSClient.deleteContainerAsync(containerId);
|
||||
*/
|
||||
containerIds = frostFSClient.listContainers();
|
||||
System.out.println();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.FrostFS.sdk.constants;
|
||||
|
||||
public class CryptoConst {
|
||||
public static final String SIGNATURE_ALGORITHM = "NONEwithECDSAinP1363Format";
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
package info.FrostFS.sdk.jdo;
|
||||
|
||||
import info.FrostFS.sdk.dto.OwnerId;
|
||||
import info.FrostFS.sdk.dto.Version;
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
package info.FrostFS.sdk.jdo;
|
||||
|
||||
import io.grpc.ChannelCredentials;
|
||||
import org.apache.commons.lang3.StringUtils;
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
package info.FrostFS.sdk.jdo;
|
||||
|
||||
import java.security.PrivateKey;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
package info.FrostFS.sdk.jdo;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
package info.FrostFS.sdk.jdo;
|
||||
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
package info.FrostFS.sdk.services;
|
||||
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
|
||||
public class ContextAccessor {
|
||||
private final ClientEnvironment context;
|
||||
|
|
|
@ -1,29 +1,32 @@
|
|||
package info.FrostFS.sdk.services;
|
||||
|
||||
import frostFS.session.Types;
|
||||
import info.FrostFS.sdk.tools.ClientSettings;
|
||||
import info.FrostFS.sdk.tools.PutObjectParameters;
|
||||
import info.FrostFS.sdk.dto.container.Container;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.dto.SessionToken;
|
||||
import info.FrostFS.sdk.dto.Version;
|
||||
import info.FrostFS.sdk.dto.container.Container;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.dto.netmap.NetmapSnapshot;
|
||||
import info.FrostFS.sdk.dto.netmap.NodeInfo;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFilter;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFrostFS;
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
import info.FrostFS.sdk.dto.object.ObjectId;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.jdo.ClientSettings;
|
||||
import info.FrostFS.sdk.jdo.NetworkSettings;
|
||||
import info.FrostFS.sdk.jdo.PutObjectParameters;
|
||||
import info.FrostFS.sdk.services.impl.*;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import info.FrostFS.sdk.tools.NetworkSettings;
|
||||
import io.grpc.Channel;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static info.FrostFS.sdk.GrpcClient.initGrpcChannel;
|
||||
import static info.FrostFS.sdk.tools.GrpcClient.initGrpcChannel;
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClient, SessionClient, ToolsClient {
|
||||
private static final String ERROR_CLIENT_OPTIONS_INIT = "Options must be initialized.";
|
||||
private static final String ERROR_VERSION_SUPPORT_TEMPLATE = "FrostFS %s is not supported.";
|
||||
|
||||
private final ContainerService containerService;
|
||||
private final NetmapService netmapService;
|
||||
private final ObjectService objectService;
|
||||
|
@ -32,7 +35,7 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien
|
|||
|
||||
public FrostFSClient(ClientSettings clientSettings) {
|
||||
if (isNull(clientSettings)) {
|
||||
throw new IllegalArgumentException("Options must be initialized");
|
||||
throw new IllegalArgumentException(ERROR_CLIENT_OPTIONS_INIT);
|
||||
}
|
||||
|
||||
clientSettings.validate();
|
||||
|
@ -53,9 +56,9 @@ public class FrostFSClient implements ContainerClient, ObjectClient, NetmapClien
|
|||
private void checkFrostFsVersionSupport(Version version) {
|
||||
var localNodeInfo = netmapService.getLocalNodeInfo();
|
||||
if (!localNodeInfo.getVersion().isSupported(version)) {
|
||||
var msg = String.format("FrostFS %s is not supported.", localNodeInfo.getVersion());
|
||||
System.out.println(msg);
|
||||
throw new IllegalArgumentException(msg);
|
||||
throw new IllegalArgumentException(
|
||||
String.format(ERROR_VERSION_SUPPORT_TEMPLATE, localNodeInfo.getVersion())
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ package info.FrostFS.sdk.services;
|
|||
|
||||
import info.FrostFS.sdk.dto.netmap.NetmapSnapshot;
|
||||
import info.FrostFS.sdk.dto.netmap.NodeInfo;
|
||||
import info.FrostFS.sdk.tools.NetworkSettings;
|
||||
import info.FrostFS.sdk.jdo.NetworkSettings;
|
||||
|
||||
public interface NetmapClient {
|
||||
NetmapSnapshot getNetmapSnapshot();
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
package info.FrostFS.sdk.services;
|
||||
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.tools.PutObjectParameters;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFilter;
|
||||
import info.FrostFS.sdk.dto.object.ObjectFrostFS;
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
import info.FrostFS.sdk.dto.object.ObjectId;
|
||||
import info.FrostFS.sdk.jdo.PutObjectParameters;
|
||||
|
||||
public interface ObjectClient {
|
||||
ObjectHeader getObjectHead(ContainerId containerId, ObjectId objectId);
|
||||
|
|
|
@ -2,23 +2,23 @@ package info.FrostFS.sdk.services.impl;
|
|||
|
||||
import frostFS.container.ContainerServiceGrpc;
|
||||
import frostFS.container.Service;
|
||||
import info.FrostFS.sdk.Verifier;
|
||||
import info.FrostFS.sdk.dto.container.Container;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.mappers.container.ContainerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.container.ContainerMapper;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.mappers.OwnerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.VersionMapper;
|
||||
import info.FrostFS.sdk.mappers.container.ContainerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.container.ContainerMapper;
|
||||
import info.FrostFS.sdk.services.ContainerClient;
|
||||
import info.FrostFS.sdk.services.ContextAccessor;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import info.FrostFS.sdk.tools.Verifier;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static info.FrostFS.sdk.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.RequestSigner.sign;
|
||||
import static info.FrostFS.sdk.RequestSigner.signRFC6979;
|
||||
import static info.FrostFS.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.sign;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.signRFC6979;
|
||||
|
||||
public class ContainerService extends ContextAccessor implements ContainerClient {
|
||||
private final ContainerServiceGrpc.ContainerServiceBlockingStub serviceBlockingStub;
|
||||
|
|
|
@ -3,20 +3,20 @@ package info.FrostFS.sdk.services.impl;
|
|||
import frostFS.netmap.NetmapServiceGrpc;
|
||||
import frostFS.netmap.Service;
|
||||
import frostFS.netmap.Types;
|
||||
import info.FrostFS.sdk.Verifier;
|
||||
import info.FrostFS.sdk.dto.netmap.NetmapSnapshot;
|
||||
import info.FrostFS.sdk.dto.netmap.NodeInfo;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.jdo.NetworkSettings;
|
||||
import info.FrostFS.sdk.mappers.netmap.NetmapSnapshotMapper;
|
||||
import info.FrostFS.sdk.mappers.netmap.NodeInfoMapper;
|
||||
import info.FrostFS.sdk.services.ContextAccessor;
|
||||
import info.FrostFS.sdk.services.NetmapClient;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import info.FrostFS.sdk.tools.NetworkSettings;
|
||||
import info.FrostFS.sdk.tools.Verifier;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static info.FrostFS.sdk.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.RequestSigner.sign;
|
||||
import static info.FrostFS.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.sign;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class NetmapService extends ContextAccessor implements NetmapClient {
|
||||
|
|
|
@ -2,11 +2,14 @@ package info.FrostFS.sdk.services.impl;
|
|||
|
||||
import frostFS.object.Service;
|
||||
import frostFS.object.Types;
|
||||
import info.FrostFS.sdk.Verifier;
|
||||
import info.FrostFS.sdk.tools.Verifier;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class ObjectReader {
|
||||
public static final String ERROR_UNEXPECTED_STREAM = "unexpected end of stream";
|
||||
public static final String ERROR_UNEXPECTED_MESSAGE_TYPE = "unexpected message type";
|
||||
|
||||
public Iterator<Service.GetResponse> call;
|
||||
|
||||
public ObjectReader(Iterator<Service.GetResponse> call) {
|
||||
|
@ -15,14 +18,14 @@ public class ObjectReader {
|
|||
|
||||
public Types.Object readHeader() {
|
||||
if (!call.hasNext()) {
|
||||
throw new IllegalArgumentException("unexpected end of stream");
|
||||
throw new IllegalArgumentException(ERROR_UNEXPECTED_STREAM);
|
||||
}
|
||||
|
||||
var response = call.next();
|
||||
Verifier.checkResponse(response);
|
||||
|
||||
if (response.getBody().getObjectPartCase().getNumber() != Service.GetResponse.Body.INIT_FIELD_NUMBER) {
|
||||
throw new IllegalArgumentException("unexpected message type");
|
||||
throw new IllegalArgumentException(ERROR_UNEXPECTED_MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
return Types.Object.newBuilder()
|
||||
|
@ -40,7 +43,7 @@ public class ObjectReader {
|
|||
Verifier.checkResponse(response);
|
||||
|
||||
if (response.getBody().getObjectPartCase().getNumber() != Service.GetResponse.Body.CHUNK_FIELD_NUMBER) {
|
||||
throw new IllegalArgumentException("unexpected message type");
|
||||
throw new IllegalArgumentException(ERROR_UNEXPECTED_MESSAGE_TYPE);
|
||||
}
|
||||
|
||||
return response.getBody().getChunk().toByteArray();
|
||||
|
|
|
@ -5,21 +5,22 @@ import com.google.protobuf.ByteString;
|
|||
import frostFS.object.ObjectServiceGrpc;
|
||||
import frostFS.object.Service;
|
||||
import frostFS.refs.Types;
|
||||
import info.FrostFS.sdk.Verifier;
|
||||
import info.FrostFS.sdk.constants.AppConst;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.dto.Split;
|
||||
import info.FrostFS.sdk.dto.container.ContainerId;
|
||||
import info.FrostFS.sdk.dto.object.*;
|
||||
import info.FrostFS.sdk.mappers.*;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.jdo.PutObjectParameters;
|
||||
import info.FrostFS.sdk.mappers.OwnerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.VersionMapper;
|
||||
import info.FrostFS.sdk.mappers.container.ContainerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectFilterMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectFrostFSMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectHeaderMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectIdMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectFrostFSMapper;
|
||||
import info.FrostFS.sdk.services.ContextAccessor;
|
||||
import info.FrostFS.sdk.services.ObjectClient;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import info.FrostFS.sdk.tools.PutObjectParameters;
|
||||
import info.FrostFS.sdk.tools.Verifier;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
|
@ -29,12 +30,14 @@ import java.util.Arrays;
|
|||
import java.util.List;
|
||||
|
||||
import static info.FrostFS.sdk.Helper.getSha256;
|
||||
import static info.FrostFS.sdk.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.RequestConstructor.addObjectSessionToken;
|
||||
import static info.FrostFS.sdk.RequestSigner.sign;
|
||||
import static info.FrostFS.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.tools.RequestConstructor.addObjectSessionToken;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.sign;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class ObjectService extends ContextAccessor implements ObjectClient {
|
||||
private static final String ERROR_PAYLOAD = "PayloadLength must be specified";
|
||||
|
||||
private final ObjectServiceGrpc.ObjectServiceBlockingStub objectServiceBlockingClient;
|
||||
private final ObjectServiceGrpc.ObjectServiceStub objectServiceClient;
|
||||
private final ObjectTools objectTools;
|
||||
|
@ -257,7 +260,7 @@ public class ObjectService extends ContextAccessor implements ObjectClient {
|
|||
var objectSize = (int) Math.min(payloadSize, networkSettings.getMaxObjectSize());
|
||||
var fullLength = header.getPayloadLength() == 0 ? payloadSize : header.getPayloadLength();
|
||||
if (fullLength == 0) {
|
||||
throw new IllegalArgumentException("Payload stream must be able to seek or PayloadLength must be specified");
|
||||
throw new IllegalArgumentException(ERROR_PAYLOAD);
|
||||
}
|
||||
|
||||
var buffer = new byte[objectSize];
|
||||
|
|
|
@ -5,17 +5,17 @@ import frostFS.object.Types;
|
|||
import info.FrostFS.sdk.dto.object.ObjectFrostFS;
|
||||
import info.FrostFS.sdk.dto.object.ObjectHeader;
|
||||
import info.FrostFS.sdk.dto.object.ObjectId;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectHeaderMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectIdMapper;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.mappers.OwnerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.VersionMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectHeaderMapper;
|
||||
import info.FrostFS.sdk.mappers.object.ObjectIdMapper;
|
||||
import info.FrostFS.sdk.services.ContextAccessor;
|
||||
import info.FrostFS.sdk.services.ToolsClient;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
|
||||
import static info.FrostFS.sdk.Helper.getSha256;
|
||||
import static info.FrostFS.sdk.RequestSigner.signData;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.signData;
|
||||
import static java.util.Objects.nonNull;
|
||||
|
||||
public class ObjectTools extends ContextAccessor implements ToolsClient {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.FrostFS.sdk.services.impl;
|
||||
|
||||
import frostFS.object.Service;
|
||||
import info.FrostFS.sdk.Verifier;
|
||||
import info.FrostFS.sdk.tools.Verifier;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
|
|
@ -4,14 +4,14 @@ import frostFS.session.Service;
|
|||
import frostFS.session.SessionServiceGrpc;
|
||||
import frostFS.session.Types;
|
||||
import info.FrostFS.sdk.dto.SessionToken;
|
||||
import info.FrostFS.sdk.jdo.ClientEnvironment;
|
||||
import info.FrostFS.sdk.mappers.OwnerIdMapper;
|
||||
import info.FrostFS.sdk.mappers.SessionMapper;
|
||||
import info.FrostFS.sdk.services.ContextAccessor;
|
||||
import info.FrostFS.sdk.services.SessionClient;
|
||||
import info.FrostFS.sdk.tools.ClientEnvironment;
|
||||
|
||||
import static info.FrostFS.sdk.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.RequestSigner.sign;
|
||||
import static info.FrostFS.sdk.tools.RequestConstructor.addMetaHeader;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.sign;
|
||||
|
||||
public class SessionService extends ContextAccessor implements SessionClient {
|
||||
private final SessionServiceGrpc.SessionServiceBlockingStub serviceBlockingStub;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package info.FrostFS.sdk;
|
||||
package info.FrostFS.sdk.tools;
|
||||
|
||||
import io.grpc.Channel;
|
||||
import io.grpc.ChannelCredentials;
|
||||
|
@ -10,6 +10,7 @@ import java.net.URISyntaxException;
|
|||
import static java.util.Objects.isNull;
|
||||
|
||||
public class GrpcClient {
|
||||
private static final String ERROR_INVALID_HOST_TEMPLATE = "Host %s has invalid format. Error: %s";
|
||||
|
||||
public static Channel initGrpcChannel(String host, ChannelCredentials creds) {
|
||||
try {
|
||||
|
@ -19,8 +20,7 @@ public class GrpcClient {
|
|||
|
||||
return channelBuilder.usePlaintext().build();
|
||||
} catch (URISyntaxException exp) {
|
||||
var message = String.format("Host %s has invalid format. Error: %s", host, exp.getMessage());
|
||||
throw new IllegalArgumentException(message);
|
||||
throw new IllegalArgumentException(String.format(ERROR_INVALID_HOST_TEMPLATE, host, exp.getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package info.FrostFS.sdk.tools;
|
||||
|
||||
import com.google.protobuf.Message;
|
||||
import com.google.protobuf.MessageOrBuilder;
|
||||
|
||||
public class MessageHelper {
|
||||
|
||||
public static Message getField(MessageOrBuilder messageOrBuilder, String fieldName) {
|
||||
return (Message) messageOrBuilder.getField(messageOrBuilder.getDescriptorForType().findFieldByName(fieldName));
|
||||
}
|
||||
|
||||
public static void setField(Message.Builder builder, String fieldName, Object value) {
|
||||
builder.setField(builder.getDescriptorForType().findFieldByName(fieldName), value);
|
||||
}
|
||||
}
|
|
@ -1,36 +1,37 @@
|
|||
package info.FrostFS.sdk;
|
||||
package info.FrostFS.sdk.tools;
|
||||
|
||||
import com.google.protobuf.AbstractMessage;
|
||||
import com.google.protobuf.Message;
|
||||
import frostFS.session.Types;
|
||||
import info.FrostFS.sdk.dto.MetaHeader;
|
||||
import info.FrostFS.sdk.jdo.ECDsa;
|
||||
import info.FrostFS.sdk.mappers.MetaHeaderMapper;
|
||||
import info.FrostFS.sdk.tools.ECDsa;
|
||||
|
||||
import static info.FrostFS.sdk.RequestSigner.signMessagePart;
|
||||
import static info.FrostFS.sdk.constants.FieldConst.META_HEADER_FIELD_NAME;
|
||||
import static info.FrostFS.sdk.tools.MessageHelper.getField;
|
||||
import static info.FrostFS.sdk.tools.MessageHelper.setField;
|
||||
import static info.FrostFS.sdk.tools.RequestSigner.signMessagePart;
|
||||
import static java.util.Objects.isNull;
|
||||
|
||||
public class RequestConstructor {
|
||||
|
||||
public static void addMetaHeader(AbstractMessage.Builder request) {
|
||||
public static void addMetaHeader(Message.Builder request) {
|
||||
addMetaHeader(request, null);
|
||||
}
|
||||
|
||||
public static void addMetaHeader(AbstractMessage.Builder request, Types.RequestMetaHeader metaHeader) {
|
||||
public static void addMetaHeader(Message.Builder request, Types.RequestMetaHeader metaHeader) {
|
||||
if (isNull(metaHeader) || metaHeader.getSerializedSize() == 0) {
|
||||
metaHeader = MetaHeaderMapper.toGrpcMessage(MetaHeader.getDefault());
|
||||
var field = request.getDescriptorForType().findFieldByName("meta_header");
|
||||
request.setField(field, metaHeader);
|
||||
setField(request, META_HEADER_FIELD_NAME, metaHeader);
|
||||
}
|
||||
}
|
||||
|
||||
public static void addObjectSessionToken(AbstractMessage.Builder request,
|
||||
public static void addObjectSessionToken(Message.Builder request,
|
||||
Types.SessionToken sessionToken,
|
||||
frostFS.refs.Types.ContainerID cid,
|
||||
frostFS.refs.Types.ObjectID oid,
|
||||
Types.ObjectSessionContext.Verb verb,
|
||||
ECDsa key) {
|
||||
var headerField = request.getDescriptorForType().findFieldByName("meta_header");
|
||||
var header = (Types.RequestMetaHeader) request.getField(headerField);
|
||||
var header = (Types.RequestMetaHeader) getField(request, META_HEADER_FIELD_NAME);
|
||||
if (header.getSessionToken().getSerializedSize() > 0) {
|
||||
return;
|
||||
}
|
||||
|
@ -46,6 +47,6 @@ public class RequestConstructor {
|
|||
.setBody(body)
|
||||
.build();
|
||||
|
||||
request.setField(headerField, header.toBuilder().setSessionToken(sessionToken).build());
|
||||
setField(request, META_HEADER_FIELD_NAME, header.toBuilder().setSessionToken(sessionToken).build());
|
||||
}
|
||||
}
|
|
@ -1,9 +1,9 @@
|
|||
package info.FrostFS.sdk;
|
||||
package info.FrostFS.sdk.tools;
|
||||
|
||||
import com.google.protobuf.AbstractMessage;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import frostFS.session.Types;
|
||||
import info.FrostFS.sdk.tools.ECDsa;
|
||||
import info.FrostFS.sdk.jdo.ECDsa;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||
import org.bouncycastle.asn1.sec.SECObjectIdentifiers;
|
||||
|
@ -15,17 +15,22 @@ import org.bouncycastle.crypto.signers.HMacDSAKCalculator;
|
|||
import java.math.BigInteger;
|
||||
import java.security.Signature;
|
||||
|
||||
import static info.FrostFS.sdk.constants.CryptoConst.SIGNATURE_ALGORITHM;
|
||||
import static info.FrostFS.sdk.constants.FieldConst.*;
|
||||
import static info.FrostFS.sdk.tools.MessageHelper.getField;
|
||||
import static info.FrostFS.sdk.tools.MessageHelper.setField;
|
||||
import static org.bouncycastle.crypto.util.DigestFactory.createSHA256;
|
||||
import static org.bouncycastle.util.BigIntegers.asUnsignedByteArray;
|
||||
|
||||
public class RequestSigner {
|
||||
public static final String ERROR_UNSUPPORTED_TYPE_TEMPLATE = "Unsupported message type: %s";
|
||||
public static final int RFC6979_SIGNATURE_SIZE = 64;
|
||||
|
||||
public static byte[] signData(ECDsa key, byte[] data) {
|
||||
var hash = new byte[65];
|
||||
hash[0] = 0x04;
|
||||
try {
|
||||
Signature signature = Signature.getInstance("NONEwithECDSAinP1363Format");
|
||||
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
signature.initSign(key.getPrivateKey());
|
||||
signature.update(DigestUtils.sha512(data));
|
||||
byte[] sig = signature.sign();
|
||||
|
@ -62,7 +67,7 @@ public class RequestSigner {
|
|||
return signature;
|
||||
}
|
||||
|
||||
public static frostFS.refs.Types.SignatureRFC6979 signRFC6979(ECDsa key, AbstractMessage message) {
|
||||
public static frostFS.refs.Types.SignatureRFC6979 signRFC6979(ECDsa key, Message message) {
|
||||
return frostFS.refs.Types.SignatureRFC6979.newBuilder()
|
||||
.setKey(ByteString.copyFrom(key.getPublicKeyByte()))
|
||||
.setSign(ByteString.copyFrom(signRFC6979(key, message.toByteArray())))
|
||||
|
@ -76,7 +81,7 @@ public class RequestSigner {
|
|||
.build();
|
||||
}
|
||||
|
||||
public static frostFS.refs.Types.Signature signMessagePart(ECDsa key, AbstractMessage data) {
|
||||
public static frostFS.refs.Types.Signature signMessagePart(ECDsa key, Message data) {
|
||||
var data2Sign = data.getSerializedSize() == 0 ? new byte[]{} : data.toByteArray();
|
||||
return frostFS.refs.Types.Signature.newBuilder()
|
||||
.setKey(ByteString.copyFrom(key.getPublicKeyByte()))
|
||||
|
@ -84,39 +89,32 @@ public class RequestSigner {
|
|||
.build();
|
||||
}
|
||||
|
||||
public static void sign(AbstractMessage.Builder request, ECDsa key) {
|
||||
var meta = (AbstractMessage) request.getField(request.getDescriptorForType().findFieldByName("meta_header"));
|
||||
var body = (AbstractMessage) request.getField(request.getDescriptorForType().findFieldByName("body"));
|
||||
var verify = (AbstractMessage) request.getField(request.getDescriptorForType().findFieldByName("verify_header"));
|
||||
public static void sign(Message.Builder request, ECDsa key) {
|
||||
var meta = getField(request, META_HEADER_FIELD_NAME);
|
||||
var body = getField(request, BODY_FIELD_NAME);
|
||||
var verify = getField(request, VERIFY_HEADER_FIELD_NAME);
|
||||
var verifyOrigin = getField(verify, ORIGIN_FIELD_NAME);
|
||||
|
||||
AbstractMessage.Builder verifyBuilder;
|
||||
Message.Builder verifyBuilder;
|
||||
if (verify instanceof Types.RequestVerificationHeader) {
|
||||
verifyBuilder = Types.RequestVerificationHeader.newBuilder();
|
||||
} else if (verify instanceof Types.ResponseVerificationHeader) {
|
||||
verifyBuilder = Types.ResponseVerificationHeader.newBuilder();
|
||||
} else {
|
||||
throw new IllegalArgumentException("Unsopported message type");
|
||||
}
|
||||
|
||||
var verifyOrigin = (AbstractMessage) verify.getField(verify.getDescriptorForType().findFieldByName("origin"));
|
||||
if (verifyOrigin.getSerializedSize() == 0) {
|
||||
verifyBuilder.setField(
|
||||
verifyBuilder.getDescriptorForType().findFieldByName("body_signature"),
|
||||
signMessagePart(key, body)
|
||||
throw new IllegalArgumentException(
|
||||
String.format(ERROR_UNSUPPORTED_TYPE_TEMPLATE, verify.getClass().getName())
|
||||
);
|
||||
} else {
|
||||
verifyBuilder.setField(verifyBuilder.getDescriptorForType().findFieldByName("origin"), verifyOrigin);
|
||||
}
|
||||
|
||||
verifyBuilder.setField(
|
||||
verifyBuilder.getDescriptorForType().findFieldByName("meta_signature"),
|
||||
signMessagePart(key, meta)
|
||||
);
|
||||
verifyBuilder.setField(
|
||||
verifyBuilder.getDescriptorForType().findFieldByName("origin_signature"),
|
||||
signMessagePart(key, verifyOrigin)
|
||||
);
|
||||
if (verifyOrigin.getSerializedSize() == 0) {
|
||||
setField(verifyBuilder, BODY_SIGNATURE_FIELD_NAME, signMessagePart(key, body));
|
||||
} else {
|
||||
setField(verifyBuilder, ORIGIN_FIELD_NAME, verifyOrigin);
|
||||
}
|
||||
|
||||
request.setField(request.getDescriptorForType().findFieldByName("verify_header"), verifyBuilder.build());
|
||||
setField(verifyBuilder, META_SIGNATURE_FIELD_NAME, signMessagePart(key, meta));
|
||||
setField(verifyBuilder, ORIGIN_SIGNATURE_FIELD_NAME, signMessagePart(key, verifyOrigin));
|
||||
setField(request, VERIFY_HEADER_FIELD_NAME, verifyBuilder.build());
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,7 @@
|
|||
package info.FrostFS.sdk;
|
||||
package info.FrostFS.sdk.tools;
|
||||
|
||||
import com.google.protobuf.AbstractMessage;
|
||||
import frostFS.refs.Types;
|
||||
import com.google.protobuf.Message;
|
||||
import frostFS.session.Types;
|
||||
import info.FrostFS.sdk.mappers.StatusMapper;
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.bouncycastle.asn1.sec.SECNamedCurves;
|
||||
|
@ -17,17 +17,20 @@ import java.security.Signature;
|
|||
import java.util.Arrays;
|
||||
|
||||
import static info.FrostFS.sdk.KeyExtension.getPublicKeyFromBytes;
|
||||
import static info.FrostFS.sdk.constants.CryptoConst.SIGNATURE_ALGORITHM;
|
||||
import static info.FrostFS.sdk.constants.FieldConst.*;
|
||||
import static info.FrostFS.sdk.tools.MessageHelper.getField;
|
||||
import static java.util.Objects.isNull;
|
||||
import static org.bouncycastle.crypto.util.DigestFactory.createSHA256;
|
||||
import static org.bouncycastle.util.BigIntegers.fromUnsignedByteArray;
|
||||
|
||||
public class Verifier {
|
||||
public static final String ERROR_WRONG_SIG_SIZE_TEMPLATE = "Wrong signature size. Expected length=%s, actual=%s";
|
||||
public static final String ERROR_INVALID_RESPONSE = "Invalid response";
|
||||
public static final int RFC6979_SIG_SIZE = 64;
|
||||
|
||||
public static boolean verifyRFC6979(Types.SignatureRFC6979 signature, AbstractMessage message) {
|
||||
return verifyRFC6979(
|
||||
signature.getKey().toByteArray(), message.toByteArray(), signature.getSign().toByteArray()
|
||||
);
|
||||
public static boolean verifyRFC6979(frostFS.refs.Types.SignatureRFC6979 signature, Message data) {
|
||||
return verifyRFC6979(signature.getKey().toByteArray(), data.toByteArray(), signature.getSign().toByteArray());
|
||||
}
|
||||
|
||||
public static boolean verifyRFC6979(byte[] publicKey, byte[] data, byte[] sig) {
|
||||
|
@ -49,8 +52,7 @@ public class Verifier {
|
|||
private static BigInteger[] decodeSignature(byte[] sig) {
|
||||
if (sig.length != RFC6979_SIG_SIZE) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format("Wrong signature size. Expected length=%s, actual=%s",
|
||||
RFC6979_SIG_SIZE, sig.length)
|
||||
String.format(ERROR_WRONG_SIG_SIZE_TEMPLATE, RFC6979_SIG_SIZE, sig.length)
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -61,42 +63,40 @@ public class Verifier {
|
|||
return rs;
|
||||
}
|
||||
|
||||
public static void checkResponse(AbstractMessage response) {
|
||||
public static void checkResponse(Message response) {
|
||||
if (!verify(response)) {
|
||||
throw new IllegalArgumentException("Invalid response");
|
||||
throw new IllegalArgumentException(ERROR_INVALID_RESPONSE);
|
||||
}
|
||||
var metaHeader = (frostFS.session.Types.ResponseMetaHeader) response
|
||||
.getField(response.getDescriptorForType().findFieldByName("meta_header"));
|
||||
|
||||
var metaHeader = (Types.ResponseMetaHeader) getField(response, META_HEADER_FIELD_NAME);
|
||||
var status = StatusMapper.toModel(metaHeader.getStatus());
|
||||
if (!status.isSuccess()) {
|
||||
throw new IllegalArgumentException(status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean verify(AbstractMessage message) {
|
||||
var body = (AbstractMessage) message.getField(message.getDescriptorForType().findFieldByName("body"));
|
||||
var metaHeader = (frostFS.session.Types.ResponseMetaHeader)
|
||||
message.getField(message.getDescriptorForType().findFieldByName("meta_header"));
|
||||
var verifyHeader = (frostFS.session.Types.ResponseVerificationHeader)
|
||||
message.getField(message.getDescriptorForType().findFieldByName("verify_header"));
|
||||
public static boolean verify(Message response) {
|
||||
var body = getField(response, BODY_FIELD_NAME);
|
||||
var metaHeader = (Types.ResponseMetaHeader) getField(response, META_HEADER_FIELD_NAME);
|
||||
var verifyHeader = (Types.ResponseVerificationHeader) getField(response, VERIFY_HEADER_FIELD_NAME);
|
||||
|
||||
return verifyMatryoshkaLevel(body, metaHeader, verifyHeader);
|
||||
}
|
||||
|
||||
public static boolean verifyMatryoshkaLevel(AbstractMessage body,
|
||||
public static boolean verifyMatryoshkaLevel(Message data,
|
||||
frostFS.session.Types.ResponseMetaHeader meta,
|
||||
frostFS.session.Types.ResponseVerificationHeader verification) {
|
||||
if (!verifyMessagePart(verification.getMetaSignature(), meta)) return false;
|
||||
var origin = verification.getOrigin();
|
||||
if (!verifyMessagePart(verification.getOriginSignature(), origin)) return false;
|
||||
if (origin.getSerializedSize() == 0) {
|
||||
return verifyMessagePart(verification.getBodySignature(), body);
|
||||
return verifyMessagePart(verification.getBodySignature(), data);
|
||||
}
|
||||
return verification.getBodySignature().getSerializedSize() == 0
|
||||
&& verifyMatryoshkaLevel(body, meta.getOrigin(), origin);
|
||||
&& verifyMatryoshkaLevel(data, meta.getOrigin(), origin);
|
||||
}
|
||||
|
||||
public static boolean verifyMessagePart(Types.Signature sig, AbstractMessage data) {
|
||||
public static boolean verifyMessagePart(frostFS.refs.Types.Signature sig, Message data) {
|
||||
if (sig.getSerializedSize() == 0 || sig.getKey().isEmpty() || sig.getSign().isEmpty()) return false;
|
||||
|
||||
var publicKey = getPublicKeyFromBytes(sig.getKey().toByteArray());
|
||||
|
@ -107,7 +107,7 @@ public class Verifier {
|
|||
|
||||
public static boolean verifyData(PublicKey publicKey, byte[] data, byte[] sig) {
|
||||
try {
|
||||
Signature signature = Signature.getInstance("NONEwithECDSAinP1363Format");
|
||||
Signature signature = Signature.getInstance(SIGNATURE_ALGORITHM);
|
||||
signature.initVerify(publicKey);
|
||||
signature.update(DigestUtils.sha512(data));
|
||||
return signature.verify(Arrays.copyOfRange(sig, 1, sig.length));
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
package info.FrostFS.sdk;
|
||||
|
||||
import com.google.protobuf.AbstractMessage;
|
||||
import com.google.protobuf.ByteString;
|
||||
import com.google.protobuf.Message;
|
||||
import org.bouncycastle.crypto.digests.RIPEMD160Digest;
|
||||
|
||||
import java.math.BigInteger;
|
||||
|
@ -30,7 +30,7 @@ public class Helper {
|
|||
return getSha256Instance().digest(value);
|
||||
}
|
||||
|
||||
public static ByteString getSha256(AbstractMessage value) {
|
||||
public static ByteString getSha256(Message value) {
|
||||
return ByteString.copyFrom(getSha256(value.toByteArray()));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<parent>
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package info.FrostFS.sdk.constants;
|
||||
|
||||
public class FieldConst {
|
||||
public static final String META_HEADER_FIELD_NAME = "meta_header";
|
||||
public static final String META_SIGNATURE_FIELD_NAME = "meta_signature";
|
||||
public static final String BODY_FIELD_NAME = "body";
|
||||
public static final String BODY_SIGNATURE_FIELD_NAME = "body_signature";
|
||||
public static final String ORIGIN_FIELD_NAME = "origin";
|
||||
public static final String ORIGIN_SIGNATURE_FIELD_NAME = "origin_signature";
|
||||
public static final String VERIFY_HEADER_FIELD_NAME = "verify_header";
|
||||
}
|
Loading…
Reference in a new issue