From effacad1fe3baec83b8331ace478904c59bc8076 Mon Sep 17 00:00:00 2001 From: samuli Date: Tue, 8 May 2018 22:31:55 +0300 Subject: [PATCH] initital --- .gitignore | 31 ++ README.md | 165 +++++++ example-app/icon-128.png | Bin 0 -> 360 bytes example-app/main.html | 14 + example-app/main.js | 50 +++ example-app/manifest.json | 17 + pom.xml | 127 ++++++ .../fi/trustnet/browserextension/Agent.java | 40 ++ .../fi/trustnet/browserextension/App.java | 414 ++++++++++++++++++ .../fi/trustnet/browserextension/Command.java | 29 ++ .../browserextension/CommandCodes.java | 14 + .../browserextension/Configuration.java | 12 + .../browserextension/DidCommands.java | 87 ++++ .../fi/trustnet/browserextension/DidList.java | 20 + .../trustnet/browserextension/DidParams.java | 47 ++ .../browserextension/PayloadKeys.java | 14 + .../trustnet/browserextension/Signature.java | 118 +++++ .../browserextension/StatusCodes.java | 8 + .../browserextension/WalletDbReader.java | 64 +++ .../browserextension/errors/ErrorCode.java | 275 ++++++++++++ .../browserextension/errors/ErrorMessage.java | 32 ++ .../errors/ExceptionMessage.java | 30 ++ .../responses/CreateAccountResponse.java | 25 ++ .../responses/LoginResponse.java | 16 + .../responses/LogoutResponse.java | 16 + .../browserextension/responses/Response.java | 37 ++ .../responses/SignatureResult.java | 54 +++ .../SignatureVerificationResult.java | 44 ++ .../responses/WalletResult.java | 25 ++ .../browserextension/user/Logger.java | 16 + .../trustnet/browserextension/user/Token.java | 27 ++ .../browserextension/user/TokenStore.java | 98 +++++ .../browserextension/user/UserAccount.java | 34 ++ .../browserextension/user/UserStore.java | 136 ++++++ .../fi/trustnet/browserextension/AppTest.java | 20 + 35 files changed, 2156 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 example-app/icon-128.png create mode 100644 example-app/main.html create mode 100644 example-app/main.js create mode 100644 example-app/manifest.json create mode 100644 pom.xml create mode 100644 src/main/java/fi/trustnet/browserextension/Agent.java create mode 100644 src/main/java/fi/trustnet/browserextension/App.java create mode 100644 src/main/java/fi/trustnet/browserextension/Command.java create mode 100644 src/main/java/fi/trustnet/browserextension/CommandCodes.java create mode 100644 src/main/java/fi/trustnet/browserextension/Configuration.java create mode 100644 src/main/java/fi/trustnet/browserextension/DidCommands.java create mode 100644 src/main/java/fi/trustnet/browserextension/DidList.java create mode 100644 src/main/java/fi/trustnet/browserextension/DidParams.java create mode 100644 src/main/java/fi/trustnet/browserextension/PayloadKeys.java create mode 100644 src/main/java/fi/trustnet/browserextension/Signature.java create mode 100644 src/main/java/fi/trustnet/browserextension/StatusCodes.java create mode 100644 src/main/java/fi/trustnet/browserextension/WalletDbReader.java create mode 100644 src/main/java/fi/trustnet/browserextension/errors/ErrorCode.java create mode 100644 src/main/java/fi/trustnet/browserextension/errors/ErrorMessage.java create mode 100644 src/main/java/fi/trustnet/browserextension/errors/ExceptionMessage.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/CreateAccountResponse.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/LoginResponse.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/LogoutResponse.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/Response.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/SignatureResult.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/SignatureVerificationResult.java create mode 100644 src/main/java/fi/trustnet/browserextension/responses/WalletResult.java create mode 100644 src/main/java/fi/trustnet/browserextension/user/Logger.java create mode 100644 src/main/java/fi/trustnet/browserextension/user/Token.java create mode 100644 src/main/java/fi/trustnet/browserextension/user/TokenStore.java create mode 100644 src/main/java/fi/trustnet/browserextension/user/UserAccount.java create mode 100644 src/main/java/fi/trustnet/browserextension/user/UserStore.java create mode 100644 src/test/java/fi/trustnet/browserextension/AppTest.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dcd690d --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +/target/ +!.mvn/wrapper/maven-wrapper.jar + +/.idea/ +/.mvn/ +/mvnw +/classes/ +/mvnw.cmd + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/build/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..49ff977 --- /dev/null +++ b/README.md @@ -0,0 +1,165 @@ +# 1. Introduction +Java backend for TrustNet browser plugin +## 1.1 Requirements +1. Access to Indy pool +2. libIndy v1.3.1 +# 2. API +## 2.1 Create new account +Creates new account. Sets up user wallet and cretes first `did`. +```json +{"operation" : "CREATE_ACCOUNT", "params" :{"username" : "xxxx", "password" : "yyyy"}} +``` +Example response: +```json +{"status":"SUCCESS","value":{"username":"xxxxxx","walletname":"eb7a5aaf-9dfa-4e61-b5ed-eff9aaae2d8d"}} +``` +## 2.2 Login to account +Logs in to account, returns `token` +```json +{"operation" : "LOGIN", "params" :{"username" : "xxxxxx", "password" : "yyyy"}} +``` +Example response: +```json +{"status":"SUCCESS","value":{"token":"66bd38e4-0e8d-46af-8b5c-2abada5f7eb7"}} +``` + +## 2.3 Create new DID +Creates new `DID` +```json +{"operation" : "CREATE_DID", "params" :{"token" : "66bd38e4-0e8d-46af-8b5c-2abada5f7eb7"}} +``` +Example response: +```json +{"status":"CREATED","value":{"did":"MsHajCPU2KjqVTYzgSYmwH","verkey":"CNeXKuzqdJMxbeC6sZHZCGyDjARqwQgkMaRTSX8CJ1p9"}} +``` + +## 2.4 Sign data +Signs data. +Example request: +```json +{"operation" : "SIGN_DATA", "params" :{"token" : "66bd38e4-0e8d-46af-8b5c-2abada5f7eb7", "did" : "MsHajCPU2KjqVTYzgSYmwH", "datatosign" :"testdata"}} +``` +Example response: +```json +{"status":"SUCCESS","value":{"dataToSign":"testdata","wallet":"eb7a5aaf-9dfa-4e61-b5ed-eff9aaae2d8d","signature":"laOJ6ACNnBcRIwG+OtG1CE7FWtGK3WCiyndYZ84SN/KIjX5aMQpeyJ7ryfMiZ/0lrCE57jzcP3JC09MXCiHQAQ==","verkey":"CNeXKuzqdJMxbeC6sZHZCGyDjARqwQgkMaRTSX8CJ1p9","did":"MsHajCPU2KjqVTYzgSYmwH"}} +``` +## 2.5 Verify signature +Verifies signature. +Example command: +```json +{"operation" : "VERIFY_SIGNATURE", "params" :{"token" : "66bd38e4-0e8d-46af-8b5c-2abada5f7eb7", "did" : "MsHajCPU2KjqVTYzgSYmwH", "message" :"testdata", "signature" :"laOJ6ACNnBcRIwG+OtG1CE7FWtGK3WCiyndYZ84SN/KIjX5aMQpeyJ7ryfMiZ/0lrCE57jzcP3JC09MXCiHQAQ=="}} +``` +Example response: +```json +{"status":"SUCCESS","value":{"verified":true,"message":"testdata","signature":"laOJ6ACNnBcRIwG+OtG1CE7FWtGK3WCiyndYZ84SN/KIjX5aMQpeyJ7ryfMiZ/0lrCE57jzcP3JC09MXCiHQAQ==","did":"MsHajCPU2KjqVTYzgSYmwH"}} +``` + +## 2.6 Log out +Logs out and invalidates the token. +Example command: +```json +{"operation" : "LOGOUT" , "params" :{"token" : "66bd38e4-0e8d-46af-8b5c-2abada5f7eb7"}} +``` +Example response: +```json +"status":"SUCCESS","value":{"loggedout":true}} +``` + + +# 3. Standalone +Make sure `RUN_AS_EXTENSION = false` in `Configuration.java`. Check that the `NETWORK_NAME` in `Configuration.java` +matches with your Indy pool configuration. + +If `CREATE_USER`or `LOGIN` commands seem to hang decrease `workload`parameter in `userstore.java`. + + +# 4. Browser extension +Make sure `RUN_AS_EXTENSION = true` in `Configuration.java`.' Check that the `NETWORK_NAME` in `Configuration.java` +matches with your Indy pool configuration. + +Build JAR and make it executable or create script that runs the JAR. +## 4.1 Chrome configuration +The following is for enabling for individual user.' +Create file `fi.trustnet.browserplugin.json file` to `~/.config/google-chrome/NativeMessagingHosts' directory. +File contents: +```json + { + "name": "fi.trustnet.browserplugin", + "description": "TrustNet browser plugin backend", + "path": "PATH_TO_EXECUTABLE_JAR", + "type": "stdio", + "allowed_origins": [ + "chrome-extension://YOUR_EXTENSION_ID/" + ] + } +``` + + +## 4.2 Usage with Chrome +### 4.2.1 Demo +directory `example-app` contains example Crome App that can communicate with the native extension. To install it: +1. Open Chrome +2. go to `chrome://extensions/` +3. Make sure Developer mode is enabled +4. Select Load unpacked +5. No the extension ID, make sure it is same as in `fi.trustnet.browserplugin.json` file, if not change the id in the file. +6. Navigate to example-app directory and open it +7. Go to `chrome://apps` and select TrustNet Demo + +### 4.2.1 Extension-background-native communication + +In background script have something like +```code +let port = null +... +chrome.runtime.onMessage.addListener((request) =>{ + if(request.operation==="CONNECT" { + let hostName="fi.trustnet.browserplugin" + port = chrome.runtime,connectNative(hostName) + port.onMessage.addListener(onNativeMessage) + port.onDisconnect.addListener(onDisconnected) + } + if(request.operation==="CREATE_ACCOUNT){ + port.postMessage(request) + } + //Other messages + +} + +const onNativeMessage = (message) => { + chrome.runtime.sendMessage({from : "background", + subject: "message", + message: "message"}) + +} + +const onDisconnected = () => { + port=null + chrome.runtime.sendMessage({from : "background", + subject: "message", + message: "DISCONNECTED"}) + +} +``` + +Code in Extension side: +```code +chrome.runtime.sendMessage(EXTENSION_ID, MESSAGE} +``` +Examples: +```code +const connect=()=>{ + chrome.runtime.sendMessage("kjhkdhldjldwlmlcwdd", {operation: "CONNECT"}) +} +const createAccount=(username, password) => { + chrome.runtime.sendMessage("kjhkdhldjldwlmlcwdd",{"operation" : "CREATE_ACCOUNT", "params"} :{"username" : username, "password" : password}} +} +``` +Receive messages from background +```code +chrome.runtime.onMessage.addListener((message, sender)=> { + if(sender==="background") { + //handle messages from native extension + } +} +``` \ No newline at end of file diff --git a/example-app/icon-128.png b/example-app/icon-128.png new file mode 100644 index 0000000000000000000000000000000000000000..c3bd2fd4884bbaece0fed130d38c3b55fd605648 GIT binary patch literal 360 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?O3?zSk_}l@c*aCb)TyNjL4P;(=r}~+Jfl=1e z#WAEJ?(Kz*yiA4yu8ze@3Xi=OhOa)F+>hm1{yYd^3YyrIP-z{Ag!*(bWq;ZTKI3^V8Bi409>2&9wYpn!t` zi$D*Tf&|#KKt>j4kXRQ`k^?B_VaOuD!>HoP!0C()DKol=I2;l{MKcmXT8(ogn$9{L tGj)DG>)|%8roVYV+Uqxb-1eSRKj^00_m{Sh-vGml!PC{xWt~$(695a?bw~gJ literal 0 HcmV?d00001 diff --git a/example-app/main.html b/example-app/main.html new file mode 100644 index 0000000..9f9c6cf --- /dev/null +++ b/example-app/main.html @@ -0,0 +1,14 @@ + + + + + + + + + + +
+ + + diff --git a/example-app/main.js b/example-app/main.js new file mode 100644 index 0000000..9193432 --- /dev/null +++ b/example-app/main.js @@ -0,0 +1,50 @@ +var port = null; + +function appendMessage(text) { + document.getElementById('response').innerHTML += "

" + text + "

"; +} + +function updateUiState() { + if (port) { + document.getElementById('connect-button').style.display = 'none'; + document.getElementById('input-text').style.display = 'block'; + document.getElementById('send-message-button').style.display = 'block'; + } else { + document.getElementById('connect-button').style.display = 'block'; + document.getElementById('input-text').style.display = 'none'; + document.getElementById('send-message-button').style.display = 'none'; + } +} + +function sendNativeMessage() { + message = JSON.parse(document.getElementById('input-text').value) + port.postMessage(message); + appendMessage("Sent message: " + JSON.stringify(message) + ""); +} + +function onNativeMessage(message) { + appendMessage("Received message: " + JSON.stringify(message) + ""); +} + +function onDisconnected() { + appendMessage("Failed to connect: " + chrome.runtime.lastError.message); + port = null; + updateUiState(); +} + +function connect() { + var hostName = "fi.trustnet.browserplugin"; + appendMessage("Connecting") + port = chrome.runtime.connectNative(hostName); + port.onMessage.addListener(onNativeMessage); + port.onDisconnect.addListener(onDisconnected); + updateUiState(); +} + +document.addEventListener('DOMContentLoaded', function () { + document.getElementById('connect-button').addEventListener( + 'click', connect); + document.getElementById('send-message-button').addEventListener( + 'click', sendNativeMessage); + updateUiState(); +}); \ No newline at end of file diff --git a/example-app/manifest.json b/example-app/manifest.json new file mode 100644 index 0000000..e0dc89a --- /dev/null +++ b/example-app/manifest.json @@ -0,0 +1,17 @@ +{ + "name": "TrustNet Demo", + "version": "1.0", + "manifest_version": 2, + "description": "COmunication with native wallet app", + "app": { + "launch": { + "local_path": "main.html" + } + }, + "icons": { + "128": "icon-128.png" + }, + "permissions": [ + "nativeMessaging" + ] +} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..6651b89 --- /dev/null +++ b/pom.xml @@ -0,0 +1,127 @@ + + + + 4.0.0 + + fi.trustnet + plugin-backend + 1.0-SNAPSHOT + + plugin-backend + + http://www.example.com + + + UTF-8 + 1.7 + 1.7 + + + + + junit + junit + 4.11 + test + + + + org.hyperledger + indy + 1.3.1 + compile + + + + com.fasterxml.jackson.core + jackson-databind + 2.9.4 + + + + + + org.xerial + sqlite-jdbc + 3.21.0.1 + + + + + org.mindrot + jbcrypt + 0.4 + + + + + + + + + + + + + maven-clean-plugin + 3.0.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.7.0 + + + maven-surefire-plugin + 2.20.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-dependency-plugin + + + + copy-dependencies + package + + copy-dependencies + + + + runtime + ${project.build.directory}/dependency-jars/ + + + + + + + diff --git a/src/main/java/fi/trustnet/browserextension/Agent.java b/src/main/java/fi/trustnet/browserextension/Agent.java new file mode 100644 index 0000000..fe14be5 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/Agent.java @@ -0,0 +1,40 @@ +package fi.trustnet.browserextension; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import fi.trustnet.browserextension.responses.CreateAccountResponse; +import fi.trustnet.browserextension.responses.Response; +import fi.trustnet.browserextension.user.Logger; +import org.hyperledger.indy.sdk.wallet.Wallet; + + +import static fi.trustnet.browserextension.Configuration.NETWORK_NAME; +import static fi.trustnet.browserextension.Configuration.RUN_AS_EXTENSION; + +public class Agent { + private static final String FRIENDLY_NAME ="friendlyName"; + + public static String initializeAgent(String walletName, String username) throws Exception { + + try { + Wallet.createWallet(NETWORK_NAME, walletName, "default", null, null).get(); + + ObjectMapper objectMapper = new ObjectMapper(); + ObjectNode didMetadata = objectMapper.createObjectNode(); + didMetadata.put(FRIENDLY_NAME, username + "@EdgeAgent"); + + DidCommands.createDid(walletName, didMetadata.toString(), null ); + + } + catch (Exception e) { + + if (RUN_AS_EXTENSION) + Logger.writeToLog("initializeAgent " + e.getMessage()); + else + System.out.println(e.getMessage()); + throw e; + } + + return walletName; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/App.java b/src/main/java/fi/trustnet/browserextension/App.java new file mode 100644 index 0000000..892b40b --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/App.java @@ -0,0 +1,414 @@ +//https://github.com/ulymarins/chrome-native-messaging-java/blob/master/host-project/src/main/java/br/net/cartoriodigital/Application.java +package fi.trustnet.browserextension; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import fi.trustnet.browserextension.errors.ErrorCode; +import fi.trustnet.browserextension.errors.ErrorMessage; +import fi.trustnet.browserextension.user.*; +import fi.trustnet.browserextension.responses.CreateAccountResponse; +import fi.trustnet.browserextension.responses.LoginResponse; +import fi.trustnet.browserextension.responses.LogoutResponse; +import fi.trustnet.browserextension.responses.Response; +import org.hyperledger.indy.sdk.LibIndy; + +import java.io.*; +import java.util.LinkedHashMap; + +import static fi.trustnet.browserextension.CommandCodes.*; +import static fi.trustnet.browserextension.Configuration.LIBINDY_LOCATION; +import static fi.trustnet.browserextension.Configuration.RUN_AS_EXTENSION; +import static fi.trustnet.browserextension.PayloadKeys.*; +import static fi.trustnet.browserextension.StatusCodes.CREATED; +import static fi.trustnet.browserextension.StatusCodes.ERROR; +import static fi.trustnet.browserextension.errors.ExceptionMessage.createErrorMessageFromException; + +public class App +{ + + + + private static ObjectMapper objectMapper; + + public static void main( String[] args ) { + + + UserStore.initUserDb(); + TokenStore.initTokenDb(); + + objectMapper = new ObjectMapper(); + + if (!LibIndy.isInitialized()) LibIndy.init(new File(LIBINDY_LOCATION)); + + + + try { + if (!RUN_AS_EXTENSION) { + System.out.println("enter commands, ctrl-c to exit"); + BufferedReader br = null; + BufferedWriter bw = null; + InputStreamReader in= new InputStreamReader(System.in); + OutputStreamWriter out = new OutputStreamWriter(System.out); + br = new BufferedReader(in); + bw = new BufferedWriter(out); + while (true) { + String cmd = br.readLine(); + String response = processInput(cmd); + bw.newLine(); + bw.write(response); + bw.newLine(); + bw.flush(); + } + + } + else { + while (true) { + byte[] msgLen = new byte[4]; + System.in.read(msgLen); + int size = getInt(msgLen); + writeReqToFile("size " + size); + byte[] b = new byte[size]; + System.in.read(b, 0, size); + writeReqToFile(new String(b, "UTF-8")); + + String response = processInput(new String(b, "UTF-8")); + + System.out.write(getBytes(response.length())); + System.out.write(response.getBytes("UTF-8")); + System.out.flush(); + } + } + + } catch (IOException e) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("Exception in msg reader loop" + e.getMessage()); + else + e.printStackTrace(); + } + } + + private static int getInt(byte[] bytes) { + return (bytes[3] << 24) & 0xff000000 | (bytes[2] << 16) & 0x00ff0000 + | (bytes[1] << 8) & 0x0000ff00 | (bytes[0] << 0) & 0x000000ff; + } + + private static byte[] getBytes(int length) { + byte[] bytes = new byte[4]; + bytes[0] = (byte) (length & 0xFF); + bytes[1] = (byte) ((length >> 8) & 0xFF); + bytes[2] = (byte) ((length >> 16) & 0xFF); + bytes[3] = (byte) ((length >> 24) & 0xFF); + return bytes; + } + + private static void writeReqToFile(String req) { + try { + FileWriter fw = new FileWriter("log.txt", true); + fw.write(req + "\n"); + fw.flush(); + fw.close(); + } + catch (Exception e) { + } + } + + private static String getWalletName(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + String tokenId = ((LinkedHashMap)params).get(TOKEN).toString(); + Token token = TokenStore.findTokenByTokenId(tokenId); + if (token == null) { + return ""; + } + return UserStore.getWalletNameByUsername(token.getUsername()); + } + + private static String getDid(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(DID).toString(); + } + + private static String getDataToSign(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(DATA_TO_SIGN).toString(); + } + + + private static String getMessage(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(MESSAGE).toString(); + } + + + private static String getSignature(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(SIGNATURE).toString(); + } + + + private static String getUsername(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(USERNAME).toString(); + } + + + private static String getPassword(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).get(PASSWORD).toString(); + } + + + private static String getToken(Object params) { + if (!(params instanceof LinkedHashMap)) { + return ""; + } + return ((LinkedHashMap)params).getOrDefault(TOKEN, "").toString(); + } + + private static boolean isTokenValid(String tokenId) { + if (TokenStore.findTokenByTokenId(tokenId) == null ){ + return false; + } + else { + return true; + } + } + + private static boolean verifyParams(String opType, Object params) { + if (!(params instanceof LinkedHashMap)) { + return false; + } + switch (opType) { + case CREATE_DID : { + if (((LinkedHashMap)params).get(TOKEN) == null) { + return false; + } + else { + return true; + } + } + + case SIGN_DATA : { + if (((LinkedHashMap)params).get(TOKEN) == null || ((LinkedHashMap)params).get(DID) == null + ||((LinkedHashMap)params).get(DATA_TO_SIGN) == null) { + return false; + } + else { + return true; + } + } + case VERIFY_SIGNATURE : { + if (((LinkedHashMap)params).get(TOKEN) == null || ((LinkedHashMap)params).get(DID) == null + ||((LinkedHashMap)params).get(SIGNATURE) == null || ((LinkedHashMap)params).get(MESSAGE) == null) { + return false; + } + else { + return true; + } + } + case GET_ALL_DIDS : { + if (((LinkedHashMap)params).get(TOKEN) == null) { + return false; + } + else { + return true; + } + } + + case LOGIN : + case CREATE_ACCOUNT : { + if (((LinkedHashMap)params).get(USERNAME) == null || ((LinkedHashMap)params).get(PASSWORD) == null ) { + return false; + } + else { + return true; + } + } + + case LOGOUT : { + if (((LinkedHashMap)params).get(TOKEN) == null) { + return false; + } + else { + return true; + } + + } + + } + return false; + } + + private static String processInput(String input) { + + try { + Command cmd = objectMapper.readValue(input, Command.class); + if (cmd.getOperation() == null) + throw new Exception(); + Object params = cmd.getParams(); + String walletName; + if (!cmd.getOperation().equals(LOGIN) && !cmd.getOperation().equals(CREATE_ACCOUNT)) { + if (!verifyParams(CREATE_DID, params)) { + return createErrorResponse(706, "Missing token"); + } + if (!isTokenValid(getToken(params))) { + return createErrorResponse(705, "Unauthorized"); + } + } + switch (cmd.getOperation()) { + case CREATE_DID : { + if (verifyParams(CREATE_DID,params)) { + walletName = getWalletName(params); + try { + + DidParams didParams = DidCommands.createDid(walletName, null, null); + Response response = new Response(); + response.setStatus(CREATED); + response.setValue(didParams); + return objectMapper.writeValueAsString(response); + } + catch (Exception e) { + return createErrorMessageFromException(e); + } + } + else return createErrorResponse(700, "wrong parameters"); + } + case SIGN_DATA : { + if (verifyParams(SIGN_DATA,params)) { + walletName = getWalletName(params); + String did = getDid(params); + String dataToSign = getDataToSign(params); + return Signature.Base64EncodedSignature(walletName,did, dataToSign); + } + else return createErrorResponse(700, "wrong parameters"); + } + case VERIFY_SIGNATURE : { + if (verifyParams(VERIFY_SIGNATURE, params)) { + walletName = getWalletName(params); + String did = getDid(params); + String signature = getSignature(params); + String message = getMessage(params); + return Signature.VerifyBase64EncodedSignature(walletName, signature, message, did); + } + else return createErrorResponse(700, "wrong parameters"); + } + + case GET_ALL_DIDS : { + if (verifyParams(GET_ALL_DIDS, params)) { + walletName = getWalletName(params); + return DidCommands.getAllDids(walletName); + } + } + + case CREATE_ACCOUNT : { + if (verifyParams(CREATE_ACCOUNT, params)) { + String username = getUsername(params); + String password = getPassword(params); + if (UserStore.findUserByUsername(username) != null) { + return createErrorResponse(703, "user with name " + username + " already exitss"); + } + UserAccount account = new UserAccount(); + account.setUsername(username); + //userstore hashes pwd before saving + account.setPassword(password); + account.setWalletname(java.util.UUID.randomUUID().toString()); + UserStore.storeNewUser(account); + + try { + Agent.initializeAgent(account.getWalletname(), account.getUsername()); + + CreateAccountResponse createAccountResponse = new CreateAccountResponse(); + createAccountResponse.setUsername(username); + createAccountResponse.setWalletname(account.getWalletname()); + Response resp = new Response(StatusCodes.SUCCESS, createAccountResponse); + return getJsonValue(resp); + } + catch (Exception e){ + UserStore.deleteUser(account.getUsername()); + return createErrorResponse(800, "Could not initialize agent"); + } + } + } + + case LOGIN : { + if (verifyParams(LOGIN, params)) { + String username = getUsername(params); + String password = getPassword(params); + if (UserStore.login(username, password)) { + Token token = new Token(); + token.setToken(java.util.UUID.randomUUID().toString()); + token.setUsername(username); + TokenStore.storeNewToken(token); + LoginResponse loginResponse = new LoginResponse(); + loginResponse.setToken(token.getToken()); + Response resp = new Response(StatusCodes.SUCCESS, loginResponse); + return getJsonValue(resp); + } + return createErrorResponse(704, "wrong username or password"); + } + } + + case LOGOUT : { + if (verifyParams(LOGOUT, params)) { + String tokenId = getToken(params); + if (TokenStore.findTokenByTokenId(tokenId) != null) { + TokenStore.removeToken(tokenId); + LogoutResponse logoutResponse = new LogoutResponse(); + logoutResponse.setLoggedout(true); + Response resp = new Response(StatusCodes.SUCCESS, logoutResponse); + return getJsonValue(resp); + } + else { + return createErrorResponse(705, "Incorrect token"); + } + } + } + + default : { + return createErrorResponse(701, "unknown operation"); + } + } + + + } + catch (Exception e) { + //e.printStackTrace(); + return createErrorResponse(700, "malformed request"); + } + + } + + private static String createErrorResponse(int code, String description) { + + ErrorMessage error = new ErrorMessage(ErrorCode.valueOf(code).toString(), description); + Response response = new Response(ERROR, error); + return getJsonValue(response); + } + + + public static String getJsonValue(Object obj) { + ObjectMapper objectMapper = new ObjectMapper(); + try { + return objectMapper.writeValueAsString(obj); + } + catch (Exception e) { + return "{\"status\":\"ERROR\",\"value\":{\"errorcode\":\"INTERNAL_ERROR\",\"description\":\"ObjectMapper exception\"}}"; + } + } + + + +} diff --git a/src/main/java/fi/trustnet/browserextension/Command.java b/src/main/java/fi/trustnet/browserextension/Command.java new file mode 100644 index 0000000..83c9cbe --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/Command.java @@ -0,0 +1,29 @@ +package fi.trustnet.browserextension; + +import java.util.LinkedHashMap; + + +public class Command { + private String operation; + private Object params; + + public Command() { + this.params = new LinkedHashMap<>(); + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } + + public Object getParams() { + return params; + } + + public void setParams(Object params) { + this.params = params; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/CommandCodes.java b/src/main/java/fi/trustnet/browserextension/CommandCodes.java new file mode 100644 index 0000000..e54157b --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/CommandCodes.java @@ -0,0 +1,14 @@ +package fi.trustnet.browserextension; + +public class CommandCodes { + public static final String CREATE_WALLET = "CREATE_WALLET"; + public static final String CREATE_DID = "CREATE_DID"; + public static final String SIGN_DATA = "SIGN_DATA"; + public static final String VERIFY_SIGNATURE = "VERIFY_SIGNATURE"; + public static final String GET_ALL_DIDS = "GET_ALL_DIDS"; + public static final String CREATE_ACCOUNT = "CREATE_ACCOUNT"; + public static final String LOGIN = "LOGIN"; + public static final String LOGOUT = "LOGOUT"; + + +} diff --git a/src/main/java/fi/trustnet/browserextension/Configuration.java b/src/main/java/fi/trustnet/browserextension/Configuration.java new file mode 100644 index 0000000..2991643 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/Configuration.java @@ -0,0 +1,12 @@ +package fi.trustnet.browserextension; + +public class Configuration { + public static final String WALLET_BASEPATH = "jdbc:sqlite:/home/samuli/.indy_client/wallet/"; + public static final String USER_DB_FILE = "/home/samuli/.indy_client/users.db"; + public static final String TOKEN_DB_FILE = "/home/samuli/.indy_client/tokens.db"; + public static final String LIBINDY_LOCATION = "./lib/libindy.so"; + //set to true before creating jar for browser extension + public static final boolean RUN_AS_EXTENSION = false; + + public static final String NETWORK_NAME = "default_pool"; +} diff --git a/src/main/java/fi/trustnet/browserextension/DidCommands.java b/src/main/java/fi/trustnet/browserextension/DidCommands.java new file mode 100644 index 0000000..0d1878d --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/DidCommands.java @@ -0,0 +1,87 @@ +package fi.trustnet.browserextension; + +import fi.trustnet.browserextension.user.Logger; +import org.hyperledger.indy.sdk.did.Did; +import org.hyperledger.indy.sdk.did.DidJSONParameters; +import org.hyperledger.indy.sdk.did.DidResults; +import org.hyperledger.indy.sdk.pool.Pool; +import org.hyperledger.indy.sdk.wallet.Wallet; + + +import static fi.trustnet.browserextension.Configuration.NETWORK_NAME; +import static fi.trustnet.browserextension.Configuration.RUN_AS_EXTENSION; + +public class DidCommands { + + + public static DidParams createDid(String walletName, String didMetadata, String serviceUrl) throws Exception { + Pool pool = null; + Wallet wallet = null; + try { + pool = Pool.openPoolLedger(NETWORK_NAME, "{}").get(); + wallet = Wallet.openWallet(walletName, null, null).get(); + + // USE GUID as seed, should be replaced with real PRNG; + String seed = java.util.UUID.randomUUID().toString(); + seed = seed.replaceAll("-", ""); + + + DidJSONParameters.CreateAndStoreMyDidJSONParameter createAndStoreMyDidJSONParameter = new DidJSONParameters.CreateAndStoreMyDidJSONParameter(null, seed , null, null); + DidResults.CreateAndStoreMyDidResult createAndStoreMyDidResult = Did.createAndStoreMyDid(wallet, createAndStoreMyDidJSONParameter.toJson()).get(); + + + + String did = createAndStoreMyDidResult.getDid(); + String verkey = createAndStoreMyDidResult.getVerkey(); + + if (didMetadata != null) { + Did.setDidMetadata(wallet, did, didMetadata); + } + if (serviceUrl != null) { + Did.setEndpointForDid(wallet, did, serviceUrl, null); + } + + DidParams didParams = new DidParams(); + didParams.setDid(did); + didParams.setVerkey(verkey); + didParams.setUrl(serviceUrl); + didParams.setDidMetadata(didMetadata); + + wallet.closeWallet().get(); + wallet = null; + pool.closePoolLedger().get(); + pool = null; + + return didParams; + } + catch (Exception e) { + try { + if (RUN_AS_EXTENSION) + Logger.writeToLog("createDid" + e.getMessage()); + else + System.out.println(e.getMessage()); + + if (wallet != null) + wallet.closeWallet().get(); + if (pool != null) + pool.closePoolLedger().get(); + throw e; + + } + catch (Exception ex) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("createDid" + ex.getMessage()); + else + System.out.println(ex.getMessage()); + + throw ex; + } + } + } + + public static String getAllDids(String walletName) { + WalletDbReader walletDbReader = new WalletDbReader(); + return walletDbReader.getAllDids(walletName); + } + +} diff --git a/src/main/java/fi/trustnet/browserextension/DidList.java b/src/main/java/fi/trustnet/browserextension/DidList.java new file mode 100644 index 0000000..83e2912 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/DidList.java @@ -0,0 +1,20 @@ +package fi.trustnet.browserextension; + +import java.util.LinkedList; +import java.util.List; + +public class DidList { + private List dids; + + public DidList() { + this.dids = new LinkedList<>(); + } + + public List getDids() { + return dids; + } + + public void setDids(List dids) { + this.dids = dids; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/DidParams.java b/src/main/java/fi/trustnet/browserextension/DidParams.java new file mode 100644 index 0000000..8232f4a --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/DidParams.java @@ -0,0 +1,47 @@ +package fi.trustnet.browserextension; + +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class DidParams { + private String did; + private String verkey; + private String url; + private Object didMetadata; + + public DidParams() { + } + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + + public String getVerkey() { + return verkey; + } + + public void setVerkey(String verkey) { + this.verkey = verkey; + } + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + public Object getDidMetadata() { + return didMetadata; + } + + public void setDidMetadata(Object didMetadata) { + this.didMetadata = didMetadata; + } +} + diff --git a/src/main/java/fi/trustnet/browserextension/PayloadKeys.java b/src/main/java/fi/trustnet/browserextension/PayloadKeys.java new file mode 100644 index 0000000..9fb2a38 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/PayloadKeys.java @@ -0,0 +1,14 @@ +package fi.trustnet.browserextension; + +public class PayloadKeys { + public static final String WALLET_NAME = "walletname"; + public static final String DID = "did"; + public static final String DATA_TO_SIGN = "datatosign"; + public static final String SIGNATURE = "signature"; + public static final String MESSAGE = "message"; + public static final String USERNAME = "username"; + public static final String PASSWORD = "password"; + public static final String TOKEN = "token"; + + +} diff --git a/src/main/java/fi/trustnet/browserextension/Signature.java b/src/main/java/fi/trustnet/browserextension/Signature.java new file mode 100644 index 0000000..2d19d85 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/Signature.java @@ -0,0 +1,118 @@ +package fi.trustnet.browserextension; + +import fi.trustnet.browserextension.responses.Response; +import fi.trustnet.browserextension.responses.SignatureResult; +import fi.trustnet.browserextension.responses.SignatureVerificationResult; +import fi.trustnet.browserextension.user.Logger; +import org.hyperledger.indy.sdk.crypto.Crypto; +import org.hyperledger.indy.sdk.did.Did; +import org.hyperledger.indy.sdk.pool.Pool; +import org.hyperledger.indy.sdk.wallet.Wallet; + +import java.util.Base64; + + +import static fi.trustnet.browserextension.App.getJsonValue; +import static fi.trustnet.browserextension.Configuration.NETWORK_NAME; +import static fi.trustnet.browserextension.Configuration.RUN_AS_EXTENSION; +import static fi.trustnet.browserextension.errors.ExceptionMessage.createErrorMessageFromException; + +public class Signature { + + public static String Base64EncodedSignature(String walletName, String did, String dataToSign) { + Pool pool =null; + Wallet wallet = null; + try { + pool = Pool.openPoolLedger(NETWORK_NAME, "{}").get(); + wallet = Wallet.openWallet(walletName, null, null).get(); + String key = Did.keyForLocalDid(wallet, did).get(); + byte[] signed = Crypto.cryptoSign(wallet, key,dataToSign.getBytes()).get(); + byte[] encoded = Base64.getEncoder().encode(signed); + wallet.closeWallet().get(); + wallet = null; + pool.closePoolLedger().get(); + pool = null; + + + SignatureResult signatureResult = new SignatureResult(); + signatureResult.setDid(did); + signatureResult.setVerkey(key); + signatureResult.setSignature(new String(encoded)); + signatureResult.setDataToSign(dataToSign); + signatureResult.setWallet(walletName); + Response response = new Response(StatusCodes.SUCCESS,signatureResult); + + return getJsonValue(response); + } + catch (Exception e) { + try{ + if (RUN_AS_EXTENSION) + Logger.writeToLog("Base64EncodedSignature" + e.getMessage()); + else + System.out.println(e.getMessage()); + + if (pool != null) + pool.closePoolLedger().get(); + if (wallet != null) + wallet.closeWallet().get(); + return createErrorMessageFromException(e); + } + catch (Exception ex) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("Base64EncodedSignature" + ex.getMessage()); + else + System.out.println(ex.getMessage()); + return createErrorMessageFromException(ex); + } + } + } + public static String VerifyBase64EncodedSignature(String walletName, String signature, String message, String did) { + Pool pool = null; + Wallet wallet = null; + try { + pool = Pool.openPoolLedger(NETWORK_NAME, "{}").get(); + wallet = Wallet.openWallet(walletName, null, null).get(); + String key = Did.keyForLocalDid(wallet, did).get(); + Boolean verified = Crypto.cryptoVerify(key, message.getBytes(), Base64.getDecoder().decode(signature)).get(); + wallet.closeWallet().get(); + pool.closePoolLedger().get(); + + SignatureVerificationResult signatureVerificationResult = new SignatureVerificationResult(); + signatureVerificationResult.setDid(did); + signatureVerificationResult.setMessage(message); + signatureVerificationResult.setVerified(verified); + signatureVerificationResult.setSignature(signature); + + + if (verified) { + Response response = new Response(StatusCodes.SUCCESS, signatureVerificationResult); + return getJsonValue(response); + } + else { + Response response = new Response(StatusCodes.FAIL, signatureVerificationResult); + return getJsonValue(response); + } + } + catch (Exception e){ + if (RUN_AS_EXTENSION) + Logger.writeToLog("VerifyBase64EncodedSignature" + e.getMessage()); + else + System.out.println(e.getMessage()); + try { + if (wallet != null) + wallet.closeWallet().get(); + if (pool != null) + pool.closePoolLedger().get(); + } + catch (Exception ex) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("Base64EncodedSignature" + ex.getMessage()); + else + System.out.println(ex.getMessage()); + + return createErrorMessageFromException(ex); + } + return createErrorMessageFromException(e); + } + } +} diff --git a/src/main/java/fi/trustnet/browserextension/StatusCodes.java b/src/main/java/fi/trustnet/browserextension/StatusCodes.java new file mode 100644 index 0000000..6e0b7ef --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/StatusCodes.java @@ -0,0 +1,8 @@ +package fi.trustnet.browserextension; + +public class StatusCodes { + public static final String SUCCESS = "SUCCESS"; + public static final String CREATED = "CREATED"; + public static final String ERROR = "ERROR"; + public static final String FAIL = "FAIL"; +} diff --git a/src/main/java/fi/trustnet/browserextension/WalletDbReader.java b/src/main/java/fi/trustnet/browserextension/WalletDbReader.java new file mode 100644 index 0000000..930b2a8 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/WalletDbReader.java @@ -0,0 +1,64 @@ +package fi.trustnet.browserextension; + +import com.fasterxml.jackson.databind.ObjectMapper; +import fi.trustnet.browserextension.responses.Response; +import fi.trustnet.browserextension.user.Logger; + +import java.sql.*; + +import static fi.trustnet.browserextension.App.getJsonValue; +import static fi.trustnet.browserextension.Configuration.RUN_AS_EXTENSION; +import static fi.trustnet.browserextension.Configuration.WALLET_BASEPATH; +import static fi.trustnet.browserextension.errors.ExceptionMessage.createErrorMessageFromException; + +public class WalletDbReader { + + + private Connection connect(String walletName) { + // SQLite connection string + Connection conn = null; + try { + Class.forName("org.sqlite.JDBC"); + String url = WALLET_BASEPATH + walletName + "/sqlite.db"; + + try { + conn = DriverManager.getConnection(url); + } catch (SQLException e) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("WalletDbReader connect" + e.getMessage()); + else System.out.println(e.getMessage()); + } + } catch (Exception e) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("WalletDbReader connect" + e.getMessage()); + else System.out.println(e.getMessage()); + } + return conn; + } + + + public String getAllDids(String walletName){ + String sql = "SELECT * FROM wallet WHERE KEY LIKE \"my%\""; + ObjectMapper objectMapper = new ObjectMapper(); + try (Connection conn = this.connect(walletName); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)) { + + DidList didList = new DidList(); + // loop through the result set + while (rs.next()) { + DidParams didParams = objectMapper.readValue(rs.getString("value"), DidParams.class); + didList.getDids().add(didParams); + } + Response response = new Response(StatusCodes.SUCCESS,didList); + + return getJsonValue(response); + } catch (Exception e) { + if (RUN_AS_EXTENSION) + Logger.writeToLog("WalletDbReader getAllDids" + e.getMessage()); + else System.out.println(e.getMessage()); + + return createErrorMessageFromException(e); + } + } +} \ No newline at end of file diff --git a/src/main/java/fi/trustnet/browserextension/errors/ErrorCode.java b/src/main/java/fi/trustnet/browserextension/errors/ErrorCode.java new file mode 100644 index 0000000..ca757e9 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/errors/ErrorCode.java @@ -0,0 +1,275 @@ +package fi.trustnet.browserextension.errors; + +import java.util.HashMap; +import java.util.Map; + + + +/** + * Enumeration of error codes returned by the indy SDK. + */ +public enum ErrorCode { + + /** + * Success + */ + Success(0), + + // Common errors + + /** + * Caller passed invalid value as param 1 (null, invalid json and etc..) + */ + CommonInvalidParam1(100), + + /** + * Caller passed invalid value as param 2 (null, invalid json and etc..) + */ + CommonInvalidParam2(101), + + /** + * Caller passed invalid value as param 3 (null, invalid json and etc..) + */ + CommonInvalidParam3(102), + + /** + * Caller passed invalid value as param 4 (null, invalid json and etc..) + */ + CommonInvalidParam4(103), + + /** + * Caller passed invalid value as param 5 (null, invalid json and etc..) + */ + CommonInvalidParam5(104), + + /** + * Caller passed invalid value as param 6 (null, invalid json and etc..) + */ + CommonInvalidParam6(105), + + /** + * Caller passed invalid value as param 7 (null, invalid json and etc..) + */ + CommonInvalidParam7(106), + + /** + * Caller passed invalid value as param 8 (null, invalid json and etc..) + */ + CommonInvalidParam8(107), + + /** + * Caller passed invalid value as param 9 (null, invalid json and etc..) + */ + CommonInvalidParam9(108), + + /** + * Caller passed invalid value as param 10 (null, invalid json and etc..) + */ + CommonInvalidParam10(109), + + /** + * Caller passed invalid value as param 11 (null, invalid json and etc..) + */ + CommonInvalidParam11(110), + + /** + * Caller passed invalid value as param 12 (null, invalid json and etc..) + */ + CommonInvalidParam12(111), + + /** + * Invalid library state was detected in runtime. It signals library bug + */ + CommonInvalidState(112), + + /** + * Object (json, config, key, claim and etc...) passed by library caller has invalid structure + */ + CommonInvalidStructure(113), + + /** + * IO ErrorMessage + */ + CommonIOError(114), + + // Wallet errors + + /** + * Caller passed invalid wallet handle + */ + WalletInvalidHandle(200), + + /** + * Unknown type of wallet was passed on create_wallet + */ + WalletUnknownTypeError(201), + + /** + * Attempt to register already existing wallet type + */ + WalletTypeAlreadyRegisteredError(202), + + /** + * Attempt to create wallet with name used for another exists wallet + */ + WalletAlreadyExistsError(203), + + /** + * Requested entity id isn't present in wallet + */ + WalletNotFoundError(204), + + /** + * Trying to use wallet with pool that has different name + */ + WalletIncompatiblePoolError(205), + + /** + * Trying to open wallet that was opened already + */ + WalletAlreadyOpenedError(206), + + /** + * Attempt to open encrypted wallet with invalid credentials + */ + WalletAccessFailed(207), + + // Ledger errors + + /** + * Trying to open pool ledger that wasn't created before + */ + PoolLedgerNotCreatedError(300), + + /** + * Caller passed invalid pool ledger handle + */ + PoolLedgerInvalidPoolHandle(301), + + /** + * Pool ledger terminated + */ + PoolLedgerTerminated(302), + + /** + * No concensus during ledger operation + */ + LedgerNoConsensusError(303), + + /** + * Attempt to send transaction without the necessary privileges + */ + LedgerSecurityError(305), + + /** + * Attempt to create pool ledger config with name used for another existing pool + */ + PoolLedgerConfigAlreadyExistsError(306), + + /** + * Timeout for action + */ + PoolLedgerTimeout(307), + + // Crypto errors + + /** + * Revocation registry is full and creation of new registry is necessary + */ + AnoncredsRevocationRegistryFullError(400), + + /** + * ??? + */ + AnoncredsInvalidUserRevocIndex(401), + + /** + * ??? + */ + AnoncredsAccumulatorIsFull(402), + + /** + * ??? + */ + AnoncredsNotIssuedError(403), + + /** + * Attempt to generate master secret with dupplicated name + */ + AnoncredsMasterSecretDuplicateNameError(404), + + /** + * ??? + */ + AnoncredsProofRejected(405), + + /** + * Attempt to use a revoked claim. + */ + AnoncredsClaimRevoked(406), + + /** + * Attempt to create claim definition with duplicated did schema pair. + */ + AnoncredsClaimDefAlreadyExistsError(407), + + // Crypto errors + + /** + * Unknown format of DID entity keys + */ + UnknownCryptoTypeError(500), + + + /** + * Attempt to create duplicate did. + */ + DidAlreadyExistsError(600), + + //Added own error codes + MalformedRequest(700), + UnknownCommand(701), + GenericError(702), + UserAlreadyExists(703), + WrongUsernameOrPssword(704), + Unauthorized(705), + MissingToken(706), + InternalServerError(800); + + private int value; + private static Map map = new HashMap(); + + private ErrorCode(int value) { + + this.value = value; + } + + static { + + for (ErrorCode errorCode : ErrorCode.values()) { + + map.put(Integer.valueOf(errorCode.value), errorCode); + } + } + + /** + * Gets the ErrorCode that corresponds to the specified int value. + * + * @param value The integer to get the error code for. + * @return The ErrorCode that corresponds to the specified integer. + */ + public static ErrorCode valueOf(int value) { + + return map.get(Integer.valueOf(value)); + } + + /** + * Gets the integer value for a specific ErrorCode. + * + * @return The integer value of the ErrorCode. + */ + public int value() { + + return this.value; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/errors/ErrorMessage.java b/src/main/java/fi/trustnet/browserextension/errors/ErrorMessage.java new file mode 100644 index 0000000..3594eb3 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/errors/ErrorMessage.java @@ -0,0 +1,32 @@ +package fi.trustnet.browserextension.errors; + +public class ErrorMessage { + private String errorcode; + private String Description; + + public ErrorMessage(String errorcode, String description) { + this.errorcode = errorcode; + Description = description; + } + + public ErrorMessage() { + } + + public String getErrorcode() { + return errorcode; + } + + public void setErrorcode(String errorcode) { + this.errorcode = errorcode; + } + + public String getDescription() { + return Description; + } + + public void setDescription(String description) { + Description = description; + } + + +} diff --git a/src/main/java/fi/trustnet/browserextension/errors/ExceptionMessage.java b/src/main/java/fi/trustnet/browserextension/errors/ExceptionMessage.java new file mode 100644 index 0000000..146c6fe --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/errors/ExceptionMessage.java @@ -0,0 +1,30 @@ +package fi.trustnet.browserextension.errors; + + +import org.hyperledger.indy.sdk.IndyException; +import fi.trustnet.browserextension.responses.Response; + + +import static com.sun.xml.internal.ws.api.message.Packet.Status.Response; +import static fi.trustnet.browserextension.App.getJsonValue; +import static fi.trustnet.browserextension.StatusCodes.ERROR; + + +public class ExceptionMessage { + public static String createErrorMessageFromException(Exception e) { + if (e.getCause() != null && IndyException.class.isAssignableFrom(e.getCause().getClass())) { + int errCode = ((IndyException)(e.getCause())).getSdkErrorCode(); + String description = ((IndyException)(e.getCause())).getMessage(); + return createErrorResponse(errCode, description); + } + return createErrorResponse(702, e.getMessage()); + } + + private static String createErrorResponse(int code, String description) { + + ErrorMessage error = new ErrorMessage(ErrorCode.valueOf(code).toString(), description); + Response response = new Response(ERROR, error); + return getJsonValue(response); + } + +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/CreateAccountResponse.java b/src/main/java/fi/trustnet/browserextension/responses/CreateAccountResponse.java new file mode 100644 index 0000000..c121bd3 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/CreateAccountResponse.java @@ -0,0 +1,25 @@ +package fi.trustnet.browserextension.responses; + +public class CreateAccountResponse { + private String username; + private String walletname; + + public CreateAccountResponse() { + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getWalletname() { + return walletname; + } + + public void setWalletname(String walletname) { + this.walletname = walletname; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/LoginResponse.java b/src/main/java/fi/trustnet/browserextension/responses/LoginResponse.java new file mode 100644 index 0000000..1d17e8d --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/LoginResponse.java @@ -0,0 +1,16 @@ +package fi.trustnet.browserextension.responses; + +public class LoginResponse { + private String token; + + public LoginResponse() { + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/LogoutResponse.java b/src/main/java/fi/trustnet/browserextension/responses/LogoutResponse.java new file mode 100644 index 0000000..80e2184 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/LogoutResponse.java @@ -0,0 +1,16 @@ +package fi.trustnet.browserextension.responses; + +public class LogoutResponse { + public LogoutResponse() { + } + + private boolean loggedout; + + public boolean isLoggedout() { + return loggedout; + } + + public void setLoggedout(boolean loggedout) { + this.loggedout = loggedout; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/Response.java b/src/main/java/fi/trustnet/browserextension/responses/Response.java new file mode 100644 index 0000000..6823bb5 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/Response.java @@ -0,0 +1,37 @@ +package fi.trustnet.browserextension.responses; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonInclude; + +@JsonInclude(JsonInclude.Include.NON_NULL) +public class Response { + private String status; + Object value; + + public Response() { + } + + public Response(String status, Object value) { + this.status = status; + this.value = value; + } + + public String getStatus() { + return status; + } + + public void setStatus(String status) { + this.status = status; + } + + public Object getValue() { + return value; + } + + public void setValue(Object value) { + this.value = value; + } + + +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/SignatureResult.java b/src/main/java/fi/trustnet/browserextension/responses/SignatureResult.java new file mode 100644 index 0000000..a303afa --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/SignatureResult.java @@ -0,0 +1,54 @@ +package fi.trustnet.browserextension.responses; + +public class SignatureResult { + private String dataToSign; + private String wallet; + private String signature; + private String verkey; + private String did; + + public SignatureResult() { + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public String getDataToSign() { + return dataToSign; + } + + public void setDataToSign(String dataToSign) { + this.dataToSign = dataToSign; + } + + public String getWallet() { + return wallet; + } + + public void setWallet(String wallet) { + this.wallet = wallet; + } + + public String getVerkey() { + return verkey; + } + + public void setVerkey(String verkey) { + this.verkey = verkey; + } + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + + +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/SignatureVerificationResult.java b/src/main/java/fi/trustnet/browserextension/responses/SignatureVerificationResult.java new file mode 100644 index 0000000..c004e9d --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/SignatureVerificationResult.java @@ -0,0 +1,44 @@ +package fi.trustnet.browserextension.responses; + +public class SignatureVerificationResult { + private boolean verified; + private String message; + private String signature; + private String did; + + public SignatureVerificationResult() { + } + + public boolean isVerified() { + return verified; + } + + public void setVerified(boolean verified) { + this.verified = verified; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + } + + public String getDid() { + return did; + } + + public void setDid(String did) { + this.did = did; + } + +} diff --git a/src/main/java/fi/trustnet/browserextension/responses/WalletResult.java b/src/main/java/fi/trustnet/browserextension/responses/WalletResult.java new file mode 100644 index 0000000..19d9552 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/responses/WalletResult.java @@ -0,0 +1,25 @@ +package fi.trustnet.browserextension.responses; + +public class WalletResult { + private String walletname; + private String operation; + + public WalletResult() { + } + + public String getWalletname() { + return walletname; + } + + public void setWalletname(String walletname) { + this.walletname = walletname; + } + + public String getOperation() { + return operation; + } + + public void setOperation(String operation) { + this.operation = operation; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/user/Logger.java b/src/main/java/fi/trustnet/browserextension/user/Logger.java new file mode 100644 index 0000000..4b67b5e --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/user/Logger.java @@ -0,0 +1,16 @@ +package fi.trustnet.browserextension.user; + +import java.io.FileWriter; + +public class Logger { + public static void writeToLog(String entry) { + try { + FileWriter fw = new FileWriter("exceptions.txt", true); + fw.write(entry + "\n"); + fw.flush(); + fw.close(); + } + catch (Exception e) { + } + } +} diff --git a/src/main/java/fi/trustnet/browserextension/user/Token.java b/src/main/java/fi/trustnet/browserextension/user/Token.java new file mode 100644 index 0000000..8cc1820 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/user/Token.java @@ -0,0 +1,27 @@ +package fi.trustnet.browserextension.user; + +public class Token { + + private String token; + private String username; + + public Token() { + + } + + public String getToken() { + return token; + } + + public void setToken(String token) { + this.token = token; + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/user/TokenStore.java b/src/main/java/fi/trustnet/browserextension/user/TokenStore.java new file mode 100644 index 0000000..9630ba9 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/user/TokenStore.java @@ -0,0 +1,98 @@ +package fi.trustnet.browserextension.user; + +import java.sql.*; + +import static fi.trustnet.browserextension.Configuration.TOKEN_DB_FILE; + +public class TokenStore { + private static final String TABLENAME = "tokens"; + + private static Connection connect() { + + Connection conn = null; + try { + Class.forName("org.sqlite.JDBC"); + String url = "jdbc:sqlite:" + TOKEN_DB_FILE; + + try { + conn = DriverManager.getConnection(url); + } catch (SQLException e) { + //System.out.println(e.getMessage()); + } + } catch (Exception e) { + + } + return conn; + } + + private static void createTables() { + + String sql = "CREATE TABLE IF NOT EXISTS " + TABLENAME + " (\n" + + " token text PRIMARY KEY,\n" + + " username text NOT NULL\n" + + ");"; + + try (Connection conn = connect(); + Statement stmt = conn.createStatement()) { + // create a new table + stmt.execute(sql); + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); + } + } + + + + + public static void initTokenDb() { + createTables(); + } + + public static void storeNewToken(Token token) { + String sql = "INSERT INTO " + TABLENAME +" (token,username) VALUES(?,?)"; + + try (Connection conn = connect(); + PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, token.getToken()); + pstmt.setString(2, token.getUsername()); + pstmt.executeUpdate(); + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); + } + } + + public static Token findTokenByTokenId(String tokenId) { + String sql = "SELECT * FROM " + TABLENAME + " WHERE token=\"" + tokenId +"\""; + Token token = null; + try (Connection conn = connect(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)){ + + if(rs.next()) { + token = new Token(); + token.setToken(rs.getString("token")); + token.setUsername(rs.getString("username")); + } + + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); + } + return token; + } + + public static void removeToken(String tokenId) { + String sql = "DELETE FROM " + TABLENAME + " WHERE token=\"" +tokenId + "\""; + try (Connection conn = connect(); + PreparedStatement preparedStatement = conn.prepareStatement(sql)) { + + preparedStatement.executeUpdate(); + } + + catch (SQLException e) { + Logger.writeToLog(e.getMessage()); + } + } + + +} + diff --git a/src/main/java/fi/trustnet/browserextension/user/UserAccount.java b/src/main/java/fi/trustnet/browserextension/user/UserAccount.java new file mode 100644 index 0000000..5af4c30 --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/user/UserAccount.java @@ -0,0 +1,34 @@ +package fi.trustnet.browserextension.user; + +public class UserAccount { + private String username; + private String password; + private String walletname; + + public UserAccount() { + } + + public String getUsername() { + return username; + } + + public void setUsername(String username) { + this.username = username; + } + + public String getPassword() { + return password; + } + + public void setPassword(String password) { + this.password = password; + } + + public String getWalletname() { + return walletname; + } + + public void setWalletname(String walletname) { + this.walletname = walletname; + } +} diff --git a/src/main/java/fi/trustnet/browserextension/user/UserStore.java b/src/main/java/fi/trustnet/browserextension/user/UserStore.java new file mode 100644 index 0000000..3355b7f --- /dev/null +++ b/src/main/java/fi/trustnet/browserextension/user/UserStore.java @@ -0,0 +1,136 @@ +package fi.trustnet.browserextension.user; + +import org.mindrot.jbcrypt.BCrypt; + +import javax.jws.soap.SOAPBinding; +import java.sql.*; + +import static fi.trustnet.browserextension.Configuration.USER_DB_FILE; + +public class UserStore { + private static final String TABLENAME = "users"; + private static int workload = 10; + + + private static Connection connect() { + // SQLite connection string + Connection conn = null; + try { + Class.forName("org.sqlite.JDBC"); + String url = "jdbc:sqlite:" + USER_DB_FILE; + + try { + conn = DriverManager.getConnection(url); + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); + } + } catch (Exception e) { + + } + return conn; + } + + private static void createTables() { + + String sql = "CREATE TABLE IF NOT EXISTS " + TABLENAME + " (\n" + + " id integer PRIMARY KEY,\n" + + " username text UNIQUE NOT NULL,\n" + + " password text NOT NULL, \n" + + " walletname text NOT NULL \n" + + ");"; + + try (Connection conn = connect(); + Statement stmt = conn.createStatement()) { + // create a new table + stmt.execute(sql); + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); } + } + + public static void initUserDb() { + createTables(); + } + + public static void storeNewUser(UserAccount userAccount) { + String sql = "INSERT INTO " + TABLENAME +" (username,password, walletname) VALUES(?,?,?)"; + + try (Connection conn = connect(); + PreparedStatement pstmt = conn.prepareStatement(sql)) { + pstmt.setString(1, userAccount.getUsername()); + pstmt.setString(2, hashPassword(userAccount.getPassword())); + pstmt.setString(3, userAccount.getWalletname()); + pstmt.executeUpdate(); + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); } + } + + public static UserAccount findUserByUsername(String name) { + String sql = "SELECT * FROM " + TABLENAME + " WHERE username=\"" + name +"\""; + UserAccount userAccount = null; + try (Connection conn = connect(); + Statement stmt = conn.createStatement(); + ResultSet rs = stmt.executeQuery(sql)){ + if(rs.next()) { + userAccount = new UserAccount(); + userAccount.setUsername(rs.getString("username")); + userAccount.setWalletname(rs.getString("walletname")); + userAccount.setPassword(rs.getString("password")); + } + + } catch (SQLException e) { + Logger.writeToLog(e.getMessage()); } + return userAccount; + } + + public static String getWalletNameByUsername(String username) { + UserAccount userAccount = findUserByUsername(username); + if (userAccount != null) { + return userAccount.getWalletname(); + } + else { + return null; + } + } + + public static void deleteUser(String username) { + String sql = "DELETE FROM " + TABLENAME + " WHERE username=\"" +username + "\""; + try (Connection conn = connect(); + PreparedStatement preparedStatement = conn.prepareStatement(sql)) { + + preparedStatement.executeUpdate(); + } + + catch (SQLException e) { + Logger.writeToLog(e.getMessage()); } + + } + public static boolean login(String username, String password) { + UserAccount userAccount = findUserByUsername(username); + if (checkPassword(password, userAccount.getPassword())) { + return true; + } + else { + return false; + } + } + + private static String hashPassword(String password_plaintext) { + String salt = BCrypt.gensalt(workload); + String hashed_password = BCrypt.hashpw(password_plaintext, salt); + + return(hashed_password); + } + + private static boolean checkPassword(String password_plaintext, String stored_hash) { + boolean password_verified = false; + + if(null == stored_hash || !stored_hash.startsWith("$2a$")) + //throw new java.lang.IllegalArgumentException("Invalid hash provided for comparison"); + Logger.writeToLog("checkPassword : Invalid hash provided for comparison"); + + password_verified = BCrypt.checkpw(password_plaintext, stored_hash); + + return(password_verified); + } + +} diff --git a/src/test/java/fi/trustnet/browserextension/AppTest.java b/src/test/java/fi/trustnet/browserextension/AppTest.java new file mode 100644 index 0000000..a9162bd --- /dev/null +++ b/src/test/java/fi/trustnet/browserextension/AppTest.java @@ -0,0 +1,20 @@ +package fi.trustnet.browserextension; + +import static org.junit.Assert.assertTrue; + +import org.junit.Test; + +/** + * Unit test for simple App. + */ +public class AppTest +{ + /** + * Rigorous Test :-) + */ + @Test + public void shouldAnswerWithTrue() + { + assertTrue( true ); + } +}