From af8cabbb280a48c199146795df5e74c4fe2eb0c2 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Mon, 13 May 2019 15:54:46 -0300 Subject: [PATCH 1/9] [headless] update dependencies --- briar-headless/build.gradle | 22 ++++++----- briar-headless/witness.gradle | 74 +++++++++++++++++------------------ 2 files changed, 48 insertions(+), 48 deletions(-) diff --git a/briar-headless/build.gradle b/briar-headless/build.gradle index 0c6eee26e..916d92f82 100644 --- a/briar-headless/build.gradle +++ b/briar-headless/build.gradle @@ -1,8 +1,8 @@ plugins { id 'java' id 'idea' - id 'org.jetbrains.kotlin.jvm' version '1.3.21' - id 'org.jetbrains.kotlin.kapt' version '1.3.21' + id 'org.jetbrains.kotlin.jvm' version '1.3.31' + id 'org.jetbrains.kotlin.kapt' version '1.3.31' id 'witness' } apply from: 'witness.gradle' @@ -14,25 +14,27 @@ dependencies { implementation project(path: ':briar-core', configuration: 'default') implementation project(path: ':bramble-java', configuration: 'default') - implementation 'io.javalin:javalin:2.7.0' - implementation 'org.slf4j:slf4j-simple:1.7.25' + implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31' + implementation 'io.javalin:javalin:2.8.0' + implementation 'org.slf4j:slf4j-simple:1.7.26' implementation 'com.fasterxml.jackson.core:jackson-databind:2.9.8' - implementation 'com.github.ajalt:clikt:1.6.0' + implementation 'com.github.ajalt:clikt:2.0.0' - kapt 'com.google.dagger:dagger-compiler:2.22.1' + def daggerVersion = '2.22.1' + kapt "com.google.dagger:dagger-compiler:$daggerVersion" testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput') - def junitVersion = '5.3.1' + def junitVersion = '5.4.2' testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" testImplementation "org.junit.jupiter:junit-jupiter-params:$junitVersion" testRuntime "org.junit.jupiter:junit-jupiter-engine:$junitVersion" - testImplementation "io.mockk:mockk:1.9.2" - testImplementation "org.skyscreamer:jsonassert:1.5.0" + testImplementation 'io.mockk:mockk:1.9.3' + testImplementation 'org.skyscreamer:jsonassert:1.5.0' testImplementation 'khttp:khttp:0.1.0' - kaptTest 'com.google.dagger:dagger-compiler:2.22.1' + kaptTest "com.google.dagger:dagger-compiler:$daggerVersion" } jar { diff --git a/briar-headless/witness.gradle b/briar-headless/witness.gradle index 2a393aa72..347be7028 100644 --- a/briar-headless/witness.gradle +++ b/briar-headless/witness.gradle @@ -3,7 +3,7 @@ dependencyVerification { 'com.fasterxml.jackson.core:jackson-annotations:2.9.0:jackson-annotations-2.9.0.jar:45d32ac61ef8a744b464c54c2b3414be571016dd46bfc2bec226761cf7ae457a', 'com.fasterxml.jackson.core:jackson-core:2.9.8:jackson-core-2.9.8.jar:d934dab0bd48994eeea2c1b493cb547158a338a80b58c4fbc8e85fb0905e105f', 'com.fasterxml.jackson.core:jackson-databind:2.9.8:jackson-databind-2.9.8.jar:2351c3eba73a545db9079f5d6d768347ad72666537362c8220fe3e950a55a864', - 'com.github.ajalt:clikt:1.6.0:clikt-1.6.0.jar:ebab34d5a60817bb7d471a67cd1740b91a5d99e224660bddbcf32bac1651a575', + 'com.github.ajalt:clikt:2.0.0:clikt-2.0.0.jar:c247adb96337e0799bf6d84f4c494df9d8f1e46e9157eacaf438d03323ee9475', 'com.google.code.findbugs:jsr305:1.3.9:jsr305-1.3.9.jar:905721a0eea90a81534abb7ee6ef4ea2e5e645fa1def0a5cd88402df1b46c9ed', 'com.google.dagger:dagger-compiler:2.22.1:dagger-compiler-2.22.1.jar:e5f28302cbe70a79d3620cddebfb8ec0736814f3980ffe1e673bfe3342f507d3', 'com.google.dagger:dagger-producers:2.22.1:dagger-producers-2.22.1.jar:f834a0082014213a68ff06a0f048d750178d02196c58b0b15beb367d32b97e35', @@ -16,20 +16,20 @@ dependencyVerification { 'com.google.j2objc:j2objc-annotations:1.1:j2objc-annotations-1.1.jar:2994a7eb78f2710bd3d3bfb639b2c94e219cedac0d4d084d516e78c16dddecf6', 'com.squareup:javapoet:1.11.1:javapoet-1.11.1.jar:9cbf2107be499ec6e95afd36b58e3ca122a24166cdd375732e51267d64058e90', 'com.vaadin.external.google:android-json:0.0.20131108.vaadin1:android-json-0.0.20131108.vaadin1.jar:dfb7bae2f404cfe0b72b4d23944698cb716b7665171812a0a4d0f5926c0fac79', - 'io.javalin:javalin:2.7.0:javalin-2.7.0.jar:0f345ea86419813b2ba45a6d64d284f15099ced9a6ce51cae815e4caec724429', - 'io.mockk:mockk-agent-api:1.9.2:mockk-agent-api-1.9.2.jar:396d56cdba086c1bf01d4402591bb7b8fe46de75110c627eb88d2cd3e58bf6f5', - 'io.mockk:mockk-agent-common:1.9.2:mockk-agent-common-1.9.2.jar:ac8ab7a568df79ec80449b05c633458397acf40e8ae5db58cd3966d463509ebc', - 'io.mockk:mockk-agent-jvm:1.9.2:mockk-agent-jvm-1.9.2.jar:acf0336dc1802cf70450b594adc8f61dce2a6942e8162789dab60f1b54256ae1', - 'io.mockk:mockk-common:1.9.2:mockk-common-1.9.2.jar:0f936f82427b0c7822cae8e303cdbd8ceee6204bed80eab3f18cf00f4b9b82a3', - 'io.mockk:mockk-dsl-jvm:1.9.2:mockk-dsl-jvm-1.9.2.jar:6f7a3093f05876b24b26db3b6d6a568e0c20253489a588dbc9c67b43eb838ad0', - 'io.mockk:mockk-dsl:1.9.2:mockk-dsl-1.9.2.jar:d681ad3a7063a2c7fb8f0164b8eb2fd0085fd9fb77af1a4f189039e73f2ec3c4', - 'io.mockk:mockk:1.9.2:mockk-1.9.2.jar:96ce20b64c6d05218fed0b99e93b9b49c2c3f40dd96273b53f2e448a598b1c57', + 'io.javalin:javalin:2.8.0:javalin-2.8.0.jar:1f2f8e60ba06b2d65058a4ca430fe74ba74c27c93b35c96a9c883bd960d6fb3f', + 'io.mockk:mockk-agent-api:1.9.3:mockk-agent-api-1.9.3.jar:90b9b54158ad31aafa414cb7889bd5a9b70b23e990c5a72eb0c17c3322e6d12d', + 'io.mockk:mockk-agent-common:1.9.3:mockk-agent-common-1.9.3.jar:a9ddd89f1e1393aa4b7e99d0032b961088bb8d51e48ff188ada3d1fa05696c88', + 'io.mockk:mockk-agent-jvm:1.9.3:mockk-agent-jvm-1.9.3.jar:4e0661778c531d2849d9636f7896bbba314307fb45b47a0107f6a7ad31d1d531', + 'io.mockk:mockk-common:1.9.3:mockk-common-1.9.3.jar:05b6d77650171b13194dd0edcc36656897d04267e85e9e89c4ec187bdaaa6a3d', + 'io.mockk:mockk-dsl-jvm:1.9.3:mockk-dsl-jvm-1.9.3.jar:86c5c158640d244d19b29e894827e9d8c27741b4e13ed2ed3bb54b7a4ee4220f', + 'io.mockk:mockk-dsl:1.9.3:mockk-dsl-1.9.3.jar:1ccb814a192a5e4d2c59369ddc2499e8417f49ec9834e4f3dc4619877fd6069a', + 'io.mockk:mockk:1.9.3:mockk-1.9.3.jar:875ec9f02fa42231510cade8c677b8598d9a0f5687b5cb25a1f188c1c41ef332', 'javax.annotation:jsr250-api:1.0:jsr250-api-1.0.jar:a1a922d0d9b6d183ed3800dfac01d1e1eb159f0e8c6f94736931c1def54a941f', 'javax.inject:javax.inject:1:javax.inject-1.jar:91c77044a50c481636c32d916fd89c9118a72195390452c81065080f957de7ff', 'javax.servlet:javax.servlet-api:3.1.0:javax.servlet-api-3.1.0.jar:af456b2dd41c4e82cf54f3e743bc678973d9fe35bd4d3071fa05c7e5333b8482', 'khttp:khttp:0.1.0:khttp-0.1.0.jar:48ab3bd22e461f2c2e74e3446d8f9568e24aab157f61fdc85ded6c0bfbe9a926', - 'net.bytebuddy:byte-buddy-agent:1.9.3:byte-buddy-agent-1.9.3.jar:547288e013a9d1f4a4ce2ab84c24e3edda6e433c7fa6b2c3c3613932671b05b1', - 'net.bytebuddy:byte-buddy:1.9.3:byte-buddy-1.9.3.jar:a27350be602caea67a33d31281496c84c69b5ab34ddc228e9ff2253fc8f9cd31', + 'net.bytebuddy:byte-buddy-agent:1.9.10:byte-buddy-agent-1.9.10.jar:8ed739d29132103250d307d2e8e3c95f07588ef0543ab11d2881d00768a5e182', + 'net.bytebuddy:byte-buddy:1.9.10:byte-buddy-1.9.10.jar:2936debc4d7b6c534848d361412e2d0f8bd06f7f27a6f4e728a20e97648d2bf3', 'org.apiguardian:apiguardian-api:1.0.0:apiguardian-api-1.0.0.jar:1f58b77470d8d147a0538d515347dd322f49a83b9e884b8970051160464b65b3', 'org.checkerframework:checker-compat-qual:2.5.3:checker-compat-qual-2.5.3.jar:d76b9afea61c7c082908023f0cbc1427fab9abd2df915c8b8a3e7a509bccbc6d', 'org.codehaus.mojo:animal-sniffer-annotations:1.14:animal-sniffer-annotations-1.14.jar:2068320bd6bad744c3673ab048f67e30bef8f518996fa380033556600669905d', @@ -48,37 +48,35 @@ dependencyVerification { 'org.eclipse.jetty:jetty-webapp:9.4.15.v20190215:jetty-webapp-9.4.15.v20190215.jar:81b56aa7c29513654827adc48e786f121b54183791c132255195b9a45d83a0f3', 'org.eclipse.jetty:jetty-xml:9.4.15.v20190215:jetty-xml-9.4.15.v20190215.jar:c6d97a70572d5400e9ff3b7e32d4a4fd1c61319cbf997655a608064a75466082', 'org.jetbrains.intellij.deps:trove4j:1.0.20181211:trove4j-1.0.20181211.jar:affb7c85a3c87bdcf69ff1dbb84de11f63dc931293934bc08cd7ab18de083601', - 'org.jetbrains.kotlin:kotlin-android-extensions:1.3.21:kotlin-android-extensions-1.3.21.jar:2b0462ac3e4b36dffdb3bfa6173cb41b0e24e25a7d7eee1012471f1d27aea2dd', - 'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.3.21:kotlin-annotation-processing-gradle-1.3.21.jar:faf880315d4fd6a666cc17aa5e9608c7468c70a279b49ccca67dba2a54adf692', - 'org.jetbrains.kotlin:kotlin-build-common:1.3.21:kotlin-build-common-1.3.21.jar:f4d8d08c6f5966d9d517ced60c5224c7edca2d811ea0a702bd7199a00dd4fa25', - 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.21:kotlin-compiler-embeddable-1.3.21.jar:afaaedc324fbf6394d9f39544efcc93cfc59f8a5aa1a1a5c71d61e2483666c6a', - 'org.jetbrains.kotlin:kotlin-compiler-runner:1.3.21:kotlin-compiler-runner-1.3.21.jar:73e7088a074f9c517cd4bb2a8611834168459661c832136cf3628ccd5994cc3b', - 'org.jetbrains.kotlin:kotlin-daemon-client:1.3.21:kotlin-daemon-client-1.3.21.jar:b3ecce11ec7b311ee0d1ccc65e811f3748f328010765e86cbdb29b2b70f73f1c', - 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.3.21:kotlin-gradle-plugin-api-1.3.21.jar:ed0ab11437310cd409657c5e5f8a6bf589af0a8348577cd600f54601fc97c369', - 'org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.3.21:kotlin-gradle-plugin-model-1.3.21.jar:fbade67a2a3fb234e2d4c1b8f07b2af6c096993f34ed732fe6fadaf696bc208a', - 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.21:kotlin-gradle-plugin-1.3.21.jar:7858c58f4c678a8416520f4c094282a481981cfe702d23121118c9c7e9ad2326', - 'org.jetbrains.kotlin:kotlin-native-utils:1.3.21:kotlin-native-utils-1.3.21.jar:406010a39f4c8cdd2351cc1110b98ed804c0aa810cb6106e7b9f4f2bcc21cd47', + 'org.jetbrains.kotlin:kotlin-android-extensions:1.3.31:kotlin-android-extensions-1.3.31.jar:2f849616dcf5a5aa372e6c11ccd196607f0c3d42dd0a9be6d49ee3732ca050ba', + 'org.jetbrains.kotlin:kotlin-annotation-processing-gradle:1.3.31:kotlin-annotation-processing-gradle-1.3.31.jar:29a5fb59416226e2326f9fcb3ad0974915a424eec9125449981e1b9bbd9b79d6', + 'org.jetbrains.kotlin:kotlin-build-common:1.3.31:kotlin-build-common-1.3.31.jar:a37bace5fce25dade884ea75972fcf2a67d6f1326bf300eca27d052423773267', + 'org.jetbrains.kotlin:kotlin-compiler-embeddable:1.3.31:kotlin-compiler-embeddable-1.3.31.jar:b7918cbce747683905486ae54e664fe5d5db60e8ed1cbfebc00c79912b9aaffd', + 'org.jetbrains.kotlin:kotlin-compiler-runner:1.3.31:kotlin-compiler-runner-1.3.31.jar:f8ab33e2ec54a1c62a189c0cab04fbadb58dfd1bdda6a8ade0849a7a9a598b7c', + 'org.jetbrains.kotlin:kotlin-daemon-client:1.3.31:kotlin-daemon-client-1.3.31.jar:f658006ac301cae33e2a6cb1afd3cc41e82d98b12876de8fbe70a202434162de', + 'org.jetbrains.kotlin:kotlin-gradle-plugin-api:1.3.31:kotlin-gradle-plugin-api-1.3.31.jar:e40152d09ec45eb9fd4c0a8340de46793ae3beeb0f70f8ab15dc0097767fc61c', + 'org.jetbrains.kotlin:kotlin-gradle-plugin-model:1.3.31:kotlin-gradle-plugin-model-1.3.31.jar:9bbe7b3afebb43e81ef4e6a3202eb86d51dee34ddb305090d5cf0f2861ce87be', + 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.3.31:kotlin-gradle-plugin-1.3.31.jar:307ced92080a1d7a887fd7f71eef7b297b514a205ecf947220bd7ce8391a5594', + 'org.jetbrains.kotlin:kotlin-native-utils:1.3.31:kotlin-native-utils-1.3.31.jar:00af02020516eed7942ace3811cacd9fa3b1de2b66c6498e17dbe3a3e9bacce1', 'org.jetbrains.kotlin:kotlin-reflect:1.3.0:kotlin-reflect-1.3.0.jar:f3231ac1c612fe72de6ffcc4f0b4c5d85ad1ad4c808fb01a1981eab1ee1202c3', - 'org.jetbrains.kotlin:kotlin-reflect:1.3.21:kotlin-reflect-1.3.21.jar:a3065c822633191e0a3e3ee12a29bec234fc4b2864a6bb87ef48cce3e9e0c26a', - 'org.jetbrains.kotlin:kotlin-script-runtime:1.3.21:kotlin-script-runtime-1.3.21.jar:2e25babc8dcd224b9c479e2c16ce7b4c50407d25f18d60d1fd262f78c2b474cb', - 'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.21:kotlin-scripting-compiler-embeddable-1.3.21.jar:f4e6f9fd384d42167e9b89f985ee4a48a0676bfe705b2e2f9d13e1591d4b7c0b', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.10:kotlin-stdlib-common-1.3.10.jar:7ebf12fdadc5fe80f7ed4dbeffb16618cee1c23cbff0b0489a254174500acc68', - 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.21:kotlin-stdlib-common-1.3.21.jar:cea61f7b611895e64f58569a9757fc0ab0d582f107211e1930e0ce2a0add52a7', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.71:kotlin-stdlib-jdk7-1.2.71.jar:b136bd61b240e07d4d92ce00d3bd1dbf584400a7bf5f220c2f3cd22446858082', - 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.2.71:kotlin-stdlib-jdk8-1.2.71.jar:ac3c8abf47790b64b4f7e2509a53f0c145e061ac1612a597520535d199946ea9', - 'org.jetbrains.kotlin:kotlin-stdlib:1.3.10:kotlin-stdlib-1.3.10.jar:9b9650550fac559f7db64d988123399ea3da7cb776bfb13b9a3ed818eef26969', - 'org.jetbrains.kotlin:kotlin-stdlib:1.3.21:kotlin-stdlib-1.3.21.jar:38ba2370d9f06f50433e06b2ca775b94473c2e2785f410926079ab793c72b034', + 'org.jetbrains.kotlin:kotlin-reflect:1.3.31:kotlin-reflect-1.3.31.jar:a0172daf57e511e8e0df9251b508db8aa6b885cdf0c5849addc9b840db4814f0', + 'org.jetbrains.kotlin:kotlin-script-runtime:1.3.31:kotlin-script-runtime-1.3.31.jar:633692186b292292e41ea60d5170e811845b78aba88e20260ba70f7ce3a3ef32', + 'org.jetbrains.kotlin:kotlin-scripting-compiler-embeddable:1.3.31:kotlin-scripting-compiler-embeddable-1.3.31.jar:4dff2f683f8ceee0e834aeb0ca2686774da6c010ad1faf671dcaf73f071de954', + 'org.jetbrains.kotlin:kotlin-stdlib-common:1.3.31:kotlin-stdlib-common-1.3.31.jar:d6e9c54c1e6c4df21be9395de558665544c6bdc8f8076ea7518f089f82cd34fc', + 'org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.3.31:kotlin-stdlib-jdk7-1.3.31.jar:dbf77e6a5626d941450fdc59cbfe24165858403c12789749a2497265269859a3', + 'org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31:kotlin-stdlib-jdk8-1.3.31.jar:ad6acd219b468a532ac3b3c5aacbfd5db02d0ffcf967e2113e4677e2429490f6', + 'org.jetbrains.kotlin:kotlin-stdlib:1.3.31:kotlin-stdlib-1.3.31.jar:f38c84326543e66ed4895b20fb3ea0fca527fd5a040e1f49d0946ecf3d2b3b23', 'org.jetbrains:annotations:13.0:annotations-13.0.jar:ace2a10dc8e2d5fd34925ecac03e4988b2c0f851650c94b8cef49ba1bd111478', 'org.json:json:20150729:json-20150729.jar:38c21b9c3d6d24919cd15d027d20afab0a019ac9205f7ed9083b32bdd42a2353', - 'org.junit.jupiter:junit-jupiter-api:5.3.1:junit-jupiter-api-5.3.1.jar:7923e21f030a9964d70a0e48007ca873280c66ddf0f0620b2d969852c23d5653', - 'org.junit.jupiter:junit-jupiter-engine:5.3.1:junit-jupiter-engine-5.3.1.jar:04f4354548a30827e126bdf6fcbe3640789ad8335a6f3f0762bf7f9f74e51fbf', - 'org.junit.jupiter:junit-jupiter-params:5.3.1:junit-jupiter-params-5.3.1.jar:72fe344712d4cd88dd0cb4bfa304322d512d2cb27173ed64cb5036a573d29f4c', - 'org.junit.platform:junit-platform-commons:1.3.1:junit-platform-commons-1.3.1.jar:457d8e1c0c80d1e320a792ec35e7c180694ba05182d7ecf7dabdb4e5a8a12fe2', - 'org.junit.platform:junit-platform-engine:1.3.1:junit-platform-engine-1.3.1.jar:303d0546c3e950cc3beaca00dfcbf2632d4eca530e4e446391bf193cbc2a71a3', - 'org.objenesis:objenesis:2.6:objenesis-2.6.jar:5e168368fbc250af3c79aa5fef0c3467a2d64e5a7bd74005f25d8399aeb0708d', + 'org.junit.jupiter:junit-jupiter-api:5.4.2:junit-jupiter-api-5.4.2.jar:cdfb355fee661633f15f2763b8c2029c2e1958585b97b9162d38a36b1754dc3e', + 'org.junit.jupiter:junit-jupiter-engine:5.4.2:junit-jupiter-engine-5.4.2.jar:42aead7c5c1b74e0ef775c374a9fc07c771fd61a3621e66df1793dba14e534fd', + 'org.junit.jupiter:junit-jupiter-params:5.4.2:junit-jupiter-params-5.4.2.jar:13f89bca59fb6931a0ca9e3f4dc74e1a3054e0c63863e091a5df4855605ae4ce', + 'org.junit.platform:junit-platform-commons:1.4.2:junit-platform-commons-1.4.2.jar:104bfa65b30ceb425a6de19d66b976caf38443ff5978ae931c103fa0f99d04ce', + 'org.junit.platform:junit-platform-engine:1.4.2:junit-platform-engine-1.4.2.jar:7edb2ad879a338a84dbb09202b1399640ec0cacc5a95168539a9a74b5a2302e1', + 'org.objenesis:objenesis:3.0.1:objenesis-3.0.1.jar:7a8ff780b9ff48415d7c705f60030b0acaa616e7f823c98eede3b63508d4e984', 'org.opentest4j:opentest4j:1.1.1:opentest4j-1.1.1.jar:f106351abd941110226745ed103c85863b3f04e9fa82ddea1084639ae0c5336c', 'org.skyscreamer:jsonassert:1.5.0:jsonassert-1.5.0.jar:a310bc79c3f4744e2b2e993702fcebaf3696fec0063643ffdc6b49a8fb03ef39', - 'org.slf4j:slf4j-api:1.7.25:slf4j-api-1.7.25.jar:18c4a0095d5c1da6b817592e767bb23d29dd2f560ad74df75ff3961dbde25b79', - 'org.slf4j:slf4j-simple:1.7.25:slf4j-simple-1.7.25.jar:0966e86fffa5be52d3d9e7b89dd674d98a03eed0a454fbaf7c1bd9493bd9d874', + 'org.slf4j:slf4j-api:1.7.26:slf4j-api-1.7.26.jar:6d9e5b86cfd1dd44c676899285b5bb4fa0d371cf583e8164f9c8a0366553242b', + 'org.slf4j:slf4j-simple:1.7.26:slf4j-simple-1.7.26.jar:4b8ed75e2273850bf4eeb411ae5de5e0c0a44da59a96ca68d284749a6a373678', ] } From 69e57bee61eae2af0515628640d1a1fb790f5588 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 14:57:18 -0300 Subject: [PATCH 2/9] [bramble] Let TestUtils return a PendingContact with random state --- .../java/org/briarproject/bramble/test/TestUtils.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java index 004977060..3a1d3f80a 100644 --- a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java +++ b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java @@ -5,6 +5,7 @@ import org.briarproject.bramble.api.contact.Contact; import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContactId; +import org.briarproject.bramble.api.contact.PendingContactState; import org.briarproject.bramble.api.crypto.AgreementPrivateKey; import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.crypto.PrivateKey; @@ -36,7 +37,6 @@ import java.util.Random; import java.util.concurrent.atomic.AtomicInteger; import static java.util.Arrays.asList; -import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_AGREEMENT_PUBLIC_KEY_BYTES; import static org.briarproject.bramble.api.crypto.CryptoConstants.MAX_SIGNATURE_PUBLIC_KEY_BYTES; import static org.briarproject.bramble.api.identity.Author.FORMAT_VERSION; @@ -181,8 +181,10 @@ public class TestUtils { PendingContactId id = new PendingContactId(getRandomId()); PublicKey publicKey = getAgreementPublicKey(); String alias = getRandomString(nameLength); - return new PendingContact(id, publicKey, alias, WAITING_FOR_CONNECTION, - timestamp); + int stateIndex = + random.nextInt(PendingContactState.values().length - 1); + PendingContactState state = PendingContactState.values()[stateIndex]; + return new PendingContact(id, publicKey, alias, state, timestamp); } public static ContactId getContactId() { From dc6971734a5e5eead2f3ae2f000c883197b361e4 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 14:58:11 -0300 Subject: [PATCH 3/9] [briar-core] Add a getRealHandshakeLink() method to BriarTestUtils Also allow testOutput from briar-core to be used in briar-headless --- briar-core/build.gradle | 12 ++++++++++++ .../briarproject/briar/test/BriarTestUtils.java | 16 ++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/briar-core/build.gradle b/briar-core/build.gradle index c37cedb75..cd3fee934 100644 --- a/briar-core/build.gradle +++ b/briar-core/build.gradle @@ -30,3 +30,15 @@ dependencies { signature 'org.codehaus.mojo.signature:java16:1.1@signature' } + +// needed to make test output available to briar-headless +configurations { + testOutput.extendsFrom(testCompile) +} +task jarTest(type: Jar, dependsOn: testClasses) { + from sourceSets.test.output + classifier = 'test' +} +artifacts { + testOutput jarTest +} diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java index 314040cfe..b99ab2c36 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java @@ -1,13 +1,19 @@ package org.briarproject.briar.test; +import org.briarproject.bramble.api.crypto.CryptoComponent; +import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.AuthorFactory; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.util.Base32; import org.briarproject.briar.api.client.MessageTracker; import org.briarproject.briar.api.client.MessageTracker.GroupCount; +import static java.lang.System.arraycopy; +import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.FORMAT_VERSION; +import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.util.StringUtils.getRandomString; import static org.junit.Assert.assertEquals; @@ -40,4 +46,14 @@ public class BriarTestUtils { return authorFactory.createLocalAuthor(name); } + public static String getRealHandshakeLink(CryptoComponent cryptoComponent) { + KeyPair keyPair = cryptoComponent.generateAgreementKeyPair(); + byte[] linkBytes = new byte[RAW_LINK_BYTES]; + byte[] version = new byte[] {FORMAT_VERSION}; + byte[] publicKey = keyPair.getPublic().getEncoded(); + arraycopy(version,0, linkBytes, 0, 1); + arraycopy(publicKey,0, linkBytes, 1, RAW_LINK_BYTES - 1); + return ("briar://" + Base32.encode(linkBytes)).toLowerCase(); + } + } From 5a73e50248680dffc761f62539a5a3a4d52930bd Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 14:59:52 -0300 Subject: [PATCH 4/9] [headless] expose ContactManager methods for adding contacts remotely --- briar-headless/README.md | 81 +++++++++++++++- briar-headless/build.gradle | 1 + .../org/briarproject/briar/headless/Router.kt | 10 ++ .../headless/contact/ContactController.kt | 4 + .../headless/contact/ContactControllerImpl.kt | 48 +++++++++- .../headless/contact/OutputPendingContact.kt | 18 ++++ .../briar/headless/BriarHeadlessTestApp.kt | 3 + .../briar/headless/IntegrationTest.kt | 11 +++ .../ContactControllerIntegrationTest.kt | 48 ++++++++++ .../headless/contact/ContactControllerTest.kt | 94 ++++++++++++++++++- 10 files changed, 313 insertions(+), 5 deletions(-) create mode 100644 briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt diff --git a/briar-headless/README.md b/briar-headless/README.md index 29aa1cec5..95cf1b043 100644 --- a/briar-headless/README.md +++ b/briar-headless/README.md @@ -71,10 +71,79 @@ Returns a JSON array of contacts: ### Adding a contact -*Not yet implemented* +The first step is to get your own link: -The only workaround is to add a contact to the Briar app running on a rooted Android phone -and then move its database (and key files) to the headless peer. +`GET /v1/contacts/add/link` + +Returns a JSON object with a `briar://` link that needs to be sent to the contact you want to add +outside of Briar via an external channel. + +```json +{ + "link": "briar://wvui4uvhbfv4tzo6xwngknebsxrafainnhldyfj63x6ipp4q2vigy" +} +``` + +Once you have received the link of your future contact, you can add them +by posting the link together with an arbitrary nickname (or alias): + +`POST /v1/contacts/add` + +The link and the alias should be posted as a JSON object: + +```json +{ + "link": "briar://ddnsyffpsenoc3yzlhr24aegfq2pwan7kkselocill2choov6sbhs", + "alias": "A nickname for the new contact" +} +``` + +This starts the process of adding the contact. +Until it is completed, a pending contact is returned as JSON: + +```json +{ + "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=", + "alias": "ztatsaajzeegraqcizbbfftofdekclatyht", + "state": "adding_contact", + "timestamp": 1557838312175 +} +``` + +The state can be one of these values: + + * `waiting_for_connection` + * `connected` + * `adding_contact` + * `failed` + +If you want to get informed about state changes, +you can use the Websocket API (below) to listen for events. + +The following events are relevant here: + + * `PendingContactStateChangedEvent` + * `PendingContactRemovedEvent` + * `ContactAddedRemotelyEvent` (when the pending contact becomes an actual contact) + +It is possible to get a list of all pending contacts: + +`GET /v1/contacts/add/pending` + +This will return a JSON array of pending contacts formatted as shown above. + +To remove a pending contact and abort the process of adding it: + +`DELETE /v1/contacts/add/pending` + +The `pendingContactId` of the pending contact to delete +needs to be provided in the request body as follows: + +```json +{ + "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=" +} +``` ### Removing a contact @@ -204,3 +273,9 @@ it will send a JSON object to connected websocket clients: Note that the JSON object in `data` is exactly what the REST API returns when listing private messages. + +# TODO + + * PendingContactStateChangedEvent + * PendingContactRemovedEvent + * ContactAddedRemotelyEvent \ No newline at end of file diff --git a/briar-headless/build.gradle b/briar-headless/build.gradle index 916d92f82..c9b463af1 100644 --- a/briar-headless/build.gradle +++ b/briar-headless/build.gradle @@ -25,6 +25,7 @@ dependencies { testImplementation project(path: ':bramble-api', configuration: 'testOutput') testImplementation project(path: ':bramble-core', configuration: 'testOutput') + testImplementation project(path: ':briar-core', configuration: 'testOutput') def junitVersion = '5.4.2' testImplementation "org.junit.jupiter:junit-jupiter-api:$junitVersion" diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt index e16f3eb4c..6dffbeb0a 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt @@ -64,6 +64,16 @@ constructor( path("/v1") { path("/contacts") { get { ctx -> contactController.list(ctx) } + path("add") { + post { ctx -> contactController.addPendingContact(ctx) } + path("link") { + get { ctx -> contactController.link(ctx) } + } + path("pending") { + get { ctx -> contactController.listPendingContacts(ctx) } + delete { ctx -> contactController.removePendingContact(ctx) } + } + } path("/:contactId") { delete { ctx -> contactController.delete(ctx) } } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt index d7a0bfbc4..cb454ddba 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt @@ -5,6 +5,10 @@ import io.javalin.Context interface ContactController { fun list(ctx: Context): Context + fun link(ctx: Context): Context + fun addPendingContact(ctx: Context): Context + fun listPendingContacts(ctx: Context): Context + fun removePendingContact(ctx: Context): Context fun delete(ctx: Context): Context } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt index d09c44dbf..1b7a639c1 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt @@ -1,10 +1,17 @@ package org.briarproject.briar.headless.contact +import com.fasterxml.jackson.databind.ObjectMapper import io.javalin.Context import io.javalin.NotFoundResponse import org.briarproject.bramble.api.contact.ContactManager +import org.briarproject.bramble.api.contact.PendingContactId import org.briarproject.bramble.api.db.NoSuchContactException +import org.briarproject.bramble.api.db.NoSuchPendingContactException import org.briarproject.briar.headless.getContactIdFromPathParam +import org.briarproject.briar.headless.getFromJson +import org.briarproject.briar.headless.json.JsonDict +import org.spongycastle.util.encoders.Base64 +import org.spongycastle.util.encoders.DecoderException import javax.annotation.concurrent.Immutable import javax.inject.Inject import javax.inject.Singleton @@ -13,7 +20,8 @@ import javax.inject.Singleton @Singleton internal class ContactControllerImpl @Inject -constructor(private val contactManager: ContactManager) : ContactController { +constructor(private val contactManager: ContactManager, private val objectMapper: ObjectMapper) : + ContactController { override fun list(ctx: Context): Context { val contacts = contactManager.contacts.map { contact -> @@ -22,6 +30,44 @@ constructor(private val contactManager: ContactManager) : ContactController { return ctx.json(contacts) } + override fun link(ctx: Context): Context { + val linkDict = JsonDict("link" to contactManager.handshakeLink) + return ctx.json(linkDict) + } + + override fun addPendingContact(ctx: Context): Context { + val link = ctx.getFromJson(objectMapper, "link") + val alias = ctx.getFromJson(objectMapper, "alias") + val pendingContact = contactManager.addPendingContact(link, alias) + return ctx.json(pendingContact.output()) + } + + override fun listPendingContacts(ctx: Context): Context { + val pendingContacts = contactManager.pendingContacts.map { pendingContact -> + pendingContact.output() + } + return ctx.json(pendingContacts) + } + + override fun removePendingContact(ctx: Context): Context { + // construct and check PendingContactId + val pendingContactString = ctx.getFromJson(objectMapper, "pendingContactId") + val pendingContactBytes = try { + Base64.decode(pendingContactString) + } catch (e: DecoderException) { + throw NotFoundResponse() + } + if (pendingContactBytes.size != PendingContactId.LENGTH) throw NotFoundResponse() + val id = PendingContactId(pendingContactBytes) + // remove + try { + contactManager.removePendingContact(id) + } catch (e: NoSuchPendingContactException) { + throw NotFoundResponse() + } + return ctx + } + override fun delete(ctx: Context): Context { val contactId = ctx.getContactIdFromPathParam() try { diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt new file mode 100644 index 000000000..ac224e307 --- /dev/null +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt @@ -0,0 +1,18 @@ +package org.briarproject.briar.headless.contact + +import org.briarproject.bramble.api.contact.PendingContact +import org.briarproject.bramble.api.contact.PendingContactState.* +import org.briarproject.briar.headless.json.JsonDict + +internal fun PendingContact.output() = JsonDict( + "pendingContactId" to id.bytes, + "alias" to alias, + "state" to when(state) { + WAITING_FOR_CONNECTION -> "waiting_for_connection" + CONNECTED -> "connected" + ADDING_CONTACT -> "adding_contact" + FAILED -> "failed" + else -> throw AssertionError() + }, + "timestamp" to timestamp +) \ No newline at end of file diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/BriarHeadlessTestApp.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/BriarHeadlessTestApp.kt index f349de62b..3bf488150 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/BriarHeadlessTestApp.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/BriarHeadlessTestApp.kt @@ -4,6 +4,7 @@ import dagger.Component import org.briarproject.bramble.BrambleCoreEagerSingletons import org.briarproject.bramble.BrambleCoreModule import org.briarproject.bramble.account.AccountModule +import org.briarproject.bramble.api.crypto.CryptoComponent import org.briarproject.bramble.event.DefaultEventExecutorModule import org.briarproject.bramble.test.TestSecureRandomModule import org.briarproject.briar.BriarCoreEagerSingletons @@ -25,5 +26,7 @@ import javax.inject.Singleton internal interface BriarHeadlessTestApp : BrambleCoreEagerSingletons, BriarCoreEagerSingletons { fun getRouter(): Router + fun getCryptoComponent(): CryptoComponent + fun getTestDataCreator(): TestDataCreator } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt index 0884f34ff..2ef97aced 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt @@ -4,6 +4,7 @@ import io.javalin.Javalin import io.javalin.core.util.Header.AUTHORIZATION import khttp.responses.Response import org.briarproject.bramble.BrambleCoreModule +import org.briarproject.bramble.api.crypto.CryptoComponent import org.briarproject.briar.BriarCoreModule import org.briarproject.briar.api.test.TestDataCreator import org.junit.jupiter.api.AfterAll @@ -22,6 +23,7 @@ abstract class IntegrationTest { private val dataDir = File("tmp") protected lateinit var api: Javalin + protected lateinit var crypto: CryptoComponent protected lateinit var testDataCreator: TestDataCreator private lateinit var router: Router @@ -33,6 +35,7 @@ abstract class IntegrationTest { BrambleCoreModule.initEagerSingletons(app) BriarCoreModule.initEagerSingletons(app) router = app.getRouter() + crypto = app.getCryptoComponent() testDataCreator = app.getTestDataCreator() api = router.start(token, port, false) @@ -52,10 +55,18 @@ abstract class IntegrationTest { return khttp.get(url, getAuthTokenHeader("wrongToken")) } + protected fun post(url: String, data: String) : Response { + return khttp.post(url, getAuthTokenHeader(token), data = data) + } + protected fun delete(url: String) : Response { return khttp.delete(url, getAuthTokenHeader(token)) } + protected fun delete(url: String, data: String) : Response { + return khttp.delete(url, getAuthTokenHeader(token), data = data) + } + protected fun deleteWithWrongToken(url: String) : Response { return khttp.delete(url, getAuthTokenHeader("wrongToken")) } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt index f00024620..96cd0b0ad 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt @@ -1,8 +1,11 @@ package org.briarproject.briar.headless.contact +import org.briarproject.bramble.api.contact.HandshakeLinkConstants.BASE32_LINK_BYTES import org.briarproject.briar.headless.IntegrationTest import org.briarproject.briar.headless.url +import org.briarproject.briar.test.BriarTestUtils.getRealHandshakeLink import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Test class ContactControllerIntegrationTest: IntegrationTest() { @@ -33,6 +36,51 @@ class ContactControllerIntegrationTest: IntegrationTest() { assertEquals(testContactName, author.getString("name")) } + @Test + fun `returns own handshake link`() { + val response = get("$url/contacts/add/link") + assertEquals(200, response.statusCode) + val link = response.jsonObject.getString("link") + assertTrue(link.startsWith("briar://")) + assertEquals(BASE32_LINK_BYTES + 8, link.length) + } + + @Test + fun `returns list of pending contacts`() { + // retrieve empty list of pending contacts + var response = get("$url/contacts/add/pending") + assertEquals(200, response.statusCode) + assertEquals(0, response.jsonArray.length()) + + // add one pending contact + val alias = "AliasFoo" + val json = """{ + "link": "${getRealHandshakeLink(crypto)}", + "alias": "$alias" + }""" + response = post("$url/contacts/add", json) + assertEquals(200, response.statusCode) + + // get added contact as only list item + response = get("$url/contacts/add/pending") + assertEquals(200, response.statusCode) + assertEquals(1, response.jsonArray.length()) + val jsonObject = response.jsonArray.getJSONObject(0) + assertEquals(alias, jsonObject.getString("alias")) + assertEquals("waiting_for_connection", jsonObject.getString("state")) + + // remove pending contact again + val idString = jsonObject.getString("pendingContactId") + val deleteJson = """{"pendingContactId": "$idString"}""" + response = delete("$url/contacts/add/pending", deleteJson) + assertEquals(200, response.statusCode) + + // list of pending contacts should be empty now + response = get("$url/contacts/add/pending") + assertEquals(200, response.statusCode) + assertEquals(0, response.jsonArray.length()) + } + @Test fun `deleting contact need authentication token`() { val response = deleteWithWrongToken("$url/contacts/1") diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt index 34f14b393..a0498ea6e 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt @@ -7,15 +7,21 @@ import io.mockk.every import io.mockk.just import org.briarproject.bramble.api.contact.Contact import org.briarproject.bramble.api.contact.ContactId +import org.briarproject.bramble.api.contact.PendingContactId import org.briarproject.bramble.api.db.NoSuchContactException +import org.briarproject.bramble.api.db.NoSuchPendingContactException import org.briarproject.bramble.identity.output +import org.briarproject.bramble.test.TestUtils.getPendingContact +import org.briarproject.bramble.test.TestUtils.getRandomBytes import org.briarproject.briar.headless.ControllerTest +import org.briarproject.briar.headless.json.JsonDict import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test internal class ContactControllerTest : ControllerTest() { - private val controller = ContactControllerImpl(contactManager) + private val controller = ContactControllerImpl(contactManager, objectMapper) + private val pendingContact = getPendingContact() @Test fun testEmptyContactList() { @@ -31,6 +37,79 @@ internal class ContactControllerTest : ControllerTest() { controller.list(ctx) } + @Test + fun testLink() { + val link = "briar://link" + every { contactManager.handshakeLink } returns link + every { ctx.json(JsonDict("link" to link)) } returns ctx + controller.link(ctx) + } + + @Test + fun testAddPendingContact() { + val link = "briar://link123" + val alias = "Alias123" + val body = """{ + "link": "$link", + "alias": "$alias" + }""" + every { ctx.body() } returns body + every { contactManager.addPendingContact(link, alias) } returns pendingContact + every { ctx.json(pendingContact.output()) } returns ctx + controller.addPendingContact(ctx) + } + + @Test + fun testListPendingContacts() { + every { contactManager.pendingContacts } returns listOf(pendingContact) + every { ctx.json(listOf(pendingContact.output())) } returns ctx + controller.listPendingContacts(ctx) + } + + @Test + fun testRemovePendingContact() { + val id = pendingContact.id + every { ctx.body() } returns """{"pendingContactId": ${toJson(id.bytes)}}""" + every { contactManager.removePendingContact(id) } just Runs + controller.removePendingContact(ctx) + } + + @Test + fun testRemovePendingContactInvalidId() { + every { ctx.body() } returns """{"pendingContactId": "foo"}""" + assertThrows(NotFoundResponse::class.java) { + controller.removePendingContact(ctx) + } + } + + @Test + fun testRemovePendingContactTooShortId() { + val bytes = getRandomBytes(PendingContactId.LENGTH - 1) + every { ctx.body() } returns """{"pendingContactId": ${toJson(bytes)}}""" + assertThrows(NotFoundResponse::class.java) { + controller.removePendingContact(ctx) + } + } + + @Test + fun testRemovePendingContactTooLongId() { + val bytes = getRandomBytes(PendingContactId.LENGTH + 1) + every { ctx.body() } returns """{"pendingContactId": ${toJson(bytes)}}""" + assertThrows(NotFoundResponse::class.java) { + controller.removePendingContact(ctx) + } + } + + @Test + fun testRemovePendingContactNonexistentId() { + val id = pendingContact.id + every { ctx.body() } returns """{"pendingContactId": ${toJson(id.bytes)}}""" + every { contactManager.removePendingContact(id) } throws NoSuchPendingContactException() + assertThrows(NotFoundResponse::class.java) { + controller.removePendingContact(ctx) + } + } + @Test fun testDelete() { every { ctx.pathParam("contactId") } returns "1" @@ -80,4 +159,17 @@ internal class ContactControllerTest : ControllerTest() { assertJsonEquals(json, author.output()) } + @Test + fun testOutputPendingContact() { + val json = """ + { + "pendingContactId": ${toJson(pendingContact.id.bytes)}, + "alias": "${pendingContact.alias}", + "state": "${pendingContact.state.name.toLowerCase()}", + "timestamp": ${pendingContact.timestamp} + } + """ + assertJsonEquals(json, pendingContact.output()) + } + } From c6211be488d970d3b65abef6229f68dcfb1a8db4 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 16:15:13 -0300 Subject: [PATCH 5/9] [bramble-core] Broadcast events when pending contacts are added or removed --- .../org/briarproject/bramble/db/DatabaseComponentImpl.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java index c11aaa7de..c1af6489d 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java @@ -7,6 +7,8 @@ import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent; +import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent; +import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent; import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PublicKey; import org.briarproject.bramble.api.crypto.SecretKey; @@ -320,6 +322,8 @@ class DatabaseComponentImpl implements DatabaseComponent { if (db.containsPendingContact(txn, p.getId())) throw new PendingContactExistsException(); db.addPendingContact(txn, p); + transaction.attach(new PendingContactStateChangedEvent(p.getId(), + p.getState())); } @Override @@ -936,6 +940,7 @@ class DatabaseComponentImpl implements DatabaseComponent { if (!db.containsPendingContact(txn, p)) throw new NoSuchPendingContactException(); db.removePendingContact(txn, p); + transaction.attach(new PendingContactRemovedEvent(p)); } @Override From 3770a9f217b1674e323e349495e13d5bfff267c0 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 16:15:47 -0300 Subject: [PATCH 6/9] [headless] make events related to adding contacts available via websocket --- briar-headless/README.md | 51 +++++++++++- .../headless/contact/ContactControllerImpl.kt | 31 ++++++- .../headless/contact/HeadlessContactModule.kt | 7 +- .../briar/headless/contact/OutputContact.kt | 5 +- .../headless/contact/OutputPendingContact.kt | 30 +++++-- .../briar/headless/ControllerTest.kt | 3 + .../headless/contact/ContactControllerTest.kt | 80 ++++++++++++++++++- .../messaging/MessagingControllerImplTest.kt | 2 - 8 files changed, 190 insertions(+), 19 deletions(-) diff --git a/briar-headless/README.md b/briar-headless/README.md index 95cf1b043..d2782368f 100644 --- a/briar-headless/README.md +++ b/briar-headless/README.md @@ -274,8 +274,51 @@ it will send a JSON object to connected websocket clients: Note that the JSON object in `data` is exactly what the REST API returns when listing private messages. -# TODO +### A new contact was added remotely - * PendingContactStateChangedEvent - * PendingContactRemovedEvent - * ContactAddedRemotelyEvent \ No newline at end of file +When the Briar peer adds a new contact remotely, +it will send a JSON object representing the new contact to connected websocket clients: + +```json +{ + "data": { + "author": { + "formatVersion": 1, + "id": "y1wkIzAimAbYoCGgWxkWlr6vnq1F8t1QRA/UMPgI0E0=", + "name": "Test", + "publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo=" + }, + "contactId": 1, + "verified": true + }, + "name": "ContactAddedRemotelyEvent", + "type": "event" +} +``` + +### A pending contact changed its state + +```json +{ + "data": { + "pendingContactId":"YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M=", + "state":"waiting_for_connection" + }, + "name": "PendingContactStateChangedEvent", + "type": "event" +} +``` + +For a list of valid states, please see the section on adding contacts above. + +### A pending contact was removed + +```json +{ + "data": { + "pendingContactId": "YqKjsczCuxScXohb5+RAYtFEwK71icoB4ldztV2gh7M=" + }, + "name": "PendingContactRemovedEvent", + "type": "event" +} +``` diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt index 1b7a639c1..16a17a532 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt @@ -5,8 +5,14 @@ import io.javalin.Context import io.javalin.NotFoundResponse import org.briarproject.bramble.api.contact.ContactManager import org.briarproject.bramble.api.contact.PendingContactId +import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent +import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent +import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchPendingContactException +import org.briarproject.bramble.api.event.Event +import org.briarproject.bramble.api.event.EventListener +import org.briarproject.briar.headless.event.WebSocketController import org.briarproject.briar.headless.getContactIdFromPathParam import org.briarproject.briar.headless.getFromJson import org.briarproject.briar.headless.json.JsonDict @@ -16,12 +22,33 @@ import javax.annotation.concurrent.Immutable import javax.inject.Inject import javax.inject.Singleton +internal const val EVENT_CONTACT_ADDED_REMOTELY = "ContactAddedRemotelyEvent" +internal const val EVENT_PENDING_CONTACT_STATE_CHANGED = "PendingContactStateChangedEvent" +internal const val EVENT_PENDING_CONTACT_REMOVED = "PendingContactRemovedEvent" + @Immutable @Singleton internal class ContactControllerImpl @Inject -constructor(private val contactManager: ContactManager, private val objectMapper: ObjectMapper) : - ContactController { +constructor( + private val contactManager: ContactManager, + private val objectMapper: ObjectMapper, + private val webSocket: WebSocketController +) : ContactController, EventListener { + + override fun eventOccurred(e: Event) = when (e) { + is ContactAddedRemotelyEvent -> { + webSocket.sendEvent(EVENT_CONTACT_ADDED_REMOTELY, e.output()) + } + is PendingContactStateChangedEvent -> { + webSocket.sendEvent(EVENT_PENDING_CONTACT_STATE_CHANGED, e.output()) + } + is PendingContactRemovedEvent -> { + webSocket.sendEvent(EVENT_PENDING_CONTACT_REMOVED, e.output()) + } + else -> { + } + } override fun list(ctx: Context): Context { val contacts = contactManager.contacts.map { contact -> diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/HeadlessContactModule.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/HeadlessContactModule.kt index bf91804b3..032af9778 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/HeadlessContactModule.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/HeadlessContactModule.kt @@ -2,6 +2,7 @@ package org.briarproject.briar.headless.contact import dagger.Module import dagger.Provides +import org.briarproject.bramble.api.event.EventBus import javax.inject.Singleton @Module @@ -9,7 +10,11 @@ class HeadlessContactModule { @Provides @Singleton - internal fun provideContactController(contactController: ContactControllerImpl): ContactController { + internal fun provideContactController( + eventBus: EventBus, + contactController: ContactControllerImpl + ): ContactController { + eventBus.addListener(contactController) return contactController } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt index d0ec5898c..232ce74dc 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt @@ -1,6 +1,7 @@ package org.briarproject.briar.headless.contact import org.briarproject.bramble.api.contact.Contact +import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent import org.briarproject.bramble.identity.output import org.briarproject.briar.headless.json.JsonDict @@ -8,4 +9,6 @@ internal fun Contact.output() = JsonDict( "contactId" to id.int, "author" to author.output(), "verified" to isVerified -) \ No newline at end of file +) + +internal fun ContactAddedRemotelyEvent.output() = contact.output() diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt index ac224e307..1988bb342 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputPendingContact.kt @@ -1,18 +1,32 @@ package org.briarproject.briar.headless.contact import org.briarproject.bramble.api.contact.PendingContact +import org.briarproject.bramble.api.contact.PendingContactState import org.briarproject.bramble.api.contact.PendingContactState.* +import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent +import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent import org.briarproject.briar.headless.json.JsonDict internal fun PendingContact.output() = JsonDict( "pendingContactId" to id.bytes, "alias" to alias, - "state" to when(state) { - WAITING_FOR_CONNECTION -> "waiting_for_connection" - CONNECTED -> "connected" - ADDING_CONTACT -> "adding_contact" - FAILED -> "failed" - else -> throw AssertionError() - }, + "state" to state.output(), "timestamp" to timestamp -) \ No newline at end of file +) + +internal fun PendingContactState.output() = when(this) { + WAITING_FOR_CONNECTION -> "waiting_for_connection" + CONNECTED -> "connected" + ADDING_CONTACT -> "adding_contact" + FAILED -> "failed" + else -> throw AssertionError() +} + +internal fun PendingContactStateChangedEvent.output() = JsonDict( + "pendingContactId" to id.bytes, + "state" to pendingContactState.output() +) + +internal fun PendingContactRemovedEvent.output() = JsonDict( + "pendingContactId" to id.bytes +) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/ControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/ControllerTest.kt index d9ffe4872..b461cb5f8 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/ControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/ControllerTest.kt @@ -14,6 +14,7 @@ import org.briarproject.bramble.api.sync.Message import org.briarproject.bramble.api.system.Clock import org.briarproject.bramble.test.TestUtils.* import org.briarproject.bramble.util.StringUtils.getRandomString +import org.briarproject.briar.headless.event.WebSocketController import org.skyscreamer.jsonassert.JSONAssert.assertEquals import org.skyscreamer.jsonassert.JSONCompareMode.STRICT import javax.servlet.http.HttpServletRequest @@ -26,6 +27,8 @@ abstract class ControllerTest { protected val clock = mockk() protected val ctx = mockk() + protected val webSocketController = mockk() + private val request = mockk(relaxed = true) private val response = mockk(relaxed = true) private val outputCtx = ContextUtil.init(request, response) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt index a0498ea6e..118c279f6 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt @@ -5,9 +5,14 @@ import io.javalin.json.JavalinJson.toJson import io.mockk.Runs import io.mockk.every import io.mockk.just +import io.mockk.runs import org.briarproject.bramble.api.contact.Contact import org.briarproject.bramble.api.contact.ContactId import org.briarproject.bramble.api.contact.PendingContactId +import org.briarproject.bramble.api.contact.PendingContactState.FAILED +import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent +import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent +import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchPendingContactException import org.briarproject.bramble.identity.output @@ -20,9 +25,11 @@ import org.junit.jupiter.api.Test internal class ContactControllerTest : ControllerTest() { - private val controller = ContactControllerImpl(contactManager, objectMapper) private val pendingContact = getPendingContact() + private val controller = + ContactControllerImpl(contactManager, objectMapper, webSocketController) + @Test fun testEmptyContactList() { every { contactManager.contacts } returns emptyList() @@ -134,6 +141,48 @@ internal class ContactControllerTest : ControllerTest() { } } + @Test + fun testContactAddedRemotelyEvent() { + val event = ContactAddedRemotelyEvent(contact) + + every { + webSocketController.sendEvent( + EVENT_CONTACT_ADDED_REMOTELY, + event.output() + ) + } just runs + + controller.eventOccurred(event) + } + + @Test + fun testPendingContactStateChangedEvent() { + val event = PendingContactStateChangedEvent(pendingContact.id, FAILED) + + every { + webSocketController.sendEvent( + EVENT_PENDING_CONTACT_STATE_CHANGED, + event.output() + ) + } just runs + + controller.eventOccurred(event) + } + + @Test + fun testPendingContactRemovedEvent() { + val event = PendingContactRemovedEvent(pendingContact.id) + + every { + webSocketController.sendEvent( + EVENT_PENDING_CONTACT_REMOVED, + event.output() + ) + } just runs + + controller.eventOccurred(event) + } + @Test fun testOutputContact() { val json = """ @@ -159,6 +208,12 @@ internal class ContactControllerTest : ControllerTest() { assertJsonEquals(json, author.output()) } + @Test + fun testOutputContactAddedRemotelyEvent() { + val event = ContactAddedRemotelyEvent(contact) + assertJsonEquals(toJson(contact.output()), event.output()) + } + @Test fun testOutputPendingContact() { val json = """ @@ -172,4 +227,27 @@ internal class ContactControllerTest : ControllerTest() { assertJsonEquals(json, pendingContact.output()) } + @Test + fun testOutputPendingContactStateChangedEvent() { + val event = PendingContactStateChangedEvent(pendingContact.id, FAILED) + val json = """ + { + "pendingContactId": ${toJson(pendingContact.id.bytes)}, + "state": "failed" + } + """ + assertJsonEquals(json, event.output()) + } + + @Test + fun testOutputPendingContactRemovedEvent() { + val event = PendingContactRemovedEvent(pendingContact.id) + val json = """ + { + "pendingContactId": ${toJson(pendingContact.id.bytes)} + } + """ + assertJsonEquals(json, event.output()) + } + } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt index c438a768b..d5ab17dc9 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/messaging/MessagingControllerImplTest.kt @@ -23,7 +23,6 @@ import org.briarproject.briar.api.messaging.PrivateMessageFactory import org.briarproject.briar.api.messaging.PrivateMessageHeader import org.briarproject.briar.api.messaging.event.PrivateMessageReceivedEvent import org.briarproject.briar.headless.ControllerTest -import org.briarproject.briar.headless.event.WebSocketController import org.briarproject.briar.headless.event.output import org.briarproject.briar.headless.json.JsonDict import org.junit.jupiter.api.Assertions.assertEquals @@ -35,7 +34,6 @@ internal class MessagingControllerImplTest : ControllerTest() { private val messagingManager = mockk() private val conversationManager = mockk() private val privateMessageFactory = mockk() - private val webSocketController = mockk() private val dbExecutor = ImmediateExecutor() private val controller = MessagingControllerImpl( From faa6a85148985d1d767c21508ec58430df2dd5d4 Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Tue, 14 May 2019 16:47:38 -0300 Subject: [PATCH 7/9] [headless] Add tests to ensure that remote contact adding needs auth token --- briar-headless/README.md | 2 +- .../org/briarproject/briar/headless/Router.kt | 2 +- .../briar/headless/IntegrationTest.kt | 4 +++ .../ContactControllerIntegrationTest.kt | 26 ++++++++++++++++++- 4 files changed, 31 insertions(+), 3 deletions(-) diff --git a/briar-headless/README.md b/briar-headless/README.md index d2782368f..a6ac23cdf 100644 --- a/briar-headless/README.md +++ b/briar-headless/README.md @@ -87,7 +87,7 @@ outside of Briar via an external channel. Once you have received the link of your future contact, you can add them by posting the link together with an arbitrary nickname (or alias): -`POST /v1/contacts/add` +`POST /v1/contacts/add/pending` The link and the alias should be posted as a JSON object: diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt index 6dffbeb0a..12afce4f5 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt @@ -65,12 +65,12 @@ constructor( path("/contacts") { get { ctx -> contactController.list(ctx) } path("add") { - post { ctx -> contactController.addPendingContact(ctx) } path("link") { get { ctx -> contactController.link(ctx) } } path("pending") { get { ctx -> contactController.listPendingContacts(ctx) } + post { ctx -> contactController.addPendingContact(ctx) } delete { ctx -> contactController.removePendingContact(ctx) } } } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt index 2ef97aced..9f53cd275 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/IntegrationTest.kt @@ -59,6 +59,10 @@ abstract class IntegrationTest { return khttp.post(url, getAuthTokenHeader(token), data = data) } + protected fun postWithWrongToken(url: String) : Response { + return khttp.post(url, getAuthTokenHeader("wrongToken"), data = "") + } + protected fun delete(url: String) : Response { return khttp.delete(url, getAuthTokenHeader(token)) } diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt index 96cd0b0ad..bd63c1193 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerIntegrationTest.kt @@ -45,6 +45,12 @@ class ContactControllerIntegrationTest: IntegrationTest() { assertEquals(BASE32_LINK_BYTES + 8, link.length) } + @Test + fun `returning own handshake link needs authentication token`() { + val response = getWithWrongToken("$url/contacts/add/link") + assertEquals(401, response.statusCode) + } + @Test fun `returns list of pending contacts`() { // retrieve empty list of pending contacts @@ -58,7 +64,7 @@ class ContactControllerIntegrationTest: IntegrationTest() { "link": "${getRealHandshakeLink(crypto)}", "alias": "$alias" }""" - response = post("$url/contacts/add", json) + response = post("$url/contacts/add/pending", json) assertEquals(200, response.statusCode) // get added contact as only list item @@ -81,6 +87,24 @@ class ContactControllerIntegrationTest: IntegrationTest() { assertEquals(0, response.jsonArray.length()) } + @Test + fun `returning list of pending contacts needs authentication token`() { + val response = getWithWrongToken("$url/contacts/add/pending") + assertEquals(401, response.statusCode) + } + + @Test + fun `adding pending contacts needs authentication token`() { + val response = postWithWrongToken("$url/contacts/add/pending") + assertEquals(401, response.statusCode) + } + + @Test + fun `removing a pending contact needs authentication token`() { + val response = deleteWithWrongToken("$url/contacts/add/pending") + assertEquals(401, response.statusCode) + } + @Test fun `deleting contact need authentication token`() { val response = deleteWithWrongToken("$url/contacts/1") From 435b43488a706ac38d6c7e069330297af54ca48c Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 15 May 2019 12:36:33 -0300 Subject: [PATCH 8/9] [headless] address review comments for remote contact adding --- .../briar/test/BriarTestUtils.java | 3 +- briar-headless/README.md | 22 +++--- .../bramble/identity/OutputAuthor.kt | 2 +- .../org/briarproject/briar/headless/Router.kt | 2 +- .../headless/contact/ContactController.kt | 2 +- .../headless/contact/ContactControllerImpl.kt | 10 ++- .../briar/headless/contact/OutputContact.kt | 9 ++- .../headless/contact/ContactControllerTest.kt | 72 +++++++++++++++++-- 8 files changed, 102 insertions(+), 20 deletions(-) diff --git a/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java b/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java index b99ab2c36..8f6f97226 100644 --- a/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java +++ b/briar-core/src/test/java/org/briarproject/briar/test/BriarTestUtils.java @@ -49,9 +49,8 @@ public class BriarTestUtils { public static String getRealHandshakeLink(CryptoComponent cryptoComponent) { KeyPair keyPair = cryptoComponent.generateAgreementKeyPair(); byte[] linkBytes = new byte[RAW_LINK_BYTES]; - byte[] version = new byte[] {FORMAT_VERSION}; byte[] publicKey = keyPair.getPublic().getEncoded(); - arraycopy(version,0, linkBytes, 0, 1); + linkBytes[0] = FORMAT_VERSION; arraycopy(publicKey,0, linkBytes, 1, RAW_LINK_BYTES - 1); return ("briar://" + Base32.encode(linkBytes)).toLowerCase(); } diff --git a/briar-headless/README.md b/briar-headless/README.md index a6ac23cdf..02a7d40d2 100644 --- a/briar-headless/README.md +++ b/briar-headless/README.md @@ -65,6 +65,8 @@ Returns a JSON array of contacts: "publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo=" }, "contactId": 1, + "alias" : "A local nickname", + "handshakePublicKey": "XnYRd7a7E4CTqgAvh4hCxh/YZ0EPscxknB9ZcEOpSzY=", "verified": true } ``` @@ -282,14 +284,18 @@ it will send a JSON object representing the new contact to connected websocket c ```json { "data": { - "author": { - "formatVersion": 1, - "id": "y1wkIzAimAbYoCGgWxkWlr6vnq1F8t1QRA/UMPgI0E0=", - "name": "Test", - "publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo=" - }, - "contactId": 1, - "verified": true + "contact": { + "author": { + "formatVersion": 1, + "id": "y1wkIzAimAbYoCGgWxkWlr6vnq1F8t1QRA/UMPgI0E0=", + "name": "Test", + "publicKey": "BDu6h1S02bF4W6rgoZfZ6BMjTj/9S9hNN7EQoV05qUo=" + }, + "contactId": 1, + "alias" : "A local nickname", + "handshakePublicKey": "XnYRd7a7E4CTqgAvh4hCxh/YZ0EPscxknB9ZcEOpSzY=", + "verified": true + } }, "name": "ContactAddedRemotelyEvent", "type": "event" diff --git a/briar-headless/src/main/java/org/briarproject/bramble/identity/OutputAuthor.kt b/briar-headless/src/main/java/org/briarproject/bramble/identity/OutputAuthor.kt index 3b6617582..cbdb0387e 100644 --- a/briar-headless/src/main/java/org/briarproject/bramble/identity/OutputAuthor.kt +++ b/briar-headless/src/main/java/org/briarproject/bramble/identity/OutputAuthor.kt @@ -8,7 +8,7 @@ fun Author.output() = JsonDict( "formatVersion" to formatVersion, "id" to id.bytes, "name" to name, - "publicKey" to publicKey + "publicKey" to publicKey.encoded ) fun AuthorInfo.Status.output() = name.toLowerCase() diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt index 12afce4f5..bb1f49cae 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/Router.kt @@ -66,7 +66,7 @@ constructor( get { ctx -> contactController.list(ctx) } path("add") { path("link") { - get { ctx -> contactController.link(ctx) } + get { ctx -> contactController.getLink(ctx) } } path("pending") { get { ctx -> contactController.listPendingContacts(ctx) } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt index cb454ddba..120015f02 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactController.kt @@ -5,7 +5,7 @@ import io.javalin.Context interface ContactController { fun list(ctx: Context): Context - fun link(ctx: Context): Context + fun getLink(ctx: Context): Context fun addPendingContact(ctx: Context): Context fun listPendingContacts(ctx: Context): Context fun removePendingContact(ctx: Context): Context diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt index 16a17a532..657649260 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/ContactControllerImpl.kt @@ -1,9 +1,11 @@ package org.briarproject.briar.headless.contact import com.fasterxml.jackson.databind.ObjectMapper +import io.javalin.BadRequestResponse import io.javalin.Context import io.javalin.NotFoundResponse import org.briarproject.bramble.api.contact.ContactManager +import org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX import org.briarproject.bramble.api.contact.PendingContactId import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent @@ -12,6 +14,8 @@ import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchPendingContactException import org.briarproject.bramble.api.event.Event import org.briarproject.bramble.api.event.EventListener +import org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH +import org.briarproject.bramble.util.StringUtils.toUtf8 import org.briarproject.briar.headless.event.WebSocketController import org.briarproject.briar.headless.getContactIdFromPathParam import org.briarproject.briar.headless.getFromJson @@ -57,7 +61,7 @@ constructor( return ctx.json(contacts) } - override fun link(ctx: Context): Context { + override fun getLink(ctx: Context): Context { val linkDict = JsonDict("link" to contactManager.handshakeLink) return ctx.json(linkDict) } @@ -65,6 +69,10 @@ constructor( override fun addPendingContact(ctx: Context): Context { val link = ctx.getFromJson(objectMapper, "link") val alias = ctx.getFromJson(objectMapper, "alias") + if (!LINK_REGEX.matcher(link).find()) throw BadRequestResponse("Invalid Link") + val aliasUtf8 = toUtf8(alias) + if (aliasUtf8.isEmpty() || aliasUtf8.size > MAX_AUTHOR_NAME_LENGTH) + throw BadRequestResponse("Invalid Alias") val pendingContact = contactManager.addPendingContact(link, alias) return ctx.json(pendingContact.output()) } diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt index 232ce74dc..e4b6cf7e1 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt @@ -8,7 +8,12 @@ import org.briarproject.briar.headless.json.JsonDict internal fun Contact.output() = JsonDict( "contactId" to id.int, "author" to author.output(), + "alias" to alias, "verified" to isVerified -) +).apply { + handshakePublicKey?.let { put("handshakePublicKey", it.encoded) } +} -internal fun ContactAddedRemotelyEvent.output() = contact.output() +internal fun ContactAddedRemotelyEvent.output() = JsonDict( + "contact" to contact.output() +) diff --git a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt index 118c279f6..05128f28a 100644 --- a/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt +++ b/briar-headless/src/test/java/org/briarproject/briar/headless/contact/ContactControllerTest.kt @@ -1,5 +1,6 @@ package org.briarproject.briar.headless.contact +import io.javalin.BadRequestResponse import io.javalin.NotFoundResponse import io.javalin.json.JavalinJson.toJson import io.mockk.Runs @@ -15,11 +16,14 @@ import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchPendingContactException +import org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH import org.briarproject.bramble.identity.output import org.briarproject.bramble.test.TestUtils.getPendingContact import org.briarproject.bramble.test.TestUtils.getRandomBytes +import org.briarproject.bramble.util.StringUtils.getRandomString import org.briarproject.briar.headless.ControllerTest import org.briarproject.briar.headless.json.JsonDict +import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Assertions.assertThrows import org.junit.jupiter.api.Test @@ -49,12 +53,12 @@ internal class ContactControllerTest : ControllerTest() { val link = "briar://link" every { contactManager.handshakeLink } returns link every { ctx.json(JsonDict("link" to link)) } returns ctx - controller.link(ctx) + controller.getLink(ctx) } @Test fun testAddPendingContact() { - val link = "briar://link123" + val link = "briar://briar://adnsyffpsenoc3yzlhr24aegfq2pwan7kkselocill2choov6sbhs" val alias = "Alias123" val body = """{ "link": "$link", @@ -66,6 +70,58 @@ internal class ContactControllerTest : ControllerTest() { controller.addPendingContact(ctx) } + @Test + fun testAddPendingContactInvalidLink() { + val link = "briar://link123" + val alias = "Alias123" + val body = """{ + "link": "$link", + "alias": "$alias" + }""" + every { ctx.body() } returns body + assertThrows(BadRequestResponse::class.java) { + controller.addPendingContact(ctx) + } + } + + @Test + fun testAddPendingContactMissingLink() { + val alias = "Alias123" + val body = """{ + "alias": "$alias" + }""" + every { ctx.body() } returns body + assertThrows(BadRequestResponse::class.java) { + controller.addPendingContact(ctx) + } + } + + @Test + fun testAddPendingContactInvalidAlias() { + val link = "briar://briar://adnsyffpsenoc3yzlhr24aegfq2pwan7kkselocill2choov6sbhs" + val alias = getRandomString(MAX_AUTHOR_NAME_LENGTH + 1) + val body = """{ + "link": "$link", + "alias": "$alias" + }""" + every { ctx.body() } returns body + assertThrows(BadRequestResponse::class.java) { + controller.addPendingContact(ctx) + } + } + + @Test + fun testAddPendingContactMissingAlias() { + val link = "briar://adnsyffpsenoc3yzlhr24aegfq2pwan7kkselocill2choov6sbhs" + val body = """{ + "link": "$link" + }""" + every { ctx.body() } returns body + assertThrows(BadRequestResponse::class.java) { + controller.addPendingContact(ctx) + } + } + @Test fun testListPendingContacts() { every { contactManager.pendingContacts } returns listOf(pendingContact) @@ -185,10 +241,13 @@ internal class ContactControllerTest : ControllerTest() { @Test fun testOutputContact() { + assertNotNull(contact.handshakePublicKey) val json = """ { "contactId": ${contact.id.int}, "author": ${toJson(author.output())}, + "alias" : "${contact.alias}", + "handshakePublicKey": ${toJson(contact.handshakePublicKey!!.encoded)}, "verified": ${contact.isVerified} } """ @@ -202,7 +261,7 @@ internal class ContactControllerTest : ControllerTest() { "formatVersion": 1, "id": ${toJson(author.id.bytes)}, "name": "${author.name}", - "publicKey": ${toJson(author.publicKey)} + "publicKey": ${toJson(author.publicKey.encoded)} } """ assertJsonEquals(json, author.output()) @@ -211,7 +270,12 @@ internal class ContactControllerTest : ControllerTest() { @Test fun testOutputContactAddedRemotelyEvent() { val event = ContactAddedRemotelyEvent(contact) - assertJsonEquals(toJson(contact.output()), event.output()) + val json = """ + { + "contact": ${toJson(contact.output())} + } + """ + assertJsonEquals(json, event.output()) } @Test From 816598b631c7c5f4116055cebceec5ecc1681edf Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Wed, 15 May 2019 16:03:02 -0300 Subject: [PATCH 9/9] [headless] only include alias in contact's JSON representation if it exists --- .../org/briarproject/briar/headless/contact/OutputContact.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt index e4b6cf7e1..7f5f35f54 100644 --- a/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt +++ b/briar-headless/src/main/java/org/briarproject/briar/headless/contact/OutputContact.kt @@ -8,9 +8,9 @@ import org.briarproject.briar.headless.json.JsonDict internal fun Contact.output() = JsonDict( "contactId" to id.int, "author" to author.output(), - "alias" to alias, "verified" to isVerified ).apply { + alias?.let { put("alias", it) } handshakePublicKey?.let { put("handshakePublicKey", it.encoded) } }