├── .travis.yml ├── StorjBrowser ├── build.bat ├── src │ └── main │ │ ├── resources │ │ ├── images │ │ │ ├── storj.png │ │ │ ├── delete.png │ │ │ ├── download.png │ │ │ ├── refresh.png │ │ │ ├── storj.jpeg │ │ │ ├── upload.png │ │ │ └── storj-small.jpeg │ │ └── layout.fxml │ │ └── java │ │ └── sample │ │ ├── Preferences.java │ │ ├── BucketListCellFactory.java │ │ ├── BucketListCell.java │ │ ├── Main.java │ │ ├── FileSizeUtils.java │ │ ├── Site.java │ │ ├── BucketEntryTableView.java │ │ ├── PasswordInputDialog.java │ │ └── Controller.java ├── README.md └── pom.xml ├── .gitignore ├── storj-bridge-rest-client ├── src │ ├── main │ │ └── java │ │ │ └── storj │ │ │ └── io │ │ │ └── restclient │ │ │ ├── model │ │ │ ├── Operation.java │ │ │ ├── Preferences.java │ │ │ ├── StorjFile.java │ │ │ ├── ECDSAKey.java │ │ │ ├── AddShardResponse.java │ │ │ ├── FilePointer.java │ │ │ ├── Token.java │ │ │ ├── Contact.java │ │ │ ├── Frame.java │ │ │ ├── Shard.java │ │ │ ├── Bucket.java │ │ │ ├── BucketEntry.java │ │ │ └── User.java │ │ │ ├── auth │ │ │ ├── AuthType.java │ │ │ ├── NoAuthType.java │ │ │ └── BasicAuthType.java │ │ │ └── rest │ │ │ ├── MapQueryEncoderUtils.java │ │ │ └── StorjRestClient.java │ └── test │ │ └── java │ │ └── storj │ │ └── io │ │ └── restclient │ │ └── rest │ │ └── StorjRestClientTest.java ├── README.md └── pom.xml ├── storj-client ├── README.md ├── src │ └── main │ │ └── java │ │ └── storj │ │ └── io │ │ └── client │ │ ├── websockets │ │ ├── AuthorizationModel.java │ │ ├── WebsocketShardSender.java │ │ └── WebsocketFileRetriever.java │ │ ├── main │ │ └── CodeTestUtils.java │ │ ├── encryption │ │ ├── EncryptionUtils.java │ │ └── AESFiles.java │ │ ├── StorjConfiguration.java │ │ ├── StorjClient.java │ │ ├── sharding │ │ └── ShardingUtils.java │ │ └── DefaultStorjClient.java └── pom.xml ├── README.md └── pom.xml /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | -------------------------------------------------------------------------------- /StorjBrowser/build.bat: -------------------------------------------------------------------------------- 1 | mvn jfx:jar -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/storj.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/storj.png -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/delete.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/delete.png -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/download.png -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/refresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/refresh.png -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/storj.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/storj.jpeg -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/upload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/upload.png -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/images/storj-small.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NutterzUK/Storj-Java/HEAD/StorjBrowser/src/main/resources/images/storj-small.jpeg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Eclipse 2 | .classpath 3 | .project 4 | .settings/ 5 | 6 | # Intellij 7 | .idea/ 8 | *.iml 9 | *.iws 10 | 11 | # Mac 12 | .DS_Store 13 | 14 | # Maven 15 | log/ 16 | target/ -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Operation.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by Stephen Nutbrown on 07/07/2016. 5 | */ 6 | public enum Operation { 7 | PUSH, PULL; 8 | } 9 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/auth/AuthType.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.auth; 2 | 3 | import com.sun.jersey.api.client.WebResource; 4 | 5 | /** 6 | * Created by Stephen Nutbrown on 03/07/2016. 7 | */ 8 | public interface AuthType { 9 | 10 | public WebResource.Builder setRequiredAuthHeaders (WebResource.Builder builder); 11 | 12 | } 13 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/auth/NoAuthType.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.auth; 2 | 3 | import com.sun.jersey.api.client.WebResource; 4 | 5 | /** 6 | * Created by Stephen Nutbrown on 03/07/2016. 7 | */ 8 | public class NoAuthType implements AuthType{ 9 | 10 | public WebResource.Builder setRequiredAuthHeaders(WebResource.Builder builder) { 11 | return builder; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Preferences.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by steve on 01/06/2017. 5 | */ 6 | public class Preferences { 7 | 8 | private boolean dnt; 9 | 10 | public Preferences(){ 11 | 12 | } 13 | 14 | public boolean isDnt() { 15 | return dnt; 16 | } 17 | 18 | public void setDnt(boolean dnt) { 19 | this.dnt = dnt; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /StorjBrowser/README.md: -------------------------------------------------------------------------------- 1 | # Java client for the storj project. 2 | 3 | This the Storj Browser project. It depends upon the Storj Client, which depends upon the Storj Rest Client. 4 | 5 | ``` 6 | ++ Parent project 7 | ++++ Storj Browser: A UI for the storj client. 8 | ++++++ storj.io.client.DefaultStorjClient-client: Storj Client. 9 | +++++++++ storj.io.client.DefaultStorjClient-bridge-rest-client: Low level rest services for connecting to the Storj Bridge. 10 | ``` 11 | 12 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/Preferences.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import com.google.gson.annotations.Expose; 4 | 5 | import java.util.ArrayList; 6 | 7 | /** 8 | * Created by steve on 21/08/2016. 9 | */ 10 | public class Preferences { 11 | 12 | @Expose 13 | ArrayList sites = new ArrayList<>(); 14 | 15 | public ArrayList getSites() { 16 | return sites; 17 | } 18 | 19 | public void setSites(ArrayList sites) { 20 | this.sites = sites; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/BucketListCellFactory.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import javafx.scene.control.ListCell; 4 | import javafx.scene.control.ListView; 5 | import javafx.util.Callback; 6 | import storj.io.restclient.model.Bucket; 7 | 8 | /** 9 | * Created by steve on 16/08/2016. 10 | */ 11 | public class BucketListCellFactory implements Callback, ListCell> { 12 | 13 | @Override 14 | public ListCell call(ListView listview) { 15 | return new BucketListCell(); 16 | } 17 | 18 | } 19 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/BucketListCell.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import javafx.scene.control.ListCell; 4 | import storj.io.restclient.model.Bucket; 5 | 6 | /** 7 | * Created by steve on 16/08/2016. 8 | */ 9 | public class BucketListCell extends ListCell { 10 | 11 | @Override 12 | public void updateItem(Bucket item, boolean empty) { 13 | super.updateItem(item, empty); 14 | // Format for bucket. 15 | if (!(item == null || empty)) { 16 | this.setText(item.getName()); 17 | } 18 | setGraphic(null); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /storj-client/README.md: -------------------------------------------------------------------------------- 1 | # This is the storj client - DEPRECATED 2 | 3 | 4 | 5 | It handles uploads and downloads, and provides a useful interface for other developers. It is implemented in Java. 6 | It depends on the Storj rest client for underlying HTTP operations. The Java Browser UI depends on this project. 7 | 8 | ``` 9 | ++ Parent project 10 | ++++ Storj Browser: A UI for the storj client. 11 | ++++++ storj.io.client.DefaultStorjClient-client: Storj Client. 12 | +++++++++ storj.io.client.DefaultStorjClient-bridge-rest-client: Low level rest services for connecting to the Storj Bridge. 13 | ``` 14 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/README.md: -------------------------------------------------------------------------------- 1 | # storj.io.client.DefaultStorjClient-bridge-rest-client 2 | 3 | This is a REST client for communicating the the storj-bridge, implemented in Java. 4 | Above this project sits a storj-client, which depends on this project for making HTTP requests. 5 | If you are wanting to use this project to upload/download data to the storj network, it is recommended 6 | that you use the storj-client project, which uses this project for it's communication. 7 | 8 | This project is purely for HTTP requests, so does not include logic for sharding files or encrypting them. 9 | 10 | ``` 11 | ++ Parent project 12 | ++++ Storj Browser: A UI for the storj client. 13 | ++++++ storj.io.client.DefaultStorjClient-client: Storj Client. 14 | +++++++++ storj.io.client.DefaultStorjClient-bridge-rest-client: Low level rest services for connecting to the Storj Bridge. 15 | ``` 16 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/Main.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import javafx.application.Application; 4 | import javafx.fxml.FXMLLoader; 5 | import javafx.scene.Parent; 6 | import javafx.scene.Scene; 7 | import javafx.scene.image.Image; 8 | import javafx.stage.Stage; 9 | 10 | public class Main extends Application { 11 | 12 | @Override 13 | public void start(Stage primaryStage) throws Exception{ 14 | Parent root = FXMLLoader.load(getClass().getClassLoader().getResource("layout.fxml")); 15 | primaryStage.getIcons().add(new Image("/images/storj.jpeg")); 16 | primaryStage.setTitle("Storj Bucket Browser"); 17 | primaryStage.setScene(new Scene(root, 800, 600)); 18 | primaryStage.setResizable(false); 19 | primaryStage.show(); 20 | } 21 | 22 | public static void main(String[] args) { 23 | launch(args); 24 | } 25 | } -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/websockets/AuthorizationModel.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.websockets; 2 | 3 | import storj.io.restclient.model.Operation; 4 | 5 | /** 6 | * Created by Stephen Nutbrown on 12/07/2016. 7 | */ 8 | public class AuthorizationModel { 9 | 10 | String token; 11 | String hash; 12 | Operation operation; 13 | 14 | public String getToken() { 15 | return token; 16 | } 17 | 18 | public void setToken(String token) { 19 | this.token = token; 20 | } 21 | 22 | public String getHash() { 23 | return hash; 24 | } 25 | 26 | public void setHash(String hash) { 27 | this.hash = hash; 28 | } 29 | 30 | public Operation getOperation() { 31 | return operation; 32 | } 33 | 34 | public void setOperation(Operation operation) { 35 | this.operation = operation; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/FileSizeUtils.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | /** 4 | * Created by steve on 19/08/2016. 5 | */ 6 | public class FileSizeUtils { 7 | 8 | /** 9 | * Turns a number of bytes into a human readable count. 10 | * Thanks to aioobe on stackoverflow: http://stackoverflow.com/questions/3758606/how-to-convert-byte-size-into-human-readable-format-in-java 11 | * @param bytes the byte count. 12 | * @param si If si should be used. 13 | * @return the human readable format. 14 | */ 15 | public static String humanReadableByteCount(long bytes, boolean si) { 16 | int unit = si ? 1000 : 1024; 17 | if (bytes < unit) return bytes + " B"; 18 | int exp = (int) (Math.log(bytes) / Math.log(unit)); 19 | String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i"); 20 | return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Java client for the storj project. 2 | 3 | This is a java client for the storj-bridge project. It has three maven modules. 4 | Storj browser is a JavaFX based storj client, with a UI, for an end user. 5 | The storj-client is the higher level project. The storj-client handles sharding and splitting files. 6 | It relies on the storj-bridge-rest-client which handles HTTP requests to the storj API. 7 | 8 | If you are wanting the browser, you'll want the Storj Browser project. 9 | If you are looking to include a storj client in your project, you'll want the storj-client project. 10 | If you are ONLY looking for handling HTTP requests and wish to implement file sharding and encryption yourself, you may use the storj-bridge-rest-client. 11 | 12 | ``` 13 | ++ Parent project 14 | ++++ Storj Browser: A UI for the storj client. 15 | ++++++ storj.io.client.DefaultStorjClient-client: Storj Client. 16 | +++++++++ storj.io.client.DefaultStorjClient-bridge-rest-client: Low level rest services for connecting to the Storj Bridge. 17 | ``` 18 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/rest/MapQueryEncoderUtils.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.rest; 2 | 3 | import java.util.*; 4 | import java.io.UnsupportedEncodingException; 5 | import java.net.URLEncoder; 6 | 7 | public class MapQueryEncoderUtils { 8 | 9 | static String urlEncodeUTF8(String s) { 10 | try { 11 | return URLEncoder.encode(s, "UTF-8"); 12 | } catch (UnsupportedEncodingException e) { 13 | throw new UnsupportedOperationException(e); 14 | } 15 | } 16 | 17 | static String urlEncodeUTF8(Map map) { 18 | StringBuilder sb = new StringBuilder("?"); 19 | for (Map.Entry entry : map.entrySet()) { 20 | if (sb.length() > 1) { 21 | sb.append("&"); 22 | } 23 | sb.append(String.format("%s=%s", 24 | urlEncodeUTF8(entry.getKey().toString()), 25 | urlEncodeUTF8(entry.getValue().toString()) 26 | )); 27 | } 28 | 29 | return sb.toString(); 30 | } 31 | } -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/Site.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | 4 | import com.google.gson.annotations.Expose; 5 | 6 | /** 7 | * Created by steve on 21/08/2016. 8 | */ 9 | public class Site { 10 | 11 | @Expose 12 | String apiRoot; 13 | 14 | @Expose 15 | String username; 16 | 17 | @Expose 18 | String siteName; 19 | 20 | 21 | public Site(String apiRoot, String username, String key, String siteName) { 22 | this.apiRoot = apiRoot; 23 | this.username = username; 24 | this.siteName = siteName; 25 | } 26 | 27 | public String getSiteName() { 28 | return siteName; 29 | } 30 | 31 | public void setSiteName(String siteName) { 32 | this.siteName = siteName; 33 | } 34 | 35 | public String getApiRoot() { 36 | return apiRoot; 37 | } 38 | 39 | public void setApiRoot(String apiRoot) { 40 | this.apiRoot = apiRoot; 41 | } 42 | 43 | public String getUsername() { 44 | return username; 45 | } 46 | 47 | public void setUsername(String username) { 48 | this.username = username; 49 | } 50 | 51 | public String toString(){ 52 | return siteName; 53 | } 54 | 55 | } 56 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/StorjFile.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by steve on 22/07/2016. 5 | */ 6 | public class StorjFile { 7 | 8 | /** 9 | * The ID of the frame to finalise. 10 | */ 11 | String frame; 12 | 13 | /** 14 | * The mimetype of the file. 15 | */ 16 | String mimetype; 17 | 18 | /** 19 | * The filename of the file. 20 | */ 21 | String filename; 22 | 23 | public StorjFile(String frame, String mimetype, String filename) { 24 | this.frame = frame; 25 | this.mimetype = mimetype; 26 | this.filename = filename; 27 | } 28 | 29 | public String getFrame() { 30 | return frame; 31 | } 32 | 33 | public void setFrame(String frame) { 34 | this.frame = frame; 35 | } 36 | 37 | public String getMimetype() { 38 | return mimetype; 39 | } 40 | 41 | public void setMimetype(String mimetype) { 42 | this.mimetype = mimetype; 43 | } 44 | 45 | public String getFilename() { 46 | return filename; 47 | } 48 | 49 | public void setFilename(String filename) { 50 | this.filename = filename; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/auth/BasicAuthType.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.auth; 2 | 3 | import com.google.common.hash.Hashing; 4 | import com.google.common.io.BaseEncoding; 5 | import com.sun.jersey.api.client.WebResource; 6 | 7 | import javax.ws.rs.core.HttpHeaders; 8 | import java.nio.charset.StandardCharsets; 9 | 10 | /** 11 | * Created by Stephen Nutbrown on 03/07/2016. 12 | */ 13 | public class BasicAuthType implements AuthType{ 14 | 15 | private String authorizationHeaderValue; 16 | 17 | public BasicAuthType(String username, String password){ 18 | authorizationHeaderValue = "basic " + base64Encode(username + ":" + sha256Encrypt(password)); 19 | } 20 | 21 | public WebResource.Builder setRequiredAuthHeaders(WebResource.Builder builder){ 22 | return builder.header(HttpHeaders.AUTHORIZATION, authorizationHeaderValue); 23 | } 24 | 25 | private String sha256Encrypt(String input){ 26 | return Hashing.sha256() 27 | .hashString(input, StandardCharsets.UTF_8) 28 | .toString(); 29 | } 30 | 31 | private String base64Encode(String input){ 32 | return BaseEncoding.base64().encode(input.getBytes(StandardCharsets.UTF_8)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | storj 8 | parent-project 9 | pom 10 | ${version} 11 | 12 | Storj Java Parent Project 13 | http://storj.io 14 | 15 | 16 | 17 | NutterzUK 18 | Stephen Nutbrown 19 | steveswfc@gmail.com 20 | 21 | developer 22 | 23 | Europe/London 24 | 25 | http://www.spindroid.co.uk/imageHost/me.jpg 26 | 27 | 28 | 29 | 30 | 31 | storj-bridge-rest-client 32 | storj-client 33 | StorjBrowser 34 | 35 | 36 | 37 | 0.0.1-Alpha 38 | 39 | 40 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/ECDSAKey.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by Stephen Nutbrown on 06/07/2016. 5 | */ 6 | public class ECDSAKey { 7 | 8 | /** 9 | * The ESDA Key value 10 | */ 11 | String key; 12 | 13 | /** 14 | * The user ID the key is associated with. 15 | */ 16 | String userId; 17 | 18 | /** 19 | * Get the key. 20 | * @return the ECDSA key value. 21 | */ 22 | public String getKey() { 23 | return key; 24 | } 25 | 26 | /** 27 | * Set the key 28 | * @param key the ECDSA key value. 29 | */ 30 | public void setKey(String key) { 31 | this.key = key; 32 | } 33 | 34 | /** 35 | * Get the user ID 36 | * @return the user id. 37 | */ 38 | public String getUserId() { 39 | return userId; 40 | } 41 | 42 | /** 43 | * Set the user id. 44 | * @param userId the user id. 45 | */ 46 | public void setUserId(String userId) { 47 | this.userId = userId; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "ECDSAKey{" + 53 | "key='" + key + '\'' + 54 | ", user='" + userId + '\'' + 55 | '}'; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/AddShardResponse.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by steve on 09/07/2016. 5 | */ 6 | public class AddShardResponse { 7 | 8 | String hash; 9 | String token; 10 | Operation operation; 11 | Contact farmer; 12 | 13 | public Contact getFarmer() { 14 | return farmer; 15 | } 16 | 17 | public void setFarmer(Contact farmer) { 18 | this.farmer = farmer; 19 | } 20 | 21 | public Operation getOperation() { 22 | return operation; 23 | } 24 | 25 | public void setOperation(Operation operation) { 26 | this.operation = operation; 27 | } 28 | 29 | public String getToken() { 30 | return token; 31 | } 32 | 33 | public void setToken(String token) { 34 | this.token = token; 35 | } 36 | 37 | public String getHash() { 38 | return hash; 39 | } 40 | 41 | public void setHash(String hash) { 42 | this.hash = hash; 43 | } 44 | 45 | @Override 46 | public String toString() { 47 | return "AddShardResponse{" + 48 | "hash='" + hash + '\'' + 49 | ", token='" + token + '\'' + 50 | ", operation=" + operation + 51 | ", farmer=" + farmer + 52 | '}'; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/FilePointer.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by Stephen Nutrown on 07/07/2016. 5 | */ 6 | public class FilePointer { 7 | String hash; 8 | String token; 9 | Operation operation; 10 | Contact farmer; 11 | long size; 12 | 13 | public Contact getFarmer() { 14 | return farmer; 15 | } 16 | 17 | public void setFarmer(Contact farmer) { 18 | this.farmer = farmer; 19 | } 20 | 21 | public long getSize() { 22 | return size; 23 | } 24 | 25 | public void setSize(long size) { 26 | this.size = size; 27 | } 28 | 29 | public String getHash() { 30 | return hash; 31 | } 32 | 33 | public void setHash(String hash) { 34 | this.hash = hash; 35 | } 36 | 37 | public String getToken() { 38 | return token; 39 | } 40 | 41 | public void setToken(String token) { 42 | this.token = token; 43 | } 44 | 45 | public Operation getOperation() { 46 | return operation; 47 | } 48 | 49 | public void setOperation(Operation operation) { 50 | this.operation = operation; 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return "FilePointer{" + 56 | "hash='" + hash + '\'' + 57 | ", token='" + token + '\'' + 58 | ", operation=" + operation + 59 | '\'' + 60 | '}'; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Token.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by Stephen Nutbrown on 07/07/2016. 5 | */ 6 | public class Token { 7 | 8 | String bucket; 9 | String expires; 10 | Operation operation; 11 | String token; 12 | String id; 13 | 14 | public String getId() { 15 | return id; 16 | } 17 | 18 | public void setId(String id) { 19 | this.id = id; 20 | } 21 | 22 | public String getBucket() { 23 | return bucket; 24 | } 25 | 26 | public void setBucket(String bucket) { 27 | this.bucket = bucket; 28 | } 29 | 30 | public String getExpires() { 31 | return expires; 32 | } 33 | 34 | public void setExpires(String expires) { 35 | this.expires = expires; 36 | } 37 | 38 | public Operation getOperation() { 39 | return operation; 40 | } 41 | 42 | public void setOperation(Operation operation) { 43 | this.operation = operation; 44 | } 45 | 46 | public String getToken() { 47 | return token; 48 | } 49 | 50 | public void setToken(String token) { 51 | this.token = token; 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | return "Token{" + 57 | "bucket='" + bucket + '\'' + 58 | ", expires='" + expires + '\'' + 59 | ", operation=" + operation + 60 | ", token='" + token + '\'' + 61 | '}'; 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/BucketEntryTableView.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import javafx.beans.property.SimpleStringProperty; 4 | import storj.io.restclient.model.BucketEntry; 5 | 6 | /** 7 | * Created by steve on 16/08/2016. 8 | */ 9 | public class BucketEntryTableView { 10 | 11 | private final SimpleStringProperty fileName; 12 | private final SimpleStringProperty size; 13 | private final SimpleStringProperty type; 14 | private final SimpleStringProperty id; 15 | 16 | public BucketEntryTableView(BucketEntry bucketEntry){ 17 | fileName = new SimpleStringProperty(bucketEntry.getFilename()); 18 | size = new SimpleStringProperty(FileSizeUtils.humanReadableByteCount(bucketEntry.getSize(), true)); 19 | type = new SimpleStringProperty(bucketEntry.getMimetype()); 20 | id = new SimpleStringProperty(bucketEntry.getId()); 21 | } 22 | 23 | public String getId(){ 24 | return id.get(); 25 | } 26 | 27 | public void setId(String id){ 28 | this.id.set(id); 29 | } 30 | 31 | public String getFileName(){ 32 | return fileName.get(); 33 | } 34 | 35 | public void setFileName(String set){ 36 | fileName.set(set); 37 | } 38 | 39 | public String getSize(){ 40 | return size.get(); 41 | } 42 | 43 | public void setSize(String set){ 44 | size.set(set); 45 | } 46 | 47 | public String getType(){ 48 | return type.get(); 49 | } 50 | 51 | public void setType(String set){ 52 | type.set(set); 53 | } 54 | 55 | 56 | 57 | } 58 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Contact.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | /** 4 | * Created by Stephen Nutbrown on 03/07/2016. 5 | */ 6 | public class Contact { 7 | 8 | private String protocol; 9 | private String address; 10 | private int port; 11 | private String lastSeen; 12 | private String nodeID; 13 | 14 | 15 | public String getProtocol() { 16 | return protocol; 17 | } 18 | 19 | public void setProtocol(String protocol) { 20 | this.protocol = protocol; 21 | } 22 | 23 | public String getAddress() { 24 | return address; 25 | } 26 | 27 | public void setAddress(String address) { 28 | this.address = address; 29 | } 30 | 31 | public int getPort() { 32 | return port; 33 | } 34 | 35 | public void setPort(int port) { 36 | this.port = port; 37 | } 38 | 39 | public String getLastSeen() { 40 | return lastSeen; 41 | } 42 | 43 | public void setLastSeen(String lastSeen) { 44 | this.lastSeen = lastSeen; 45 | } 46 | 47 | public String getNodeID() { 48 | return nodeID; 49 | } 50 | 51 | public void setNodeID(String nodeId) { 52 | this.nodeID = nodeId; 53 | } 54 | 55 | @Override 56 | public String toString() { 57 | return "Contact{" + 58 | "protocol='" + protocol + '\'' + 59 | ", address='" + address + '\'' + 60 | ", port=" + port + 61 | ", lastSeen='" + lastSeen + '\'' + 62 | ", nodeID='" + nodeID + '\'' + 63 | '}'; 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Frame.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Represents a file staging frame. 7 | * Created by Stephen Nutbrown on 06/07/2016. 8 | */ 9 | public class Frame { 10 | 11 | String user; 12 | String created; 13 | String id; 14 | List shards; 15 | int size; 16 | boolean locked; 17 | 18 | public boolean isLocked() { 19 | return locked; 20 | } 21 | 22 | public void setLocked(boolean locked) { 23 | this.locked = locked; 24 | } 25 | 26 | public int getSize() { 27 | return size; 28 | } 29 | 30 | public void setSize(int size) { 31 | this.size = size; 32 | } 33 | 34 | public String getUser() { 35 | return user; 36 | } 37 | 38 | public void setUser(String user) { 39 | this.user = user; 40 | } 41 | 42 | public String getCreated() { 43 | return created; 44 | } 45 | 46 | public void setCreated(String created) { 47 | this.created = created; 48 | } 49 | 50 | public String getId() { 51 | return id; 52 | } 53 | 54 | public void setId(String id) { 55 | this.id = id; 56 | } 57 | 58 | public List getShards() { 59 | return shards; 60 | } 61 | 62 | public void setShards(List shards) { 63 | this.shards = shards; 64 | } 65 | 66 | @Override 67 | public String toString() { 68 | return "Frame{" + 69 | "created='" + created + '\'' + 70 | ", id='" + id + '\'' + 71 | ", shards=" + shards + 72 | '}'; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Shard.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | import org.codehaus.jackson.annotate.JsonIgnore; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * Created by Stephen Nutbrown on 06/07/2016. 10 | */ 11 | public class Shard { 12 | 13 | @JsonIgnore 14 | String _id; 15 | 16 | int index; 17 | 18 | String hash; 19 | long size; 20 | List tree = new ArrayList(); 21 | List challenges = new ArrayList(); 22 | 23 | @JsonIgnore 24 | String path; 25 | 26 | public String getPath() { 27 | return path; 28 | } 29 | 30 | public void setPath(String path) { 31 | this.path = path; 32 | } 33 | 34 | public String get_id() { 35 | return _id; 36 | } 37 | 38 | public void set_id(String _id) { 39 | this._id = _id; 40 | } 41 | 42 | public int getIndex() { 43 | return index; 44 | } 45 | 46 | public void setIndex(int index) { 47 | this.index = index; 48 | } 49 | 50 | public String getHash() { 51 | return hash; 52 | } 53 | 54 | public void setHash(String hash) { 55 | this.hash = hash; 56 | } 57 | 58 | public long getSize() { 59 | return size; 60 | } 61 | 62 | public void setSize(long size) { 63 | this.size = size; 64 | } 65 | 66 | public List getTree() { 67 | return tree; 68 | } 69 | 70 | public void setTree(List tree) { 71 | this.tree = tree; 72 | } 73 | 74 | public List getChallenges() { 75 | return challenges; 76 | } 77 | 78 | public void setChallenges(List challenges) { 79 | this.challenges = challenges; 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | return "Shard{" + 85 | "index=" + index + 86 | ", hash='" + hash + '\'' + 87 | ", size=" + size + 88 | ", tree=" + tree + 89 | ", challenges=" + challenges + 90 | '}'; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/Bucket.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | import java.util.List; 4 | 5 | /** 6 | * Created by Stephen Nutbrown on 07/07/2016. 7 | */ 8 | public class Bucket { 9 | 10 | int storage; 11 | int transfer; 12 | String status; 13 | List pubkeys; 14 | String user; 15 | String name; 16 | String created; 17 | String id; 18 | 19 | public int getStorage() { 20 | return storage; 21 | } 22 | 23 | public void setStorage(int storage) { 24 | this.storage = storage; 25 | } 26 | 27 | public int getTransfer() { 28 | return transfer; 29 | } 30 | 31 | public void setTransfer(int transfer) { 32 | this.transfer = transfer; 33 | } 34 | 35 | public String getStatus() { 36 | return status; 37 | } 38 | 39 | public void setStatus(String status) { 40 | this.status = status; 41 | } 42 | 43 | public List getPubkeys() { 44 | return pubkeys; 45 | } 46 | 47 | public void setPubkeys(List pubkeys) { 48 | this.pubkeys = pubkeys; 49 | } 50 | 51 | public String getUser() { 52 | return user; 53 | } 54 | 55 | public void setUser(String user) { 56 | this.user = user; 57 | } 58 | 59 | public String getName() { 60 | return name; 61 | } 62 | 63 | public void setName(String name) { 64 | this.name = name; 65 | } 66 | 67 | public String getCreated() { 68 | return created; 69 | } 70 | 71 | public void setCreated(String created) { 72 | this.created = created; 73 | } 74 | 75 | public String getId() { 76 | return id; 77 | } 78 | 79 | public void setId(String id) { 80 | this.id = id; 81 | } 82 | 83 | @Override 84 | public String toString() { 85 | return "Bucket{" + 86 | "storage=" + storage + 87 | ", transfer=" + transfer + 88 | ", status='" + status + '\'' + 89 | ", pubkeys=" + pubkeys + 90 | ", user='" + user + '\'' + 91 | ", name='" + name + '\'' + 92 | ", created='" + created + '\'' + 93 | ", id='" + id + '\'' + 94 | '}'; 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/websockets/WebsocketShardSender.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.websockets; 2 | 3 | import com.google.gson.Gson; 4 | import org.java_websocket.client.WebSocketClient; 5 | import org.java_websocket.drafts.Draft_17; 6 | import org.java_websocket.handshake.ServerHandshake; 7 | import storj.io.restclient.model.AddShardResponse; 8 | import storj.io.restclient.model.Shard; 9 | 10 | import java.io.*; 11 | import java.net.URI; 12 | import java.nio.ByteBuffer; 13 | import java.nio.file.Files; 14 | import java.util.concurrent.CountDownLatch; 15 | import java.util.logging.Logger; 16 | 17 | 18 | 19 | public class WebsocketShardSender extends WebSocketClient { 20 | 21 | private Logger logger = Logger.getLogger(this.getClass().getName()); 22 | private Gson gson = new Gson(); 23 | private Shard shard; 24 | private AddShardResponse destination; 25 | private AuthorizationModel authModel; 26 | private CountDownLatch latch; 27 | 28 | public WebsocketShardSender(URI serverURI, Shard shard, AddShardResponse destination, CountDownLatch latch){ 29 | super(serverURI, new Draft_17(), null, 99999); 30 | this.shard = shard; 31 | this.destination = destination; 32 | this.latch = latch; 33 | 34 | authModel = new AuthorizationModel(); 35 | authModel.setToken(destination.getToken()); 36 | authModel.setOperation(destination.getOperation()); 37 | authModel.setHash(destination.getHash()); 38 | 39 | } 40 | 41 | public void onOpen(ServerHandshake serverHandshake) { 42 | File shardFile = new File(shard.getPath()); 43 | try { 44 | // send auth as text. 45 | send(gson.toJson(authModel)); 46 | // send shard data as binary - note this will need changing to read in small amounts to save memory.. when it's working. 47 | send(Files.readAllBytes(shardFile.toPath())); 48 | } catch (IOException e) { 49 | throw new RuntimeException(e); 50 | } 51 | } 52 | 53 | public void onMessage(String s) { 54 | logger.info(s); 55 | } 56 | 57 | public void onClose(int i, String s, boolean b) { 58 | logger.info("Websocket closed with reason" + i + s + b); 59 | latch.countDown(); 60 | } 61 | 62 | public void onError(Exception e) { 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/BucketEntry.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | import org.codehaus.jackson.map.annotate.JsonSerialize; 4 | 5 | /** 6 | * Created by Stephen Nutbrown on 07/07/2016. 7 | */ 8 | @JsonSerialize(include=JsonSerialize.Inclusion.NON_NULL) 9 | public class BucketEntry { 10 | 11 | String id; 12 | String hash; 13 | String bucket; 14 | String mimetype; 15 | String filename; 16 | long size; 17 | String frame; 18 | String name; 19 | String renewal; 20 | 21 | public String getId() { 22 | return id; 23 | } 24 | 25 | public void setId(String id) { 26 | this.id = id; 27 | } 28 | 29 | public String getRenewal() { 30 | return renewal; 31 | } 32 | 33 | public void setRenewal(String renewal) { 34 | this.renewal = renewal; 35 | } 36 | 37 | public String getName() { 38 | return name; 39 | } 40 | 41 | public void setName(String name) { 42 | this.name = name; 43 | } 44 | 45 | public String getFrame() { 46 | return frame; 47 | } 48 | 49 | public void setFrame(String frame) { 50 | this.frame = frame; 51 | } 52 | 53 | public String getHash() { 54 | return hash; 55 | } 56 | 57 | public void setHash(String hash) { 58 | this.hash = hash; 59 | } 60 | 61 | public String getBucket() { 62 | return bucket; 63 | } 64 | 65 | public void setBucket(String bucket) { 66 | this.bucket = bucket; 67 | } 68 | 69 | public String getMimetype() { 70 | return mimetype; 71 | } 72 | 73 | public void setMimetype(String mimetype) { 74 | this.mimetype = mimetype; 75 | } 76 | 77 | public String getFilename() { 78 | return filename; 79 | } 80 | 81 | public void setFilename(String filename) { 82 | this.filename = filename; 83 | } 84 | 85 | public long getSize() { 86 | return size; 87 | } 88 | 89 | public void setSize(long size) { 90 | this.size = size; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | return "BucketEntry{" + 96 | "hash='" + hash + '\'' + 97 | ", bucket='" + bucket + '\'' + 98 | ", mimetype='" + mimetype + '\'' + 99 | ", filename='" + filename + '\'' + 100 | ", size=" + size + 101 | '}'; 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | storj 8 | storj-bridge-rest-client 9 | ${version} 10 | jar 11 | 12 | Storj Rest Client 13 | http://storj.io 14 | 15 | 16 | 17 | NutterzUK 18 | Stephen Nutbrown 19 | steveswfc@gmail.com 20 | 21 | developer 22 | 23 | Europe/London 24 | 25 | http://www.spindroid.co.uk/imageHost/me.jpg 26 | 27 | 28 | 29 | 30 | 31 | storj 32 | parent-project 33 | ${version} 34 | ../pom.xml 35 | 36 | 37 | 38 | 39 | 40 | 41 | com.sun.jersey 42 | jersey-client 43 | 1.19.1 44 | 45 | 46 | 47 | com.sun.jersey 48 | jersey-json 49 | 1.19.1 50 | 51 | 52 | 53 | 54 | 55 | com.google.guava 56 | guava 57 | 19.0 58 | 59 | 60 | 61 | 62 | junit 63 | junit 64 | RELEASE 65 | test 66 | 67 | 68 | 69 | com.github.kristofa 70 | mock-http-server 71 | 4.1 72 | test 73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/main/CodeTestUtils.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.main; 2 | 3 | /** 4 | * Utility class containing methods to aid in the continuous testing of code. 5 | * Contains methods to assist in testing the project on different developers 6 | * machines. 7 | * 8 | * @author Lewis Foster 9 | */ 10 | public final class CodeTestUtils { 11 | 12 | private static final String USERNAME_PROPERTY = "storj_username"; 13 | private static final String DEFAULT_USERNAME = "costifrope@throwam.com"; 14 | 15 | private static final String PASSWORD_PROPERTY = "storj_password"; 16 | private static final String DEFAULT_PASSWORD = "stackoverflow"; 17 | 18 | private static final String BASEPATH_PROPERTY = "storj_basepath"; 19 | private static final String DEFAULT_BASEPATH = "https://api.storj.io"; 20 | 21 | private static final String ENCRYPTIONKEY_PROPERTY = "storj_encryoptionkey"; 22 | private static final String DEFAULT_ENCRYPTIONKEY = "DefaultKey"; 23 | 24 | /** 25 | * Returns the value of the system property with the key of {@value #ENCRYPTIONKEY_PROPERTY}. 26 | * If the system property is not set the default value of {@value #DEFAULT_ENCRYPTIONKEY} is used. 27 | * 28 | * @return the test encryption key. 29 | */ 30 | public static String getEncryptionKey() { 31 | return System.getProperty(ENCRYPTIONKEY_PROPERTY, DEFAULT_ENCRYPTIONKEY); 32 | } 33 | 34 | 35 | /** 36 | * Returns the value of the system property with the key of 37 | * {@value #USERNAME_PROPERTY}. If the system property is not set the 38 | * default of {@value #DEFAULT_USERNAME} is used. 39 | * 40 | * @return the test storj.io.client.DefaultStorjClient username 41 | */ 42 | public static String getStorjUsername() { 43 | return System.getProperty(USERNAME_PROPERTY, DEFAULT_USERNAME); 44 | } 45 | 46 | /** 47 | * Returns the value of the system property with the key of 48 | * {@value #PASSWORD_PROPERTY}. If the system property is not set the 49 | * default of {@value #DEFAULT_PASSWORD} is used. 50 | * 51 | * @return the test storj.io.client.DefaultStorjClient password 52 | */ 53 | public static String getStorjPassword() { 54 | return System.getProperty(PASSWORD_PROPERTY, DEFAULT_PASSWORD); 55 | } 56 | 57 | /** 58 | * Returns the value of the system property with the key of 59 | * {@value #BASEPATH_PROPERTY}. If the system property is not set the 60 | * default of {@value #DEFAULT_BASEPATH} is used. 61 | * 62 | * @return the test storj.io.client.DefaultStorjClient base path 63 | */ 64 | public static String getStorjBasePath() { 65 | return System.getProperty(BASEPATH_PROPERTY, DEFAULT_BASEPATH); 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /StorjBrowser/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | groupId 8 | StorjBrowser 9 | ${version} 10 | 11 | Storj Browser 12 | http://storj.io 13 | 14 | 15 | 16 | NutterzUK 17 | Stephen Nutbrown 18 | steveswfc@gmail.com 19 | 20 | developer 21 | 22 | Europe/London 23 | 24 | http://www.spindroid.co.uk/imageHost/me.jpg 25 | 26 | 27 | 28 | 29 | 30 | storj 31 | parent-project 32 | ${version} 33 | ../pom.xml 34 | 35 | 36 | 37 | 38 | 39 | storj 40 | storj-client 41 | ${version} 42 | 43 | 44 | 45 | 46 | org.controlsfx 47 | controlsfx 48 | 8.40.11 49 | 50 | 51 | 52 | 53 | 54 | 55 | StorjBrowser 56 | 57 | 58 | org.apache.maven.plugins 59 | maven-compiler-plugin 60 | 61 | 1.8 62 | 1.8 63 | 64 | 65 | 66 | 67 | com.zenjava 68 | javafx-maven-plugin 69 | 8.1.4 70 | 71 | sample.Main 72 | 73 | 74 | 75 | create-jfxjar 76 | package 77 | 78 | build-jar 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/encryption/EncryptionUtils.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.encryption; 2 | 3 | import com.google.common.hash.Hashing; 4 | import org.bouncycastle.crypto.digests.RIPEMD160Digest; 5 | import org.bouncycastle.util.encoders.Hex; 6 | 7 | import java.io.File; 8 | 9 | /** 10 | * Created by steve on 03/08/2016. 11 | */ 12 | public class EncryptionUtils { 13 | 14 | /** 15 | * Encrypt a file using AES. 16 | * @param input the input file. 17 | * @param output where to store the output after encryption. 18 | * @param key the key used to encrypt (To decrypt this key is required). 19 | * @throws Exception problem encrypting file. 20 | */ 21 | public static void encryptFile(File input, File output, String key) throws Exception { 22 | new AESFiles().encrypt(input, output, key.getBytes()); 23 | } 24 | 25 | /** 26 | * Decrypt a file using AES. 27 | * @param input the encrypted input file. 28 | * @param output where to store the output after decryption. 29 | * @param key the key used when encryping. 30 | * @throws Exception problem decrypting file. 31 | */ 32 | public static void decryptFile(File input, File output, String key) throws Exception { 33 | new AESFiles().decrypt(input, output, key.getBytes()); 34 | } 35 | 36 | /** 37 | * Take an input array of bytes and encode it as the storj core does. 38 | * This firstly sha56s encrypts the file, then hex encodes it. 39 | * Then, it RIPEMD160s the result and again hex encodes, before returning. 40 | * @param input a byte array to encrypt. 41 | * @return the byte[] after encrypting. 42 | */ 43 | public static byte[] rmd160Sha256(byte[] input){ 44 | byte[] sha256 = Hashing.sha256().hashBytes(input).asBytes(); 45 | sha256 = Hex.encode(sha256); 46 | RIPEMD160Digest digest = new RIPEMD160Digest(); 47 | digest.update(sha256, 0, sha256.length); 48 | byte[] output = new byte[digest.getDigestSize()]; 49 | digest.doFinal (output, 0); 50 | output = Hex.encode(output); 51 | return output; 52 | } 53 | 54 | 55 | /** 56 | * A more efficient version of rmd160sha256 for files, as it uses streaming. 57 | * @param file the file to hash. 58 | * @return the file after sha256 and ripemd160. 59 | * @throws Exception 60 | */ 61 | public static byte[] getRipemdSha256File(File file) throws Exception{ 62 | // Get sha256 for the file. 63 | byte[] sha256sBytes = com.google.common.io.Files.hash(file, Hashing.sha256()).asBytes(); 64 | 65 | // Updated in v3.0 of storj bridge. 66 | //sha256sBytes = Hex.encode(sha256sBytes); 67 | 68 | // Get RIPEMD160 for that. 69 | RIPEMD160Digest digest = new RIPEMD160Digest(); 70 | digest.update (sha256sBytes, 0, sha256sBytes.length); 71 | byte[] output = new byte[digest.getDigestSize()]; 72 | digest.doFinal (output, 0); 73 | output = Hex.encode(output); 74 | return output; 75 | } 76 | 77 | } 78 | -------------------------------------------------------------------------------- /storj-client/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 4.0.0 6 | 7 | storj 8 | storj-client 9 | ${version} 10 | jar 11 | 12 | Storj High Level Client 13 | http://storj.io 14 | 15 | 16 | 17 | NutterzUK 18 | Stephen Nutbrown 19 | steveswfc@gmail.com 20 | 21 | developer 22 | 23 | Europe/London 24 | 25 | http://www.spindroid.co.uk/imageHost/me.jpg 26 | 27 | 28 | 29 | 30 | 31 | storj 32 | parent-project 33 | ${version} 34 | ../ 35 | 36 | 37 | 38 | 39 | storj 40 | storj-bridge-rest-client 41 | ${version} 42 | 43 | 44 | 45 | 46 | org.bouncycastle 47 | bcpkix-jdk15on 48 | 1.54 49 | 50 | 51 | 52 | 53 | com.google.code.gson 54 | gson 55 | 2.7 56 | 57 | 58 | 59 | org.java-websocket 60 | Java-WebSocket 61 | 1.3.0 62 | 63 | 64 | 65 | org.apache.commons 66 | commons-lang3 67 | 3.0 68 | 69 | 70 | 71 | 78 | 79 | 80 | com.google.guava 81 | guava 82 | 19.0 83 | 84 | 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/websockets/WebsocketFileRetriever.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.websockets; 2 | 3 | import com.google.gson.Gson; 4 | import org.java_websocket.client.WebSocketClient; 5 | import org.java_websocket.drafts.Draft; 6 | import org.java_websocket.drafts.Draft_17; 7 | import org.java_websocket.handshake.ServerHandshake; 8 | import storj.io.restclient.model.FilePointer; 9 | 10 | import java.io.File; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.io.InputStream; 14 | import java.net.URI; 15 | import java.nio.ByteBuffer; 16 | import java.nio.channels.FileChannel; 17 | import java.time.LocalTime; 18 | import java.util.Map; 19 | import java.util.concurrent.CountDownLatch; 20 | import java.util.logging.Logger; 21 | 22 | /** 23 | * Created by steve on 12/07/2016. 24 | */ 25 | public class WebsocketFileRetriever extends WebSocketClient { 26 | 27 | private Logger logger = Logger.getLogger(this.getClass().getName()); 28 | private Gson gson = new Gson(); 29 | private FilePointer filePointer; 30 | private File outputFile; 31 | private AuthorizationModel authModel; 32 | private FileChannel channel; 33 | private CountDownLatch latch; 34 | 35 | public WebsocketFileRetriever(URI serverURI, FilePointer filePointer, File outputFile, CountDownLatch latch){ 36 | super(serverURI, new Draft_17(), null, 99999); 37 | this.filePointer = filePointer; 38 | this.outputFile = outputFile; 39 | authModel = new AuthorizationModel(); 40 | authModel.setToken(filePointer.getToken()); 41 | authModel.setOperation(filePointer.getOperation()); 42 | authModel.setHash(filePointer.getHash()); 43 | this.latch = latch; 44 | } 45 | 46 | public void onOpen(ServerHandshake serverHandshake) { 47 | logger.info("Connected to farmer."); 48 | ByteBuffer buffer = ByteBuffer.allocate(gson.toJson(authModel).getBytes().length); 49 | buffer.put(gson.toJson(authModel).getBytes()); 50 | send(gson.toJson(authModel)); 51 | 52 | try { 53 | outputFile.getParentFile().mkdirs(); 54 | outputFile.createNewFile(); 55 | channel = new FileOutputStream(outputFile, true).getChannel(); 56 | } catch (IOException e) { 57 | e.printStackTrace(); 58 | } 59 | } 60 | 61 | @Override 62 | public void onMessage(String s){ 63 | logger.info("Received text... " + s); 64 | } 65 | 66 | @Override 67 | public void onMessage(ByteBuffer b){ 68 | logger.info("Received binary... " + b); 69 | try { 70 | channel.write(b); 71 | } catch (IOException e) { 72 | e.printStackTrace(); 73 | } 74 | } 75 | 76 | @Override 77 | public void onClose(int i, String s, boolean b) { 78 | logger.info("Closing connection. " + i + s + b); 79 | try { 80 | channel.close(); 81 | latch.countDown(); 82 | } catch (IOException e) { 83 | e.printStackTrace(); 84 | } 85 | } 86 | 87 | public void onError(Exception e) { 88 | e.printStackTrace(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/encryption/AESFiles.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.encryption; 2 | 3 | import javax.crypto.Cipher; 4 | import javax.crypto.CipherInputStream; 5 | import javax.crypto.CipherOutputStream; 6 | import javax.crypto.spec.IvParameterSpec; 7 | import javax.crypto.spec.SecretKeySpec; 8 | import java.io.File; 9 | import java.io.FileInputStream; 10 | import java.io.FileOutputStream; 11 | 12 | class AESFiles { 13 | 14 | private byte[] getKeyBytes(final byte[] key) throws Exception { 15 | byte[] keyBytes = new byte[16]; 16 | System.arraycopy(key, 0, keyBytes, 0, Math.min(key.length, keyBytes.length)); 17 | return keyBytes; 18 | } 19 | 20 | private Cipher getCipherEncrypt(final byte[] key) throws Exception { 21 | byte[] keyBytes = getKeyBytes(key); 22 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 23 | SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); 24 | IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes); 25 | cipher.init(Cipher.ENCRYPT_MODE, secretKeySpec, ivParameterSpec); 26 | return cipher; 27 | } 28 | 29 | private Cipher getCipherDecrypt(byte[] key) throws Exception { 30 | byte[] keyBytes = getKeyBytes(key); 31 | Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); 32 | SecretKeySpec secretKeySpec = new SecretKeySpec(keyBytes, "AES"); 33 | IvParameterSpec ivParameterSpec = new IvParameterSpec(keyBytes); 34 | cipher.init(Cipher.DECRYPT_MODE, secretKeySpec, ivParameterSpec); 35 | return cipher; 36 | } 37 | 38 | public void encrypt(File inputFile, File outputFile, byte[] key) throws Exception { 39 | Cipher cipher = getCipherEncrypt(key); 40 | FileOutputStream fos = null; 41 | CipherOutputStream cos = null; 42 | FileInputStream fis = null; 43 | try { 44 | fis = new FileInputStream(inputFile); 45 | fos = new FileOutputStream(outputFile); 46 | cos = new CipherOutputStream(fos, cipher); 47 | byte[] data = new byte[1024]; 48 | int read = fis.read(data); 49 | while (read != -1) { 50 | cos.write(data, 0, read); 51 | read = fis.read(data); 52 | } 53 | cos.flush(); 54 | } finally { 55 | if (cos != null) { 56 | cos.close(); 57 | } 58 | if (fos != null) { 59 | fos.close(); 60 | } 61 | if (fis != null) { 62 | fis.close(); 63 | } 64 | } 65 | System.out.println("Encrypted SIZE " + outputFile.length()); 66 | 67 | } 68 | 69 | public void decrypt(File inputFile, File outputFile, byte[] key) throws Exception { 70 | long length = inputFile.length(); 71 | System.out.println("Size before decrypt " + length); 72 | Cipher cipher = getCipherDecrypt(key); 73 | FileOutputStream fos = null; 74 | CipherInputStream cis = null; 75 | FileInputStream fis = null; 76 | try { 77 | fis = new FileInputStream(inputFile); 78 | cis = new CipherInputStream(fis, cipher); 79 | fos = new FileOutputStream(outputFile); 80 | byte[] data = new byte[1024]; 81 | int read = cis.read(data); 82 | while (read != -1) { 83 | fos.write(data, 0, read); 84 | read = cis.read(data); 85 | } 86 | } finally { 87 | fos.close(); 88 | cis.close(); 89 | fis.close(); 90 | } 91 | } 92 | } -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/model/User.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.model; 2 | 3 | import com.google.common.hash.Hashing; 4 | import org.codehaus.jackson.annotate.JsonIgnore; 5 | import org.codehaus.jackson.map.annotate.JsonSerialize; 6 | 7 | import java.nio.charset.StandardCharsets; 8 | import java.util.Date; 9 | 10 | /** 11 | * Created by Stephen Nutbrown on 03/07/2016. 12 | */ 13 | @JsonSerialize(include= JsonSerialize.Inclusion.NON_NULL) 14 | public class User { 15 | 16 | private String email; 17 | private String password; 18 | private String redirect; 19 | private Long __nonce; 20 | @JsonIgnore 21 | private Preferences preferences; 22 | @JsonIgnore 23 | private boolean activated; 24 | private Date created; 25 | private String id; 26 | @JsonIgnore 27 | private String uuid; 28 | private String pubkey; 29 | @JsonIgnore 30 | private boolean isFreeTier; 31 | 32 | public String getUuid() { 33 | return uuid; 34 | } 35 | 36 | public void setUuid(String uuid) { 37 | this.uuid = uuid; 38 | } 39 | 40 | public boolean isIsFreeTier() { 41 | return isFreeTier; 42 | } 43 | 44 | public void setIsFreeTier(boolean freeTier) { 45 | isFreeTier = freeTier; 46 | } 47 | 48 | public Preferences getPreferences() { 49 | return preferences; 50 | } 51 | 52 | public void setPreferences(Preferences preferences) { 53 | this.preferences = preferences; 54 | } 55 | 56 | public String getPubkey() { 57 | return pubkey; 58 | } 59 | 60 | public void setPubkey(String pubkey) { 61 | this.pubkey = pubkey; 62 | } 63 | 64 | public boolean isActivated() { 65 | return activated; 66 | } 67 | 68 | public void setActivated(boolean activated) { 69 | this.activated = activated; 70 | } 71 | 72 | public String getPassword(){ 73 | return password; 74 | } 75 | 76 | public Date getCreated() { 77 | return created; 78 | } 79 | 80 | public void setCreated(Date created) { 81 | this.created = created; 82 | } 83 | 84 | public String getId() { 85 | return id; 86 | } 87 | 88 | public void setId(String id) { 89 | this.id = id; 90 | } 91 | 92 | public void setPassword(String password){ 93 | this.password = sha256Encrypt(password); 94 | } 95 | 96 | public String getEmail() { 97 | return email; 98 | } 99 | 100 | public void setEmail(String email) { 101 | this.email = email; 102 | } 103 | 104 | public String getRedirect() { 105 | return redirect; 106 | } 107 | 108 | public void setRedirect(String redirect) { 109 | this.redirect = redirect; 110 | } 111 | 112 | public Long get__nonce() { 113 | return __nonce; 114 | } 115 | 116 | public void set__nonce(Long __nonce) { 117 | this.__nonce = __nonce; 118 | } 119 | 120 | private String sha256Encrypt(String input){ 121 | return Hashing.sha256() 122 | .hashString(input, StandardCharsets.UTF_8) 123 | .toString(); 124 | } 125 | 126 | @Override 127 | public String toString() { 128 | return "User{" + 129 | "redirect='" + redirect + '\'' + 130 | ", __nonce=" + __nonce + 131 | ", activated=" + activated + 132 | ", created=" + created + 133 | ", id='" + id + '\'' + 134 | ", email='" + email + '\'' + 135 | '}'; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/StorjConfiguration.java: -------------------------------------------------------------------------------- 1 | package storj.io.client; 2 | 3 | import com.google.common.io.Files; 4 | import org.apache.commons.lang3.ObjectUtils; 5 | import storj.io.restclient.auth.AuthType; 6 | import storj.io.restclient.auth.BasicAuthType; 7 | import storj.io.restclient.auth.NoAuthType; 8 | 9 | import java.io.File; 10 | import java.util.logging.Logger; 11 | 12 | /** 13 | * Created by Stephen Nutbrown on 23/07/2016. 14 | */ 15 | public class StorjConfiguration { 16 | 17 | private Logger logger = Logger.getLogger(this.getClass().getName()); 18 | 19 | private AuthType auth = new NoAuthType(); 20 | 21 | private String encryptionKey; 22 | 23 | private int shardSizeInBytes = 1024*1024*8; 24 | 25 | private int retryRestAttempts = 4; 26 | 27 | private File tempDirectoryForShards = Files.createTempDir(); 28 | 29 | private String apiRoot = "https://api.storj.io"; 30 | 31 | /** 32 | * Create an unauthenticated storj client configuration. 33 | * @param encryptionKey the encryption key to use. 34 | */ 35 | public StorjConfiguration(String encryptionKey){ 36 | if(encryptionKey == null){ 37 | throw new RuntimeException("Encryption key required for encrypting and decrypting files."); 38 | } 39 | this.encryptionKey = encryptionKey; 40 | } 41 | 42 | /** 43 | * Create a storj client configuration with a predefined authentication type. 44 | * @param encryptionKey the encrption key to use. 45 | * @param auth the auth type. 46 | */ 47 | public StorjConfiguration(String encryptionKey, AuthType auth){ 48 | this(encryptionKey); 49 | this.auth = auth; 50 | } 51 | 52 | /** 53 | * Create a storj client configuration with basic authentication. 54 | * @param encryptionKey the encryption key to use. 55 | * @param username the username. 56 | * @param password the password 57 | */ 58 | public StorjConfiguration(String encryptionKey, String username, String password){ 59 | this(encryptionKey); 60 | setAuth(new BasicAuthType(username, password)); 61 | } 62 | 63 | public AuthType getAuth() { 64 | if(auth instanceof NoAuthType){ 65 | logger.info("No authentication strategy has been specified, only endpoints which do not require auth will work."); 66 | } 67 | return auth; 68 | } 69 | 70 | public void setAuth(AuthType auth) { 71 | this.auth = auth; 72 | } 73 | 74 | public Logger getLogger() { 75 | return logger; 76 | } 77 | 78 | public void setLogger(Logger logger) { 79 | this.logger = logger; 80 | } 81 | 82 | public String getApiRoot() { 83 | return apiRoot; 84 | } 85 | 86 | public void setApiRoot(String apiRoot) { 87 | this.apiRoot = apiRoot; 88 | } 89 | 90 | public String getEncryptionKey() { 91 | return encryptionKey; 92 | } 93 | 94 | public void setEncryptionKey(String encryptionKey) { 95 | this.encryptionKey = encryptionKey; 96 | } 97 | 98 | public int getShardSizeInBytes() { 99 | return shardSizeInBytes; 100 | } 101 | 102 | public void setShardSizeInBytes(int shardSizeInBytes) { 103 | this.shardSizeInBytes = shardSizeInBytes; 104 | } 105 | 106 | public int getRetryRestAttempts() { 107 | return retryRestAttempts; 108 | } 109 | 110 | public void setRetryRestAttempts(int retryRestAttempts) { 111 | this.retryRestAttempts = retryRestAttempts; 112 | } 113 | 114 | public File getTempDirectoryForShards() { 115 | return tempDirectoryForShards; 116 | } 117 | 118 | public void setTempDirectoryForShards(File tempDirectoryForShards) { 119 | if(tempDirectoryForShards == null || !tempDirectoryForShards.isDirectory() || !tempDirectoryForShards.canWrite()){ 120 | throw new RuntimeException("Temp directory must be readable, writable and a directory not a file."); 121 | } 122 | this.tempDirectoryForShards = tempDirectoryForShards; 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/StorjClient.java: -------------------------------------------------------------------------------- 1 | package storj.io.client; 2 | 3 | import storj.io.restclient.model.Bucket; 4 | import storj.io.restclient.model.BucketEntry; 5 | import storj.io.restclient.model.User; 6 | 7 | import java.io.File; 8 | import java.util.List; 9 | 10 | /** 11 | * Created by steve on 03/08/2016. 12 | */ 13 | public interface StorjClient { 14 | /** 15 | * Set the storj configuration. 16 | * 17 | * @param configuration the storj configuration to set. 18 | */ 19 | void setConfiguration(StorjConfiguration configuration); 20 | 21 | /** 22 | * Return the configuration of this storj.io.client.DefaultStorjClient client. 23 | * 24 | * @return the storj client configuration. 25 | */ 26 | StorjConfiguration getConguration(); 27 | 28 | /** 29 | * Upload a file 30 | * 31 | * @param inputFile the file to upload. 32 | * @param bucketId the ID of the bucket to upload to. 33 | * @return A bucket entry representing the file on the bridge. 34 | * @throws Exception Problem uploading file. 35 | */ 36 | BucketEntry uploadFile(File inputFile, String bucketId) throws Exception; 37 | 38 | /** 39 | * Upload a file to the storj network. 40 | * 41 | * @param file the file to upload. 42 | * @param bucket the bucket to upload to. 43 | * @return a bucket entry representing the file stored on the bridge. 44 | * @throws Exception problem uploading file. 45 | */ 46 | BucketEntry uploadFile(File file, Bucket bucket) throws Exception; 47 | 48 | /** 49 | * Download a file into the temp directory specified in the storj.io.client.StorjConfiguration. 50 | * This call takes care of retrieving the file shards and piecing the file back together. 51 | * 52 | * @param bucketEntry the Bucket entry to retrieve. 53 | * @return A file pointer to the retrieved file. 54 | */ 55 | File downloadFile(BucketEntry bucketEntry, File outputFile); 56 | 57 | /** 58 | * Download a file into the temp directory specified in the storj.io.client.StorjConfiguration. 59 | * This call takes care of retrieving the file shards and piecing the file back together. 60 | * 61 | * @param bucketId the ID of the bucket. 62 | * @param bucketEntryId the ID of the bucketEntry 63 | * @param outputFile The file to output to. 64 | * @return A file pointer to the retrieved file. 65 | */ 66 | File downloadFile(String bucketId, String bucketEntryId, File outputFile); 67 | 68 | /** 69 | * Get all buckets. 70 | * 71 | * @return all buckets for the user. 72 | */ 73 | List listBuckets(); 74 | 75 | /** 76 | * Get a bucket by it's ID. 77 | * 78 | * @param bucketId the bucket ID. 79 | * @return the bucket. 80 | */ 81 | Bucket getBucket(String bucketId); 82 | 83 | /** 84 | * Create a bucket. 85 | * 86 | * @param bucketName the name of the bucket to create. 87 | * @return the created bucket. 88 | */ 89 | Bucket createBucket(String bucketName); 90 | 91 | /** 92 | * Delete a bucket. 93 | * 94 | * @param buckeId the ID of the bucket to delete. 95 | */ 96 | void deleteBucket(String buckeId); 97 | 98 | /** 99 | * Deletes a bucket. 100 | * 101 | * @param bucket the bucket to delete. 102 | */ 103 | void deleteBucket(Bucket bucket); 104 | 105 | /** 106 | * Request a password reset email. 107 | * 108 | * @param emailAddress the email address of the account to reset. 109 | */ 110 | void resetPassword(String emailAddress); 111 | 112 | /** 113 | * Request a password reset email. 114 | * 115 | * @param user the user account to reset. 116 | */ 117 | void resetPassword(User user); 118 | 119 | /** 120 | * Create a user. Warning: The users account will need verifying before using. 121 | * 122 | * @param email the email address of the user. 123 | * @param password the password of the user. 124 | * @return An object from the bridge representing a user. 125 | */ 126 | User createUser(String email, String password); 127 | 128 | /** 129 | * Get a list of files stored in a bucket. 130 | * 131 | * @param bucketId the ID of the bucket. 132 | * @return the files stored in the bucket. 133 | */ 134 | List listFiles(String bucketId); 135 | 136 | /** 137 | * Delete a file. 138 | * 139 | * @param bucketId The bucket ID the file lives in. 140 | * @param fileId the file ID. 141 | */ 142 | void deleteFile(String bucketId, String fileId); 143 | 144 | } 145 | 146 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/sharding/ShardingUtils.java: -------------------------------------------------------------------------------- 1 | package storj.io.client.sharding; 2 | 3 | import com.google.common.base.Charsets; 4 | import com.google.common.primitives.Bytes; 5 | import org.bouncycastle.util.encoders.Hex; 6 | import storj.io.client.encryption.EncryptionUtils; 7 | import storj.io.restclient.model.Shard; 8 | 9 | import java.io.File; 10 | import java.io.FileInputStream; 11 | import java.io.FileOutputStream; 12 | import java.io.IOException; 13 | import java.util.ArrayList; 14 | import java.util.Arrays; 15 | import java.util.List; 16 | import java.util.Random; 17 | 18 | import static java.nio.file.Files.readAllBytes; 19 | 20 | /** 21 | * Created by Stephen Nutbrown on 09/07/2016. 22 | */ 23 | public class ShardingUtils { 24 | 25 | /** 26 | * Utility method to split a file into several shards. 27 | * @param input the file to split into shards. 28 | * @param shardSize the size (in bytes) the shards should be. 29 | * @return the shards. 30 | * @throws Exception problem sharding the file. 31 | */ 32 | public static List shardFile(File input, int shardSize) throws Exception { 33 | ArrayList shards = new ArrayList(); 34 | 35 | int numChallenges = 8; 36 | 37 | FileInputStream inputStream = new FileInputStream(input); 38 | byte[] buffer = new byte[shardSize]; 39 | int length; 40 | int shardIndex = 0; 41 | int index = 0; 42 | // read file, one "buffer" at a time. The buffer is set to the shard size 43 | // So each read is 1 shard :). 44 | while ((length = inputStream.read(buffer)) > 0){ 45 | 46 | // Write the file 47 | File fileShard = File.createTempFile("shard",".shard"); 48 | FileOutputStream out = new FileOutputStream(fileShard); 49 | out.write(buffer, 0, length); 50 | out.close(); 51 | 52 | // create shard object pointing to the file. 53 | Shard shard = new Shard(); 54 | shard.setSize(fileShard.length()); 55 | shard.setHash(new String(EncryptionUtils.getRipemdSha256File(fileShard))); 56 | shard.setPath(fileShard.getAbsolutePath()); 57 | shard.setIndex(index++); 58 | addChallenges(shard, buffer, numChallenges); 59 | 60 | shard.setIndex(shardIndex++); 61 | shards.add(shard); 62 | } 63 | return shards; 64 | } 65 | 66 | /** 67 | * Create challenges for a shard. 68 | * @param shard the shard to create challenges for. 69 | * @param shardData the data contained in the shard. 70 | * @param numberOfChallenges the number of challenges. 71 | */ 72 | public static void addChallenges(Shard shard, byte[] shardData, int numberOfChallenges){ 73 | for(int i = 0; i< numberOfChallenges; i++) { 74 | String randomChallenge = getRandomChallengeString(); 75 | byte[] challengeBytes = randomChallenge.getBytes(Charsets.UTF_8); 76 | 77 | // trim empty space at the end of shardData. 78 | shardData = Arrays.copyOf(shardData, (int)shard.getSize()); 79 | 80 | // Data to hash = challenge + shard data. 81 | byte[] dataToHash = Hex.encode(Bytes.concat(challengeBytes, shardData)); 82 | 83 | // RMD160(SHA256(RMD160(SHA256(challenge + shard)))) 84 | byte[] tree = EncryptionUtils.rmd160Sha256(EncryptionUtils.rmd160Sha256(dataToHash)); 85 | 86 | shard.getChallenges().add(randomChallenge); 87 | shard.getTree().add(new String(tree)); 88 | } 89 | } 90 | 91 | /** 92 | * Creates a random 32 byte string. 93 | * @return a random 32 byte string. 94 | */ 95 | public static String getRandomChallengeString(){ 96 | int numChars = 32; 97 | 98 | Random r = new Random(); 99 | StringBuffer sb = new StringBuffer(); 100 | while(sb.length() < numChars){ 101 | sb.append(Integer.toHexString(r.nextInt())); 102 | } 103 | return sb.toString().substring(0, numChars); 104 | } 105 | 106 | /** 107 | * Take several shards and put them back together into one file. 108 | * Note this does not decrypt the file. 109 | * @param shards the shards. 110 | * @param destination the destination to put the combined file. 111 | * @throws IOException Problem reading/writing. 112 | */ 113 | public static void pieceTogetherFile(List shards, File destination) throws IOException { 114 | FileOutputStream outputStream = new FileOutputStream(destination); 115 | for(File shard : shards) { 116 | byte[] shardBytes = readAllBytes(shard.toPath()); 117 | outputStream.write(shardBytes); 118 | } 119 | outputStream.close(); 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/PasswordInputDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. 3 | * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. 4 | * 5 | * 6 | * 7 | * 8 | * 9 | * 10 | * 11 | * 12 | * 13 | * 14 | * 15 | * 16 | * 17 | * 18 | * 19 | * 20 | * 21 | * 22 | * 23 | * 24 | */ 25 | 26 | package sample; 27 | 28 | import com.sun.javafx.scene.control.skin.resources.ControlResources; 29 | import javafx.application.Platform; 30 | import javafx.beans.NamedArg; 31 | import javafx.geometry.Pos; 32 | import javafx.scene.control.*; 33 | import javafx.scene.control.ButtonBar.ButtonData; 34 | import javafx.scene.layout.GridPane; 35 | import javafx.scene.layout.Priority; 36 | import javafx.scene.layout.Region; 37 | 38 | /** 39 | * A dialog that shows a text input control to the user. 40 | * 41 | * @see Dialog 42 | * @since JavaFX 8u40 43 | */ 44 | public class PasswordInputDialog extends Dialog { 45 | 46 | /************************************************************************** 47 | * 48 | * Fields 49 | * 50 | **************************************************************************/ 51 | 52 | private final GridPane grid; 53 | private final Label label; 54 | private final TextField textField; 55 | private final String defaultValue; 56 | 57 | 58 | 59 | /************************************************************************** 60 | * 61 | * Constructors 62 | * 63 | **************************************************************************/ 64 | 65 | /** 66 | * Creates a new TextInputDialog without a default value entered into the 67 | * dialog {@link TextField}. 68 | */ 69 | public PasswordInputDialog() { 70 | this(""); 71 | } 72 | 73 | /** 74 | * Creates a new TextInputDialog with the default value entered into the 75 | * dialog {@link TextField}. 76 | */ 77 | public PasswordInputDialog(@NamedArg("defaultValue") String defaultValue) { 78 | final DialogPane dialogPane = getDialogPane(); 79 | 80 | // -- textfield 81 | this.textField = new PasswordField(); 82 | this.textField.setMaxWidth(Double.MAX_VALUE); 83 | GridPane.setHgrow(textField, Priority.ALWAYS); 84 | GridPane.setFillWidth(textField, true); 85 | 86 | // -- label 87 | label = createContentLabel(dialogPane.getContentText()); 88 | label.setPrefWidth(Region.USE_COMPUTED_SIZE); 89 | label.textProperty().bind(dialogPane.contentTextProperty()); 90 | 91 | this.defaultValue = defaultValue; 92 | 93 | this.grid = new GridPane(); 94 | this.grid.setHgap(10); 95 | this.grid.setMaxWidth(Double.MAX_VALUE); 96 | this.grid.setAlignment(Pos.CENTER_LEFT); 97 | 98 | dialogPane.contentTextProperty().addListener(o -> updateGrid()); 99 | 100 | setTitle(ControlResources.getString("Dialog.confirm.title")); 101 | dialogPane.setHeaderText(ControlResources.getString("Dialog.confirm.header")); 102 | dialogPane.getStyleClass().add("text-input-dialog"); 103 | dialogPane.getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL); 104 | 105 | updateGrid(); 106 | 107 | setResultConverter((dialogButton) -> { 108 | ButtonData data = dialogButton == null ? null : dialogButton.getButtonData(); 109 | return data == ButtonData.OK_DONE ? textField.getText() : null; 110 | }); 111 | } 112 | 113 | /** 114 | * Creates a Label node that works well within a Dialog. 115 | * @param text The text to display 116 | */ 117 | static Label createContentLabel(String text) { 118 | Label label = new Label(text); 119 | label.setMaxWidth(Double.MAX_VALUE); 120 | label.setMaxHeight(Double.MAX_VALUE); 121 | label.getStyleClass().add("content"); 122 | label.setWrapText(true); 123 | label.setPrefWidth(360); 124 | return label; 125 | } 126 | 127 | 128 | 129 | /************************************************************************** 130 | * 131 | * Public API 132 | * 133 | **************************************************************************/ 134 | 135 | /** 136 | * Returns the {@link TextField} used within this dialog. 137 | */ 138 | public final TextField getEditor() { 139 | return textField; 140 | } 141 | 142 | /** 143 | * Returns the default value that was specified in the constructor. 144 | */ 145 | public final String getDefaultValue() { 146 | return defaultValue; 147 | } 148 | 149 | 150 | 151 | /************************************************************************** 152 | * 153 | * Private Implementation 154 | * 155 | **************************************************************************/ 156 | 157 | private void updateGrid() { 158 | grid.getChildren().clear(); 159 | 160 | grid.add(label, 0, 0); 161 | grid.add(textField, 1, 0); 162 | getDialogPane().setContent(grid); 163 | 164 | Platform.runLater(() -> textField.requestFocus()); 165 | } 166 | } 167 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/resources/layout.fxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 84 | 89 | 94 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /storj-client/src/main/java/storj/io/client/DefaultStorjClient.java: -------------------------------------------------------------------------------- 1 | package storj.io.client; 2 | 3 | 4 | import storj.io.client.encryption.EncryptionUtils; 5 | import storj.io.client.sharding.ShardingUtils; 6 | import storj.io.client.websockets.WebsocketFileRetriever; 7 | import storj.io.client.websockets.WebsocketShardSender; 8 | import storj.io.restclient.model.*; 9 | import storj.io.restclient.rest.StorjRestClient; 10 | 11 | import java.io.File; 12 | import java.io.IOException; 13 | import java.net.URI; 14 | import java.nio.file.Files; 15 | import java.util.List; 16 | import java.util.concurrent.CountDownLatch; 17 | import java.util.logging.Logger; 18 | 19 | 20 | /** 21 | * Created by Stephen Nutbrown on 23/07/2016. 22 | */ 23 | public class DefaultStorjClient implements StorjClient { 24 | 25 | private Logger logger = Logger.getLogger(this.getClass().getName()); 26 | 27 | StorjConfiguration config; 28 | StorjRestClient storjRestClient; 29 | 30 | /** 31 | * Construct a storj.io.client.DefaultStorjClient client using the config. 32 | * @param config the config for the client. 33 | */ 34 | public DefaultStorjClient(StorjConfiguration config) { 35 | this.config = config; 36 | storjRestClient = new StorjRestClient(config.getApiRoot(), config.getAuth()); 37 | } 38 | 39 | public void setConfiguration(StorjConfiguration configuration) { 40 | this.config = configuration; 41 | } 42 | 43 | public StorjConfiguration getConguration() { 44 | return config; 45 | } 46 | 47 | public BucketEntry uploadFile(File inputFile, String bucketId) throws Exception { 48 | 49 | String encryptionPassword = config.getEncryptionKey(); 50 | 51 | // TODO: neaten this. 52 | File encryptedFile = new File(config.getTempDirectoryForShards().getPath()+ "/" + inputFile.getName()+ ".encrypted"); 53 | 54 | // Create encrypted file. 55 | EncryptionUtils.encryptFile(inputFile, encryptedFile, encryptionPassword); 56 | 57 | // Shard the file. 58 | List shards = ShardingUtils.shardFile(encryptedFile, config.getShardSizeInBytes()); 59 | 60 | // create a frame. 61 | Frame frame = storjRestClient.createFrame(); 62 | 63 | // upload shards. 64 | for (Shard shard : shards) { 65 | AddShardResponse response = storjRestClient.addShardToFrame(frame.getId(), shard, 8); 66 | 67 | String address = "ws://" + response.getFarmer().getAddress() + ":" + response.getFarmer().getPort(); 68 | CountDownLatch latch; 69 | latch = new CountDownLatch(1); 70 | try { 71 | WebsocketShardSender sender = new WebsocketShardSender(new URI(address), shard, response, latch); 72 | sender.connect(); 73 | latch.await(); 74 | } catch (Exception e) { 75 | throw new RuntimeException(e); 76 | } finally { 77 | // clean up shard files.. 78 | File shardFile = new File(shard.getPath()); 79 | shardFile.delete(); 80 | } 81 | } 82 | 83 | // Create the bucket entry. 84 | BucketEntry bucketEntry = new BucketEntry(); 85 | // Library for getting mime type (Should work on linux which Files.probe won't always). 86 | bucketEntry.setMimetype(Files.probeContentType(inputFile.toPath())); 87 | bucketEntry.setFilename(inputFile.getName()); 88 | bucketEntry.setFrame(frame.getId()); 89 | bucketEntry.setSize(encryptedFile.length()); 90 | 91 | // clean up encrypted file 92 | encryptedFile.delete(); 93 | 94 | // store the bucket entry. 95 | return storjRestClient.storeFile(bucketId, bucketEntry); 96 | 97 | } 98 | 99 | public BucketEntry uploadFile(File file, Bucket bucket) throws Exception { 100 | return uploadFile(file, bucket.getId()); 101 | } 102 | 103 | public void deleteFile(String bucketId, String fileId){ 104 | storjRestClient.destroyFileEntry(bucketId, fileId); 105 | } 106 | 107 | public File downloadFile(BucketEntry bucketEntry, File outputFile) { 108 | return downloadFile(bucketEntry.getBucket(), bucketEntry.getId(), outputFile); 109 | } 110 | 111 | public File downloadFile(String bucketId, String bucketEntryId, File outputFile) { 112 | File encryptedOutputFile = null; 113 | try { 114 | encryptedOutputFile = File.createTempFile("temp","encrypted"); 115 | } catch (IOException e) { 116 | e.printStackTrace(); 117 | } 118 | 119 | Token token = storjRestClient.getTokenForBucket(bucketId, Operation.PULL); 120 | List pointers = storjRestClient.getFilePointers(bucketId, bucketEntryId, token.getToken()); 121 | 122 | // download shards. 123 | for (FilePointer pointer : pointers) { 124 | try { 125 | CountDownLatch latch = new CountDownLatch(1); 126 | String farmer = "ws://" + pointer.getFarmer().getAddress() + ":" + pointer.getFarmer().getPort(); 127 | WebsocketFileRetriever c = new WebsocketFileRetriever(new URI(farmer), pointer, encryptedOutputFile, latch); 128 | c.connect(); 129 | latch.await(); 130 | } catch (Exception e) { 131 | throw new RuntimeException(e); 132 | } 133 | } 134 | 135 | try { 136 | logger.info("Encrypted file: " + encryptedOutputFile.getAbsolutePath()); 137 | EncryptionUtils.decryptFile(encryptedOutputFile, outputFile, config.getEncryptionKey()); 138 | logger.info("Decrypted file: " + outputFile.getAbsolutePath()); 139 | 140 | } catch (Exception e) { 141 | e.printStackTrace(); 142 | } 143 | 144 | System.out.println(outputFile.getPath()); 145 | 146 | return outputFile; 147 | } 148 | 149 | public List listBuckets() { 150 | return storjRestClient.getAllBuckets(); 151 | } 152 | 153 | public Bucket getBucket(String bucketId) { 154 | return storjRestClient.getBucketById(bucketId); 155 | } 156 | 157 | public Bucket createBucket(String bucketName) { 158 | Bucket bucket = new Bucket(); 159 | bucket.setName(bucketName); 160 | return storjRestClient.createBucket(bucket); 161 | } 162 | 163 | public void deleteBucket(String buckeId) { 164 | storjRestClient.deleteBucket(buckeId); 165 | } 166 | 167 | public void deleteBucket(Bucket bucket) { 168 | deleteBucket(bucket.getId()); 169 | } 170 | 171 | public void resetPassword(String emailAddress) { 172 | storjRestClient.resetPassword(emailAddress); 173 | } 174 | 175 | public void resetPassword(User user) { 176 | resetPassword(user.getEmail()); 177 | } 178 | 179 | public User createUser(String email, String password) { 180 | User user = new User(); 181 | user.setEmail(email); 182 | user.setPassword(password); 183 | return storjRestClient.createUser(user); 184 | } 185 | 186 | public List listFiles(String bucketId) { 187 | return storjRestClient.getFilesInBucket(bucketId); 188 | } 189 | } 190 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/test/java/storj/io/restclient/rest/StorjRestClientTest.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.rest; 2 | 3 | import com.github.kristofa.test.http.Method; 4 | import com.github.kristofa.test.http.MockHttpServer; 5 | import com.github.kristofa.test.http.SimpleHttpResponseProvider; 6 | import com.github.kristofa.test.http.UnsatisfiedExpectationException; 7 | import com.github.kristofa.test.http.client.HttpClient; 8 | import org.apache.commons.lang3.StringUtils; 9 | import org.apache.http.protocol.HTTP; 10 | import org.apache.log4j.BasicConfigurator; 11 | import org.junit.*; 12 | import org.junit.Assert.*; 13 | import storj.io.restclient.auth.BasicAuthType; 14 | import storj.io.restclient.auth.NoAuthType; 15 | import storj.io.restclient.model.Bucket; 16 | import storj.io.restclient.model.User; 17 | import org.junit.Assume.*; 18 | 19 | import javax.ws.rs.core.MediaType; 20 | 21 | import java.util.List; 22 | import java.util.Random; 23 | 24 | import static junit.framework.TestCase.assertEquals; 25 | import static org.junit.Assert.assertFalse; 26 | import static org.junit.Assert.assertNotNull; 27 | 28 | /** 29 | * Created by Stephen Nutbrown on 03/07/2016. 30 | */ 31 | public class StorjRestClientTest { 32 | 33 | /** 34 | * To also run tests against a live server (Requires active internet connection and access to storj bridge, 35 | * set these properties. 36 | */ 37 | private static final boolean TEST_AGAINST_LIVE_SERVER = true; 38 | private static final String TEST_LIVE_PASSWORD = "pass"; 39 | private static final String TEST_LIVE_USERNAME = "user"; 40 | private static final String TEST_LIVE_API_ROOT = "https://api.storj.io"; 41 | 42 | // Mock server. 43 | private MockHttpServer server; 44 | private SimpleHttpResponseProvider responseProvider; 45 | 46 | // Clients under test. 47 | private StorjRestClient noAuthClient; 48 | private StorjRestClient basicAuthClient; 49 | private StorjRestClient noAuthLiveClient; 50 | private StorjRestClient basicAuthLiveClient; 51 | 52 | // Storj API root. 53 | private static final int PORT = 51234; 54 | 55 | // Contact end points 56 | private static final String storjApiContacts = "/contacts"; 57 | 58 | // User end points. 59 | private static final String storjApiUsers = "/users"; 60 | private static final String storjApiUsersPassReset = "/resets"; 61 | private static final String storjApiUsersActivate = "/activations"; 62 | private static final String storjApiUsersDeactivate = "/deactivations"; 63 | private static final String storjApiKeys = "/keys"; 64 | private static final String storjApiFrames = "/frames"; 65 | private static final String storjApiBuckets = "/buckets"; 66 | 67 | @Before 68 | public void before() throws Exception { 69 | // Configure logger. 70 | BasicConfigurator.configure(); 71 | 72 | // Start mock server. 73 | responseProvider = new SimpleHttpResponseProvider(); 74 | server = new MockHttpServer(PORT, responseProvider); 75 | server.start(); 76 | 77 | // Create clients to test against mock server. 78 | String apiRootForClient = "http://localhost:" + PORT; 79 | noAuthClient = new StorjRestClient(apiRootForClient, new NoAuthType()); 80 | basicAuthClient = new StorjRestClient(apiRootForClient, new BasicAuthType("user", "pass")); 81 | 82 | // Create clients to test against LIVE server 83 | if(TEST_AGAINST_LIVE_SERVER) { 84 | noAuthLiveClient = new StorjRestClient(TEST_LIVE_API_ROOT, new NoAuthType()); 85 | basicAuthLiveClient = new StorjRestClient(TEST_LIVE_API_ROOT, new BasicAuthType(TEST_LIVE_USERNAME, TEST_LIVE_PASSWORD)); 86 | } 87 | } 88 | 89 | @After 90 | public void tearDown() throws Exception { 91 | server.stop(); 92 | } 93 | 94 | 95 | @Test 96 | public void getContacts() throws Exception { 97 | 98 | } 99 | 100 | @Test 101 | public void getContact() throws Exception { 102 | 103 | } 104 | 105 | 106 | @Test 107 | public void deleteUser() throws Exception { 108 | 109 | } 110 | 111 | @Test 112 | public void resetPassword() throws Exception { 113 | 114 | } 115 | 116 | @Test 117 | public void confirmPasswordReset() throws Exception { 118 | 119 | } 120 | 121 | @Test 122 | public void activateRegisteredUser() throws Exception { 123 | 124 | } 125 | 126 | @Test 127 | public void deactivateRegisteredUser() throws Exception { 128 | 129 | } 130 | 131 | @Test 132 | public void ecdsaKeyGetAll() throws Exception { 133 | 134 | } 135 | 136 | @Test 137 | public void ecdsaKeyRegister() throws Exception { 138 | 139 | } 140 | 141 | @Test 142 | public void ecdsaKeyDestroy() throws Exception { 143 | 144 | } 145 | 146 | @Test 147 | public void getFrames() throws Exception { 148 | 149 | } 150 | 151 | @Test 152 | public void createFrame() throws Exception { 153 | 154 | } 155 | 156 | @Test 157 | public void destroyFrame() throws Exception { 158 | 159 | } 160 | 161 | @Test 162 | public void getFrameById() throws Exception { 163 | 164 | } 165 | 166 | @Test 167 | public void addShardToFrame() throws Exception { 168 | 169 | } 170 | 171 | @Test 172 | public void createBucket() throws Exception { 173 | String mockResponse = "{\"user\":\"test@test.com\",\"created\":\"2016-07-30T21:40:05.012Z\",\"name\":\"testy\",\"pubkeys\":[],\"status\":\"Active\",\"transfer\":0,\"storage\":0,\"id\":\"123456\"}"; 174 | String requestBody = "{\"storage\":0,\"transfer\":0,\"status\":null,\"pubkeys\":null,\"user\":null,\"name\":\"testy\",\"created\":null,\"id\":null}"; 175 | 176 | responseProvider.expect(Method.POST, storjApiBuckets, MediaType.APPLICATION_JSON, requestBody).respondWith(201, MediaType.APPLICATION_JSON, mockResponse); 177 | Bucket bucketToCreate = new Bucket(); 178 | String name = "testy"; 179 | bucketToCreate.setName(name); 180 | 181 | Bucket createdBucket = basicAuthClient.createBucket(bucketToCreate); 182 | assertEquals(name, createdBucket.getName()); 183 | assertEquals("test@test.com", createdBucket.getUser()); 184 | assertEquals(0, createdBucket.getTransfer()); 185 | assertEquals("123456", createdBucket.getId()); 186 | responseProvider.verify(); 187 | 188 | } 189 | 190 | @Test 191 | public void deleteBucket() throws Exception { 192 | 193 | } 194 | 195 | @Test 196 | public void getBucketById() throws Exception { 197 | 198 | } 199 | 200 | @Test 201 | public void updateBucket() throws Exception { 202 | 203 | } 204 | 205 | @Test 206 | public void getTokenForBucket() throws Exception { 207 | 208 | } 209 | 210 | @Test 211 | public void getFilesInBucket() throws Exception { 212 | 213 | } 214 | 215 | @Test 216 | public void storeFile() throws Exception { 217 | 218 | } 219 | 220 | @Test 221 | public void destroyFileEntry() throws Exception { 222 | 223 | } 224 | 225 | @Test 226 | public void getFilePointers() throws Exception { 227 | 228 | } 229 | 230 | @Test 231 | public void createUser() throws UnsatisfiedExpectationException { 232 | String expectedContentType = MediaType.APPLICATION_JSON; 233 | String email = "testemail@test.com"; 234 | String password = "testpassword"; 235 | 236 | String expectedRequestBody = "{\"email\":\"testemail@test.com\",\"password\":\"9f735e0df9a1ddc702bf0a1a7b83033f9f7153a00c29de82cedadc9957289b05\"}"; 237 | String mockResponse = "{\"activated\":false,\"created\":\"2016-07-24T09:11:53.604Z\",\"email\":\"testemail@test.com\",\"id\":\"testemail@test.com\"}"; 238 | 239 | responseProvider.expect(Method.POST, storjApiUsers, MediaType.APPLICATION_JSON, expectedRequestBody).respondWith(201, MediaType.APPLICATION_JSON, mockResponse); 240 | 241 | // Set up user model. 242 | User user = new User(); 243 | user.setEmail(email); 244 | user.setPassword(password); 245 | 246 | // create 247 | User responseUser = noAuthClient.createUser(user); 248 | 249 | // check only expected requests were received. 250 | server.verify(); 251 | 252 | assertEquals(email, responseUser.getEmail()); 253 | assertFalse(responseUser.isActivated()); 254 | assertEquals(email, responseUser.getEmail()); 255 | } 256 | 257 | @Test 258 | public void getAllBuckets() { 259 | String mockResponse = "[{\"user\":\"test@test.com\",\"created\":\"2016-07-23T08:43:00.253Z\",\"name\":\"TestBucket\",\"pubkeys\":[],\"status\":\"Active\",\"transfer\":0,\"storage\":0,\"id\":\"1234\"}]"; 260 | responseProvider.expect(Method.GET, storjApiBuckets).respondWith(200, MediaType.APPLICATION_JSON, mockResponse); 261 | 262 | List response = basicAuthClient.getAllBuckets(); 263 | assertEquals(1, response.size()); 264 | 265 | Bucket bucket = response.get(0); 266 | assertEquals("test@test.com", bucket.getUser()); 267 | assertEquals("2016-07-23T08:43:00.253Z", bucket.getCreated()); 268 | assertEquals("TestBucket", bucket.getName()); 269 | assertEquals("Active", bucket.getStatus()); 270 | assertEquals("1234", bucket.getId()); 271 | assertEquals(0, bucket.getTransfer()); 272 | assertEquals(0, bucket.getStorage()); 273 | } 274 | 275 | @Test 276 | public void liveTestCreateUser(){ 277 | Assume.assumeTrue(TEST_AGAINST_LIVE_SERVER); 278 | 279 | // Set up test user. 280 | Random rn = new Random(); 281 | int randomNumber = rn.nextInt(5000); 282 | String emailAddress = randomNumber + "" + System.currentTimeMillis() + "@notreal.com"; 283 | User user = new User(); 284 | user.setEmail(emailAddress); 285 | user.setPassword("TestPassword"); 286 | 287 | // Send request. 288 | User createdUser = noAuthLiveClient.createUser(user); 289 | 290 | // Check created user object. 291 | assertEquals(emailAddress, createdUser.getEmail()); 292 | assertFalse(StringUtils.isEmpty(createdUser.getId())); 293 | assertNotNull(createdUser.getCreated()); 294 | assertFalse(createdUser.isActivated()); 295 | } 296 | } 297 | -------------------------------------------------------------------------------- /storj-bridge-rest-client/src/main/java/storj/io/restclient/rest/StorjRestClient.java: -------------------------------------------------------------------------------- 1 | package storj.io.restclient.rest; 2 | 3 | import com.sun.jersey.api.client.Client; 4 | import com.sun.jersey.api.client.GenericType; 5 | import com.sun.jersey.api.client.WebResource; 6 | import com.sun.jersey.api.client.config.ClientConfig; 7 | import com.sun.jersey.api.client.config.DefaultClientConfig; 8 | import com.sun.jersey.api.client.filter.LoggingFilter; 9 | import com.sun.jersey.api.json.JSONConfiguration; 10 | import com.sun.jersey.client.urlconnection.URLConnectionClientHandler; 11 | import org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider; 12 | import org.codehaus.jackson.jaxrs.JacksonJsonProvider; 13 | import org.codehaus.jackson.map.DeserializationConfig; 14 | import storj.io.restclient.model.*; 15 | import storj.io.restclient.auth.AuthType; 16 | import storj.io.restclient.auth.BasicAuthType; 17 | import storj.io.restclient.auth.NoAuthType; 18 | 19 | import javax.ws.rs.core.MediaType; 20 | 21 | import java.util.HashMap; 22 | import java.util.List; 23 | import java.util.Map; 24 | import java.util.logging.Logger; 25 | 26 | /** 27 | * Created by Stephen Nutbrown on 03/07/2016. 28 | */ 29 | public class StorjRestClient { 30 | 31 | // Storj API root. 32 | private static String apiRoot; 33 | 34 | // Contact end points 35 | private String storjApiContacts; 36 | 37 | // User end points. 38 | private String storjApiUsers; 39 | private String storjApiUsersPassReset; 40 | private String storjApiUsersActivate; 41 | private String storjApiUsersDeactivate; 42 | 43 | // Keys 44 | private String storjApiKeys = apiRoot + "/keys"; 45 | 46 | // Frames 47 | private String storjApiFrames = apiRoot + "/frames"; 48 | 49 | // Buckets 50 | private String storjApiBuckets = apiRoot + "/buckets"; 51 | 52 | private Client jerseyClient; 53 | 54 | private static final String INCOMING_MEDIA_TYPE = MediaType.APPLICATION_JSON; 55 | private static final String OUTGOING_MEDIA_TYPE = MediaType.APPLICATION_JSON; 56 | 57 | private Logger logger = Logger.getLogger(this.getClass().getName()); 58 | 59 | 60 | /** 61 | * AuthType represents the type of authentication used for the storj API. 62 | * Currently can be NoAuthType, BasicAuthType or ECDSA auth type. 63 | */ 64 | private AuthType auth; 65 | 66 | /** 67 | * Create a storj restclient. 68 | */ 69 | public StorjRestClient(String apiRoot, AuthType authType) { 70 | setApiRoot(apiRoot); 71 | this.auth = authType; 72 | configureJersey(); 73 | } 74 | 75 | private void setApiRoot(String apiRoot) { 76 | this.apiRoot = apiRoot; 77 | storjApiContacts = apiRoot + "/contacts"; 78 | storjApiUsers = apiRoot + "/users"; 79 | storjApiUsersPassReset = storjApiUsers + "/resets"; 80 | storjApiUsersActivate = apiRoot + "/activations"; 81 | storjApiUsersDeactivate = storjApiUsers + "/deactivations"; 82 | storjApiKeys = apiRoot + "/keys"; 83 | storjApiFrames = apiRoot + "/frames"; 84 | storjApiBuckets = apiRoot + "/buckets"; 85 | } 86 | 87 | /** 88 | * Retrieve a page of contacts from the API 89 | * 90 | * @param pagination 91 | * The pagination indicator. 92 | * @param connected 93 | * Filter results by connection status. 94 | * @return A page of contacts. 95 | */ 96 | public List getContacts(int pagination, boolean connected) { 97 | String queryParamPage = "page=" + pagination; 98 | String queryParamConnected = connected ? "connected=1" : "connected=0"; 99 | String requestUrl = storjApiContacts + "?" + queryParamPage + "&" + queryParamConnected; 100 | return getBuilder(requestUrl).get(new GenericType>() { 101 | }); 102 | } 103 | 104 | /** 105 | * Retrieve a page of contacts from the API 106 | * 107 | * @param nodeID 108 | * Node ID of the contact to lookup 109 | * @return The contact. 110 | */ 111 | public Contact getContact(String nodeID) { 112 | String requestUrl = storjApiContacts + "/" + nodeID; 113 | return getBuilder(requestUrl).get(Contact.class); 114 | } 115 | 116 | /** 117 | * Creates a user. 118 | * 119 | * @param user 120 | * the user to create. 121 | * @return The user. 122 | */ 123 | public User createUser(User user) { 124 | return getBuilder(storjApiUsers, user).post(User.class); 125 | } 126 | 127 | /** 128 | * Deletes a user. 129 | * 130 | * @param userEmail 131 | * the user to delete. 132 | */ 133 | public void deleteUser(String userEmail) { 134 | String requestUrl = storjApiUsers + "/" + userEmail; 135 | getBuilder(requestUrl).delete(); 136 | } 137 | 138 | /** 139 | * Sends a PATCH request to reset a users password. 140 | * 141 | * @param userEmail 142 | * the users email to reset. 143 | */ 144 | public void resetPassword(String userEmail) { 145 | String requestUrl = storjApiUsers + "/" + userEmail; 146 | getBuilder(requestUrl).method("PATCH", String.class); 147 | } 148 | 149 | /** 150 | * Sends a GET request to confirm the password reset. 151 | * 152 | * @param token 153 | * the password reset token. 154 | * @return the User if OK 155 | */ 156 | public User confirmPasswordReset(String token) { 157 | String requestUrl = storjApiUsersPassReset + "/" + token; 158 | return getBuilder(requestUrl).get(User.class); 159 | } 160 | 161 | /** 162 | * Activates a registered user. 163 | * 164 | * @param token 165 | * activation token. 166 | * @return The user which is now activated. 167 | */ 168 | public User activateRegisteredUser(String token) { 169 | String requestUrl = storjApiUsersActivate + "/" + token; 170 | return getBuilder(requestUrl).get(User.class); 171 | } 172 | 173 | /** 174 | * Deactivates a registered user. 175 | * 176 | * @param token 177 | * deactivation token. 178 | * @return The user which is now deactivated. 179 | */ 180 | public User deactivateRegisteredUser(String token) { 181 | String requestUrl = storjApiUsersDeactivate + "/" + token; 182 | return getBuilder(requestUrl).get(User.class); 183 | } 184 | 185 | /** 186 | * Get all ECDSA Keys. 187 | * 188 | * @return a list of ECDSA keys associated with the authorized user. 189 | */ 190 | public List ecdsaKeyGetAll() { 191 | return getBuilder(storjApiKeys).get(new GenericType>() { 192 | }); 193 | } 194 | 195 | /** 196 | * Registers a ECDSA public key for the user account 197 | * 198 | * @param key 199 | * the public key to register 200 | * @return The ECDSA key returned by the server. 201 | */ 202 | public ECDSAKey ecdsaKeyRegister(String key) { 203 | Map postBody = new HashMap(); 204 | postBody.put("key", key); 205 | return getBuilder(storjApiKeys).post(ECDSAKey.class, postBody); 206 | } 207 | 208 | /** 209 | * Destroys a ECDSA public key for the user account 210 | * 211 | * @param publicKey 212 | * the public key to destroy. 213 | */ 214 | public void ecdsaKeyDestroy(String publicKey) { 215 | String requestUrl = storjApiKeys + "/" + publicKey; 216 | getBuilder(requestUrl).delete(); 217 | } 218 | 219 | /** 220 | * Returns all of the open file stages for the caller. 221 | * 222 | * @return all of the open file stages for the caller 223 | */ 224 | public List getFrames() { 225 | return getBuilder(storjApiFrames).get(new GenericType>() { 226 | }); 227 | } 228 | 229 | /** 230 | * Creates a new file staging frame. 231 | * 232 | * @return the created frame. 233 | */ 234 | public Frame createFrame() { 235 | return getBuilder(storjApiFrames).post(Frame.class); 236 | } 237 | 238 | /** 239 | * Destroy a frame. 240 | * 241 | * @param frameId 242 | * the ID of the frame to destroy. 243 | */ 244 | public void destroyFrame(String frameId) { 245 | String requestUrl = storjApiFrames + "/" + frameId; 246 | getBuilder(requestUrl).delete(); 247 | } 248 | 249 | /** 250 | * Get a drame by ID. 251 | * 252 | * @param frameId 253 | * The ID of the frame to get. 254 | * @return the frame. 255 | */ 256 | public Frame getFrameById(String frameId) { 257 | String requestUrl = storjApiFrames + "/" + frameId; 258 | return getBuilder(requestUrl).get(Frame.class); 259 | } 260 | 261 | /** 262 | * Add a shard to a frame. 263 | * 264 | * @param frameId 265 | * the ID of the frame to add a shard to. 266 | * @param shard 267 | * the shard to add. 268 | * @param retries 269 | * the number of times to retry. 270 | * @return the Frame with the shard added. 271 | */ 272 | public AddShardResponse addShardToFrame(String frameId, Shard shard, int retries) { 273 | String requestUrl = storjApiFrames + "/" + frameId; 274 | 275 | for(int i = 1; i < retries; i++) { 276 | logger.info("Attempting to negotiate shard contract, attempt " + i + " of " + retries); 277 | try { 278 | return getBuilder(requestUrl, shard).put(AddShardResponse.class); 279 | } catch (Exception e) { 280 | logger.info("Failed with reason: " + e.getMessage()); 281 | } 282 | } 283 | 284 | logger.info("Final attempt to upload shard..."); 285 | return getBuilder(requestUrl, shard).put(AddShardResponse.class); 286 | } 287 | 288 | /** 289 | * Get a list of all the buckets the user has access to. 290 | * 291 | * @return the list of buckets. 292 | */ 293 | public List getAllBuckets() { 294 | 295 | return getBuilder(storjApiBuckets).get(new GenericType>() { 296 | }); 297 | } 298 | 299 | /** 300 | * Creates a bucket on the server. 301 | * 302 | * @param bucket 303 | * The bucket to create. 304 | * @return The bucket which has been created. 305 | */ 306 | public Bucket createBucket(Bucket bucket) { 307 | return getBuilder(storjApiBuckets, bucket).post(Bucket.class); 308 | } 309 | 310 | /** 311 | * Delete the bucket on the server. 312 | * 313 | * @param bucketId 314 | * The id of the bucket to destroy. 315 | */ 316 | public void deleteBucket(String bucketId) { 317 | String requestUrl = storjApiBuckets + "/" + bucketId; 318 | getBuilder(requestUrl).delete(); 319 | } 320 | 321 | /** 322 | * Retrieves a bucket by ID. 323 | * @param bucketId the ID of the bucket. 324 | * @return The bucket. 325 | */ 326 | public Bucket getBucketById(String bucketId){ 327 | String requestUrl = storjApiBuckets + "/" + bucketId; 328 | return getBuilder(storjApiBuckets).get(Bucket.class); 329 | } 330 | 331 | /** 332 | * Update a bucket via a patch request. 333 | * 334 | * @param bucket 335 | * the bucket to update on the server. 336 | * @return The bucket which has been updated. 337 | */ 338 | public Bucket updateBucket(Bucket bucket) { 339 | String requestUrl = storjApiBuckets + "/" + bucket.getId(); 340 | return getBuilder(requestUrl, bucket).method("PATCH", Bucket.class); 341 | } 342 | 343 | /** 344 | * Create a token for the specified bucket and operation. 345 | * 346 | * @param bucketId 347 | * the ID of the bucket to create a token for. 348 | * @param operation 349 | * The operation to create a token for. 350 | * @return The created token. 351 | */ 352 | public Token getTokenForBucket(String bucketId, Operation operation) { 353 | String requestUrl = storjApiBuckets + "/" + bucketId + "/" + "tokens"; 354 | Map postBody = new HashMap(); 355 | postBody.put("operation", operation.toString()); 356 | return getBuilder(requestUrl, postBody).post(Token.class); 357 | } 358 | 359 | /** 360 | * Get a list of all the files in a bucket. 361 | * 362 | * @param bucketId 363 | * the bucket id. 364 | * @return the meta data for the files. 365 | */ 366 | public List getFilesInBucket(String bucketId) { 367 | String requestUrl = storjApiBuckets + "/" + bucketId + "/" + "files"; 368 | return getBuilder(requestUrl).get(new GenericType>() { 369 | }); 370 | } 371 | 372 | /** 373 | * Add a file in the storj network through the storj bridge 374 | * 375 | * @param bucketId 376 | * the bucket ID to add to. 377 | * @param bucketEntry 378 | * The bucket entry. 379 | * @return a bucket entry. 380 | */ 381 | public BucketEntry storeFile(String bucketId, BucketEntry bucketEntry) { 382 | String requestUrl = storjApiBuckets + "/" + bucketId + "/" + "files"; 383 | return getBuilder(requestUrl, bucketEntry).post(BucketEntry.class); 384 | } 385 | 386 | /** 387 | * Destroy a file entry. 388 | * 389 | * @param bucketId 390 | * The bucket ID the file belongs to. 391 | * @param fileId 392 | * The fileId of the file to destroy. 393 | */ 394 | public void destroyFileEntry(String bucketId, String fileId) { 395 | String requestUrl = storjApiBuckets + "/" + bucketId + "/files/" + fileId; 396 | getBuilder(requestUrl).delete(); 397 | } 398 | 399 | /** 400 | * Get file pointers for a file on the storj network. 401 | * 402 | * @param bucketId 403 | * The ID of the bucket the file belongs in. 404 | * @param fileId 405 | * The ID of the file. 406 | * @param xToken 407 | * The access token. 408 | * @return A list of filepointers to retrieve the file. 409 | */ 410 | public List getFilePointers(String bucketId, String fileId, String xToken) { 411 | String requestUrl = storjApiBuckets + "/" + bucketId + "/files/" + fileId; 412 | 413 | // Add URL params. 414 | Map urlParams = new HashMap(); 415 | urlParams.put("skip", "0"); 416 | urlParams.put("limit", "10"); 417 | requestUrl += MapQueryEncoderUtils.urlEncodeUTF8(urlParams); 418 | 419 | // Headers. 420 | WebResource.Builder builder = getBuilder(requestUrl); 421 | builder.header("x-token", xToken); 422 | 423 | return builder.get(new GenericType>() { 424 | }); 425 | } 426 | 427 | /** 428 | * Configure Jersey to use Jackson for unmarshalling and marshalling JSON. 429 | */ 430 | private void configureJersey() { 431 | 432 | ClientConfig cc = new DefaultClientConfig(); 433 | cc.getFeatures().put(JSONConfiguration.FEATURE_POJO_MAPPING, Boolean.TRUE); 434 | // Required for PATCH. 435 | cc.getProperties().put(URLConnectionClientHandler.PROPERTY_HTTP_URL_CONNECTION_SET_METHOD_WORKAROUND, true); 436 | jerseyClient = Client.create(cc); 437 | jerseyClient.addFilter(new LoggingFilter(System.out)); 438 | } 439 | 440 | /** 441 | * Helper method to create a WebResource.Builder creating a request to the 442 | * Storj API. Sets the request to accept media types consisting of 443 | * {@value #INCOMING_MEDIA_TYPE} and sets the authentication headers using 444 | * the currently set implementation of {@link AuthType}. 445 | * 446 | * @param requestUrl 447 | * the URL to create the request builder for. 448 | * @return WebResource.Builder the request builder 449 | */ 450 | private WebResource.Builder getBuilder(String requestUrl) { 451 | 452 | WebResource.Builder builder = jerseyClient.resource(requestUrl).getRequestBuilder(); 453 | 454 | builder = builder.accept(INCOMING_MEDIA_TYPE); 455 | builder = auth.setRequiredAuthHeaders(builder); 456 | 457 | return builder; 458 | } 459 | 460 | /** 461 | * Creates a WebResource.Builder using the same logic as 462 | * {@link #getBuilder(String requestUrl)} and includes a request entity. The 463 | * media type of the request entity is set to {@value #OUTGOING_MEDIA_TYPE}. 464 | * 465 | * @param requestUrl 466 | * the URL to create the request builder for. 467 | * @param entity the request entity 468 | * @return WebResource.Builder the request builder 469 | */ 470 | private WebResource.Builder getBuilder(String requestUrl, Object entity) { 471 | 472 | WebResource.Builder builder = getBuilder(requestUrl); 473 | builder.type(OUTGOING_MEDIA_TYPE); 474 | builder.entity(entity); 475 | 476 | return builder; 477 | } 478 | } 479 | -------------------------------------------------------------------------------- /StorjBrowser/src/main/java/sample/Controller.java: -------------------------------------------------------------------------------- 1 | package sample; 2 | 3 | import com.google.gson.Gson; 4 | import com.google.gson.GsonBuilder; 5 | import com.sun.jersey.api.client.UniformInterfaceException; 6 | import javafx.application.Platform; 7 | 8 | import javafx.collections.ObservableList; 9 | import javafx.concurrent.Task; 10 | import javafx.event.ActionEvent; 11 | import javafx.fxml.FXML; 12 | import javafx.fxml.Initializable; 13 | import javafx.scene.control.*; 14 | import javafx.scene.control.cell.PropertyValueFactory; 15 | import javafx.scene.image.ImageView; 16 | import javafx.scene.layout.GridPane; 17 | import javafx.scene.layout.Priority; 18 | import javafx.stage.FileChooser; 19 | import javafx.stage.Stage; 20 | import org.controlsfx.control.TaskProgressView; 21 | import storj.io.client.DefaultStorjClient; 22 | import storj.io.client.StorjClient; 23 | import storj.io.client.StorjConfiguration; 24 | import storj.io.restclient.model.Bucket; 25 | import storj.io.restclient.model.BucketEntry; 26 | import java.io.*; 27 | import java.net.URL; 28 | import java.nio.file.Files; 29 | import java.nio.file.Path; 30 | import java.nio.file.StandardOpenOption; 31 | import java.util.*; 32 | import java.util.concurrent.ExecutorService; 33 | import java.util.concurrent.Executors; 34 | import java.util.stream.Collectors; 35 | 36 | public class Controller implements Initializable{ 37 | 38 | @FXML 39 | ListView bucketView; 40 | 41 | @FXML 42 | TableView tableView; 43 | 44 | @FXML 45 | TableColumn fileName; 46 | 47 | @FXML 48 | TableColumn size; 49 | 50 | @FXML 51 | TableColumn type; 52 | 53 | @FXML 54 | TableColumn id; 55 | 56 | @FXML 57 | TaskProgressView> progressView; 58 | 59 | private ObservableList bucketList; 60 | 61 | private ObservableList tableValues; 62 | 63 | private Preferences preferences; 64 | 65 | private StorjClient client; 66 | 67 | private final ExecutorService exec = Executors.newFixedThreadPool(1, r -> { 68 | Thread t = new Thread(r); 69 | t.setDaemon(true); 70 | return t ; 71 | }); 72 | 73 | public void initialize(URL location, ResourceBundle resources) { 74 | 75 | loadConfigurationFromFile(); 76 | 77 | bucketView.setCellFactory(new BucketListCellFactory()); 78 | bucketList = bucketView.getItems(); 79 | 80 | fileName.setCellValueFactory( 81 | new PropertyValueFactory("fileName") 82 | ); 83 | 84 | size.setCellValueFactory( 85 | new PropertyValueFactory("size") 86 | ); 87 | 88 | type.setCellValueFactory( 89 | new PropertyValueFactory("type") 90 | ); 91 | 92 | id.setCellValueFactory( 93 | new PropertyValueFactory("id") 94 | ); 95 | 96 | tableValues = tableView.getItems(); 97 | 98 | bucketView.getSelectionModel().selectedItemProperty().addListener( 99 | (observableValue, oldValue, newValue) -> { 100 | if(newValue != null) { 101 | runTask(updateFilesTask(newValue.getId()), "Update files list."); 102 | }}); 103 | 104 | progressView.setGraphicFactory(task -> new ImageView("images/storj-small.jpeg")); 105 | 106 | } 107 | 108 | @FXML 109 | private void handleOpenSite(){ 110 | Dialog dialog = new ChoiceDialog(preferences.getSites().get(0), preferences.getSites()); 111 | dialog.setTitle("Open account"); 112 | dialog.setHeaderText("Select the account to switch to."); 113 | 114 | Optional result = dialog.showAndWait(); 115 | 116 | if (result.isPresent()) { 117 | String pw = promptForPassword(); 118 | if(pw != null) { 119 | updateStorjConfiguration(result.get(), pw); 120 | } 121 | } 122 | } 123 | 124 | @FXML 125 | private void handleDeleteSite(){ 126 | Dialog dialog = new ChoiceDialog(preferences.getSites().get(0), preferences.getSites()); 127 | dialog.setTitle("Delete account"); 128 | dialog.setHeaderText("Select the account to delete."); 129 | Optional result = dialog.showAndWait(); 130 | if (result.isPresent()) { 131 | preferences.getSites().remove(result.get()); 132 | writePreferences(); 133 | } 134 | } 135 | 136 | private boolean checkAccountOpen(){ 137 | if(client == null){ 138 | Alert alert = new Alert(Alert.AlertType.WARNING); 139 | alert.setTitle("First select an account."); 140 | String s = "You should first select an account. Click Accounts -> New\n or Accounts -> Open."; 141 | alert.setContentText(s); 142 | alert.showAndWait(); 143 | return false; 144 | } 145 | return true; 146 | } 147 | 148 | @FXML 149 | private boolean handleAbout(){ 150 | if(client == null){ 151 | Alert alert = new Alert(Alert.AlertType.INFORMATION); 152 | alert.setTitle("Storj browser"); 153 | String s = "This is a very early version of the Storj Browser.\n\n Version: 0.0.1-Alpha"; 154 | alert.setContentText(s); 155 | alert.showAndWait(); 156 | return false; 157 | } 158 | return true; 159 | } 160 | 161 | 162 | private void firstSelectPrompt(String whatToSelect){ 163 | Alert alert = new Alert(Alert.AlertType.WARNING); 164 | alert.setTitle("First select the " + whatToSelect + "."); 165 | String s = "First select the " + whatToSelect + "."; 166 | alert.setContentText(s); 167 | alert.showAndWait(); 168 | } 169 | 170 | @FXML 171 | private void handleAddNewSite(){ 172 | Dialog dialog = new Dialog<>(); 173 | dialog.setTitle("Add new account"); 174 | dialog.setHeaderText("Add a new account. \nNote, Storj Browser does not store your password."); 175 | dialog.setResizable(true); 176 | 177 | Label label0 = new Label("Account name (Anything): "); 178 | Label label1 = new Label("Bridge Host: "); 179 | Label label2 = new Label("Username (Email): "); 180 | Label label3 = new Label("Password: "); 181 | 182 | TextField text0 = new TextField(); 183 | TextField text1 = new TextField(); 184 | TextField text2 = new TextField(); 185 | TextField text3 = new PasswordField(); 186 | 187 | text1.setText("https://api.storj.io"); 188 | GridPane grid = new GridPane(); 189 | 190 | grid.add(label0, 1, 1); 191 | grid.add(text0, 2, 1); 192 | 193 | grid.add(label1, 1, 2); 194 | grid.add(text1, 2, 2); 195 | grid.add(label2, 1, 3); 196 | grid.add(text2, 2, 3); 197 | grid.add(label3, 1, 4); 198 | grid.add(text3, 2, 4); 199 | dialog.getDialogPane().setContent(grid); 200 | 201 | ButtonType buttonTypeOk = new ButtonType("Ok", ButtonBar.ButtonData.OK_DONE); 202 | dialog.getDialogPane().getButtonTypes().add(buttonTypeOk); 203 | 204 | dialog.setResultConverter((button) -> { 205 | if (button == buttonTypeOk) { 206 | return new Site(text1.getText(), text2.getText(), text3.getText(), text0.getText()); 207 | } 208 | return null; 209 | }); 210 | 211 | Optional result = dialog.showAndWait(); 212 | 213 | if (result.isPresent()) { 214 | preferences.getSites().add(result.get()); 215 | writePreferences(); 216 | updateStorjConfiguration(result.get(), text3.getText()); 217 | runTask(updateBucketsTask(), "Update bucket list."); 218 | } 219 | } 220 | 221 | private void updateStorjConfiguration(Site site, String password) { 222 | StorjConfiguration configuration = new StorjConfiguration(password, site.getUsername(), password); 223 | client = new DefaultStorjClient(configuration); 224 | runTask(updateBucketsTask(), "Update bucket list."); 225 | } 226 | 227 | private void loadConfigurationFromFile(){ 228 | preferences = loadPreferences(); 229 | } 230 | 231 | private String promptForPassword() { 232 | PasswordInputDialog dialog = new PasswordInputDialog("Password"); 233 | 234 | dialog.setTitle("Enter password"); 235 | dialog.setHeaderText("This program does not store your password. \nPlease enter it here to access your storj buckets."); 236 | 237 | Optional result = dialog.showAndWait(); 238 | if (result.isPresent()) { 239 | return result.get(); 240 | } else { 241 | return null; 242 | } 243 | } 244 | 245 | private void writePreferences(){ 246 | Gson gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create(); 247 | String settingFilePath = System.getProperty("user.home") + File.separator + ".storjBrowser" + File.separator + "settings.json"; 248 | try { 249 | Path pathToFile = new File(settingFilePath).toPath(); 250 | 251 | if(!Files.exists(pathToFile)){ 252 | Files.createDirectories(pathToFile.getParent()); 253 | } 254 | 255 | Files.write(pathToFile, gson.toJson(preferences).getBytes(), 256 | StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.CREATE ); 257 | } catch (IOException e) { 258 | e.printStackTrace(); 259 | } 260 | } 261 | 262 | private Preferences loadPreferences() { 263 | Gson gson = new Gson(); 264 | 265 | String settingFilePath = System.getProperty("user.home") + File.separator + ".storjBrowser" + File.separator + "settings.json"; 266 | File file = new File(settingFilePath); 267 | Path pathToFile = file.toPath(); 268 | if(file.exists()){ 269 | try { 270 | preferences = gson.fromJson(new String(Files.readAllBytes(pathToFile)), Preferences.class); 271 | } catch (IOException e) { 272 | e.printStackTrace(); 273 | }; 274 | }else{ 275 | preferences = new Preferences(); 276 | handleAddNewSite(); 277 | writePreferences(); 278 | } 279 | return preferences; 280 | } 281 | 282 | @FXML 283 | private void handleFileDownload(ActionEvent event){ 284 | if(checkAccountOpen()) { 285 | if (bucketView.getSelectionModel().getSelectedItem() == null || tableView.getSelectionModel().getSelectedItem() == null) { 286 | firstSelectPrompt("file"); 287 | }else { 288 | String bucketId = bucketView.getSelectionModel().getSelectedItem().getId(); 289 | Stage stage = (Stage) bucketView.getScene().getWindow(); 290 | final FileChooser fileChooser = new FileChooser(); 291 | fileChooser.setTitle("Save File"); 292 | fileChooser.setInitialFileName(tableView.getSelectionModel().getSelectedItem().getFileName()); 293 | File file = fileChooser.showSaveDialog(stage); 294 | if (file != null) { 295 | if (tableView.getSelectionModel().getSelectedItem() == null) { 296 | firstSelectPrompt("file"); 297 | } else { 298 | runTask(downloadFileTask(file, bucketId, tableView.getSelectionModel().getSelectedItem().getId()), "Download file."); 299 | } 300 | } 301 | } 302 | } 303 | } 304 | 305 | private void runTask(Task task, String name){ 306 | task.setOnFailed(e -> { 307 | showException(e.getSource().getException()); 308 | }); 309 | Platform.runLater(()-> { 310 | exec.submit(task); 311 | progressView.getTasks().add(task); 312 | }); 313 | } 314 | 315 | @FXML 316 | private void handleFileUpload(ActionEvent event){ 317 | if(checkAccountOpen()) { 318 | if(bucketView.getSelectionModel().getSelectedItem() == null){ 319 | firstSelectPrompt("bucket"); 320 | }else { 321 | String bucketId = bucketView.getSelectionModel().getSelectedItem().getId(); 322 | Stage stage = (Stage) bucketView.getScene().getWindow(); 323 | final FileChooser fileChooser = new FileChooser(); 324 | File file = fileChooser.showOpenDialog(stage); 325 | if (file != null) { 326 | runTask(uploadFileTask(file, bucketId), "Upload file."); 327 | } 328 | } 329 | } 330 | } 331 | 332 | 333 | private Task downloadFileTask(File file, String bucketId, String fileId){ 334 | return new Task() { 335 | 336 | {this.updateTitle("Downloading to " + file.getName());} 337 | 338 | @Override 339 | public Void call() throws Exception { 340 | client.downloadFile(bucketId, fileId, file); 341 | runTask(updateFilesTask(bucketId), "Update file list."); 342 | return null; 343 | } 344 | }; 345 | } 346 | 347 | 348 | private Task uploadFileTask(File file, String bucketId){ 349 | return new Task() { 350 | @Override 351 | public Void call() throws Exception { 352 | {this.updateTitle("Uploading file " + file.getName());} 353 | client.uploadFile(file, bucketId); 354 | runTask(updateFilesTask(bucketId), "Update file list."); 355 | return null; 356 | } 357 | }; 358 | } 359 | 360 | public void createList() { 361 | runTask(updateBucketsTask(), "Update bucket list."); 362 | } 363 | 364 | private Task updateFilesTask(String bucketId){ 365 | return new Task() { 366 | @Override 367 | public Void call() throws Exception { 368 | {this.updateTitle("Updating list of files");} 369 | 370 | List bucketEntries = client.listFiles(bucketId); 371 | Platform.runLater(()-> { 372 | tableValues.clear(); 373 | List views = bucketEntries.stream().map(bucketEntry -> new BucketEntryTableView(bucketEntry)).collect(Collectors.toList()); 374 | tableValues.addAll(views); 375 | }); 376 | return null; 377 | } 378 | }; 379 | } 380 | 381 | private Task updateBucketsTask() { 382 | return new Task() { 383 | @Override 384 | public Void call() throws Exception { 385 | {this.updateTitle("Refreshing bucket list.");} 386 | 387 | final List buckets = client.listBuckets(); 388 | Platform.runLater(()->{ 389 | bucketList.clear(); 390 | bucketList.addAll(buckets); 391 | }); 392 | return null; 393 | } 394 | }; 395 | } 396 | 397 | private Task deleteBucketsTask(String bucketId) { 398 | return new Task() { 399 | @Override 400 | public Void call() throws Exception { 401 | {this.updateTitle("Deleting bucket " + bucketId + ".");} 402 | client.deleteBucket(bucketId); 403 | Platform.runLater(()-> { 404 | tableValues.clear(); 405 | bucketList.clear(); 406 | runTask(updateBucketsTask(), "Update Bucket list."); 407 | }); 408 | return null; 409 | } 410 | }; 411 | } 412 | 413 | @FXML 414 | private void handleDeleteBucket(){ 415 | if(checkAccountOpen()) { 416 | if(bucketView.getSelectionModel().getSelectedItem() == null ) { 417 | firstSelectPrompt("bucket"); 418 | } else { 419 | String bucketId = bucketView.getSelectionModel().getSelectedItem().getId(); 420 | runTask(deleteBucketsTask(bucketId), "Delete bucket " + bucketId); 421 | } 422 | } 423 | } 424 | 425 | @FXML 426 | private void handleCreateBucket(){ 427 | if(checkAccountOpen()) { 428 | 429 | TextInputDialog dialog = new TextInputDialog("Bucket Name"); 430 | dialog.setTitle("Create bucket"); 431 | dialog.setHeaderText("Enter the name of the bucket you would like to create:"); 432 | 433 | Optional result = dialog.showAndWait(); 434 | 435 | if (result.isPresent()) { 436 | runTask(createBucketsTask(result.get()), "Create bucket " + result.get()); 437 | } 438 | } 439 | } 440 | 441 | private Task createBucketsTask(String bucketName) { 442 | return new Task() { 443 | @Override 444 | public Void call() throws Exception { 445 | {this.updateTitle("Creating bucket " + bucketName + ".");} 446 | client.createBucket(bucketName); 447 | tableValues.clear(); 448 | bucketList.clear(); 449 | runTask(updateBucketsTask(), "Update bucket list."); 450 | return null; 451 | } 452 | }; 453 | } 454 | 455 | @FXML 456 | private void handleDelete(ActionEvent event) { 457 | if(checkAccountOpen()) { 458 | if (bucketView.getSelectionModel().getSelectedItem() == null || tableView.getSelectionModel().getSelectedItem() == null) { 459 | firstSelectPrompt("file"); 460 | }else{ 461 | runTask(deleteFileTask(tableView.getSelectionModel().getSelectedItem().getId()), "Deleting file " + tableView.getSelectionModel().getSelectedItem().getFileName()); 462 | } 463 | } 464 | } 465 | 466 | @FXML 467 | private void handleRefresh(ActionEvent event) { 468 | if(checkAccountOpen()) { 469 | if (bucketView.getSelectionModel().getSelectedItem() == null) { 470 | firstSelectPrompt("bucket"); 471 | } else { 472 | String bucketId = bucketView.getSelectionModel().getSelectedItem().getId(); 473 | runTask(updateFilesTask(bucketId), "Update files list."); 474 | } 475 | } 476 | } 477 | 478 | 479 | private Task deleteFileTask(String fileId) { 480 | return new Task() { 481 | @Override 482 | public Void call() throws Exception { 483 | {this.updateTitle("Deleting file " + fileId + ".");} 484 | String bucketId = bucketView.getSelectionModel().getSelectedItem().getId(); 485 | client.deleteFile(bucketId, fileId); 486 | runTask(updateFilesTask(bucketId), "Update files list."); 487 | return null; 488 | } 489 | }; 490 | } 491 | 492 | private void showException(Throwable throwable) { 493 | String genericError = "Please feel to report it as an issue on github with the stack trace below."; 494 | String errorToShow = genericError; 495 | String restResponse = null; 496 | 497 | Alert alert = new Alert(Alert.AlertType.ERROR); 498 | alert.setTitle("Error"); 499 | if(throwable instanceof UniformInterfaceException){ 500 | UniformInterfaceException restException = (UniformInterfaceException) throwable; 501 | int status = restException.getResponse().getStatus(); 502 | String reason = restException.getResponse().getStatusInfo().getReasonPhrase(); 503 | errorToShow = "The bridge returned a status of " + status + " with reason: \"" + reason + 504 | "\". An exception trace is below, and if you believe this is an error, please report it on GitHub."; 505 | restResponse = restException.getResponse().toString(); 506 | } 507 | 508 | alert.setHeaderText("Something went wrong."); 509 | alert.setContentText(errorToShow); 510 | 511 | StringWriter sw = new StringWriter(); 512 | PrintWriter pw = new PrintWriter(sw); 513 | throwable.printStackTrace(pw); 514 | String exceptionText = sw.toString(); 515 | 516 | if(restResponse != null){ 517 | exceptionText += "\n\nResponse from Server:\n\n" + restResponse; 518 | } 519 | 520 | Label label = new Label("The exception stacktrace was:"); 521 | 522 | TextArea textArea = new TextArea(exceptionText); 523 | textArea.setEditable(false); 524 | textArea.setWrapText(true); 525 | 526 | textArea.setMaxWidth(Double.MAX_VALUE); 527 | textArea.setMaxHeight(Double.MAX_VALUE); 528 | GridPane.setVgrow(textArea, Priority.ALWAYS); 529 | GridPane.setHgrow(textArea, Priority.ALWAYS); 530 | 531 | GridPane expContent = new GridPane(); 532 | expContent.setMaxWidth(Double.MAX_VALUE); 533 | expContent.add(label, 0, 0); 534 | expContent.add(textArea, 0, 1); 535 | alert.getDialogPane().setExpandableContent(expContent); 536 | alert.showAndWait(); 537 | } 538 | } 539 | 540 | 541 | --------------------------------------------------------------------------------