From 1866712067864a9648e7d1c6f1edad47a1a24025 Mon Sep 17 00:00:00 2001 From: Felix Prahl-Kamps Date: Mon, 27 May 2019 16:06:07 +0200 Subject: [PATCH] initial commit --- .idea/codeStyles/codeStyleConfig.xml | 5 - .idea/encodings.xml | 4 + .idea/inspectionProfiles/Project_Default.xml | 15 + .idea/misc.xml | 3 - .idea/modules.xml | 2 +- .idea/runConfigurations.xml | 12 + .idea/uiDesigner.xml | 124 ----- .idea/vcs.xml | 6 + app/build.gradle | 46 +- .../mispbump/ExampleInstrumentedTest.java | 4 +- app/src/main/AndroidManifest.xml | 69 ++- .../wg/its/mispbump/MainActivity.java | 191 ------- .../its/mispbump/MyOrganisationActivity.java | 333 ------------- .../wg/its/mispbump/QrSyncActivity.java | 456 ----------------- .../wg/its/mispbump/SyncUploadActivity.java | 470 ------------------ .../adapter/OrganisationInfoEntryAdapter.java | 76 --- .../adapter/SyncedPartnerAdapter.java | 92 ---- .../mispbump/adapter/UploadStateAdapter.java | 102 ---- .../its/mispbump/auxiliary/AESSecurity.java | 157 ------ .../mispbump/auxiliary/PreferenceManager.java | 142 ------ .../its/mispbump/auxiliary/RandomString.java | 50 -- .../its/mispbump/auxiliary/ReadableError.java | 49 -- .../wg/its/mispbump/auxiliary/TempAuth.java | 7 - .../its/mispbump/cam/AutoFitTextureView.java | 76 --- .../wg/its/mispbump/model/Organisation.java | 193 ------- .../wg/its/mispbump/model/PublicKeyQr.java | 57 --- .../wg/its/mispbump/model/Server.java | 105 ---- .../wg/its/mispbump/model/StringPair.java | 11 - .../its/mispbump/model/SyncInformationQr.java | 50 -- .../wg/its/mispbump/model/SyncedPartner.java | 48 -- .../wg/its/mispbump/model/UploadState.java | 57 --- .../overview/wg/its/mispbump/model/User.java | 301 ----------- .../JsonArrayRequestWithJsonObject.java | 42 -- .../wg/its/mispbump/network/MispRequest.java | 432 ---------------- .../java/lu/circl/mispbump/AESActivity.java | 65 +++ .../java/lu/circl/mispbump/HomeActivity.java | 120 +++++ .../java/lu/circl/mispbump/LoginActivity.java | 175 +++++++ .../lu/circl/mispbump/StartUpActivity.java | 33 ++ .../java/lu/circl/mispbump/SyncActivity.java | 234 +++++++++ .../circl/mispbump/adapters/UserAdapter.java | 60 +++ .../lu/circl/mispbump/auxiliary/KeyValue.java | 11 + .../mispbump/auxiliary/PreferenceManager.java | 312 ++++++++++++ .../mispbump/cam/AutoFitTextureView.java | 76 +++ .../circl}/mispbump/cam/CameraFragment.java | 230 ++++++--- .../restful_client/MispOrganisation.java | 10 + .../restful_client/MispRestClient.java | 346 +++++++++++++ .../restful_client/MispRestService.java | 39 ++ .../mispbump/restful_client/MispServer.java | 28 ++ .../mispbump/restful_client/MispUser.java | 12 + .../mispbump/restful_client/Organisation.java | 82 +++ .../circl/mispbump/restful_client/Server.java | 130 +++++ .../circl/mispbump/restful_client/User.java | 115 +++++ .../circl/mispbump/security/AESSecurity.java | 154 ++++++ .../mispbump/security/KeyStoreWrapper.java | 198 ++++++++ app/src/main/res/anim/slide_down.xml | 16 - app/src/main/res/anim/slide_up.xml | 21 - .../drawable-v24/ic_launcher_foreground.xml | 64 +-- .../main/res/drawable/ic_account_circle.xml | 5 + ...d.xml => ic_cloud_download_black_24dp.xml} | 0 ...d.xml => ic_cloud_download_light_24dp.xml} | 2 +- .../main/res/drawable/ic_delete_forever.xml | 5 + .../{icon_add.xml => ic_email_black_24dp.xml} | 2 +- .../drawable/ic_help_outline_black_24dp.xml | 5 + .../res/drawable/ic_launcher_background.xml | 142 +++--- app/src/main/res/drawable/ic_person.xml | 5 + .../main/res/drawable/ic_sync_black_24dp.xml | 5 + .../main/res/drawable/icon_arrow_right.xml | 5 - app/src/main/res/drawable/icon_check.xml | 9 - app/src/main/res/drawable/icon_close.xml | 9 - .../main/res/drawable/icon_cloud_upload.xml | 9 - app/src/main/res/drawable/icon_contact.xml | 9 - app/src/main/res/drawable/icon_forward.xml | 9 - app/src/main/res/drawable/icon_hour_glass.xml | 9 - app/src/main/res/drawable/icon_key.xml | 9 - app/src/main/res/drawable/icon_retry.xml | 9 - .../main/res/drawable/icon_round_check.xml | 12 - .../main/res/drawable/icon_round_error.xml | 9 - app/src/main/res/drawable/icon_settings.xml | 9 - app/src/main/res/drawable/rounded_square.xml | 12 - app/src/main/res/layout/activity_aes.xml | 59 +++ app/src/main/res/layout/activity_home.xml | 119 +++++ app/src/main/res/layout/activity_login.xml | 95 ++++ app/src/main/res/layout/activity_main.xml | 62 --- .../res/layout/activity_my_organisation.xml | 63 --- app/src/main/res/layout/activity_qr_sync.xml | 69 --- app/src/main/res/layout/activity_start_up.xml | 9 + app/src/main/res/layout/activity_sync.xml | 50 ++ app/src/main/res/layout/activity_upload.xml | 74 --- .../res/layout/dialog_enter_credentials.xml | 40 -- app/src/main/res/layout/dialog_public_key.xml | 27 - .../main/res/layout/dialog_save_authkey.xml | 14 - .../res/layout/dialog_select_delete_data.xml | 29 -- app/src/main/res/layout/dialog_sync_info.xml | 27 - app/src/main/res/layout/fragment_camera.xml | 26 +- .../main/res/layout/row_org_info_entry.xml | 31 -- .../res/layout/row_synced_organisation.xml | 56 --- app/src/main/res/layout/row_upload_state.xml | 59 --- app/src/main/res/layout/view_organisation.xml | 84 ---- app/src/main/res/layout/view_pk_info.xml | 36 -- app/src/main/res/layout/viewholder_user.xml | 43 ++ app/src/main/res/menu/main_menu.xml | 19 + app/src/main/res/menu/menu_login.xml | 11 + app/src/main/res/menu/menu_main.xml | 16 - app/src/main/res/menu/menu_my_org.xml | 10 - .../res/mipmap-anydpi-v26/ic_launcher.xml | 4 +- .../mipmap-anydpi-v26/ic_launcher_round.xml | 4 +- app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 3056 -> 2963 bytes .../res/mipmap-hdpi/ic_launcher_round.png | Bin 5024 -> 4905 bytes .../mipmap-hdpi/launcher_handshake_round.png | Bin 6967 -> 0 bytes .../mipmap-hdpi/launcher_handshake_square.png | Bin 4749 -> 0 bytes .../main/res/mipmap-hdpi/launcher_round_2.png | Bin 7694 -> 0 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 2096 -> 2060 bytes .../res/mipmap-mdpi/ic_launcher_round.png | Bin 2858 -> 2783 bytes .../mipmap-mdpi/launcher_handshake_round.png | Bin 3658 -> 0 bytes .../mipmap-mdpi/launcher_handshake_square.png | Bin 2495 -> 0 bytes .../main/res/mipmap-mdpi/launcher_round_2.png | Bin 3972 -> 0 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 4569 -> 4490 bytes .../res/mipmap-xhdpi/ic_launcher_round.png | Bin 7098 -> 6895 bytes .../mipmap-xhdpi/launcher_handshake_round.png | Bin 9650 -> 0 bytes .../launcher_handshake_square.png | Bin 6539 -> 0 bytes .../res/mipmap-xhdpi/launcher_round_2.png | Bin 10854 -> 0 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 6464 -> 6387 bytes .../res/mipmap-xxhdpi/ic_launcher_round.png | Bin 10676 -> 10413 bytes .../launcher_handshake_round.png | Bin 18233 -> 0 bytes .../launcher_handshake_square.png | Bin 11931 -> 0 bytes .../res/mipmap-xxhdpi/launcher_round_2.png | Bin 20619 -> 0 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 9250 -> 9128 bytes .../res/mipmap-xxxhdpi/ic_launcher_round.png | Bin 15523 -> 15132 bytes .../launcher_handshake_round.png | Bin 27323 -> 0 bytes .../launcher_handshake_square.png | Bin 19482 -> 0 bytes .../res/mipmap-xxxhdpi/launcher_round_2.png | Bin 30906 -> 0 bytes app/src/main/res/raw/misp.crt | 23 + app/src/main/res/values-de/strings.xml | 52 -- app/src/main/res/values/colors.xml | 12 +- app/src/main/res/values/strings.xml | 64 +-- app/src/main/res/values/styles.xml | 27 +- .../circl}/mispbump/ExampleUnitTest.java | 2 +- build.gradle | 10 +- gradle.properties | 2 + gradle/wrapper/gradle-wrapper.jar | Bin 54329 -> 54329 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- 141 files changed, 3056 insertions(+), 4883 deletions(-) delete mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/encodings.xml create mode 100644 .idea/inspectionProfiles/Project_Default.xml create mode 100644 .idea/runConfigurations.xml delete mode 100644 .idea/uiDesigner.xml create mode 100644 .idea/vcs.xml rename app/src/androidTest/java/{de/overview/wg/its => lu/circl}/mispbump/ExampleInstrumentedTest.java (83%) delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/Server.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/model/User.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java delete mode 100644 app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java create mode 100644 app/src/main/java/lu/circl/mispbump/AESActivity.java create mode 100644 app/src/main/java/lu/circl/mispbump/HomeActivity.java create mode 100644 app/src/main/java/lu/circl/mispbump/LoginActivity.java create mode 100644 app/src/main/java/lu/circl/mispbump/StartUpActivity.java create mode 100644 app/src/main/java/lu/circl/mispbump/SyncActivity.java create mode 100644 app/src/main/java/lu/circl/mispbump/adapters/UserAdapter.java create mode 100644 app/src/main/java/lu/circl/mispbump/auxiliary/KeyValue.java create mode 100644 app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java create mode 100644 app/src/main/java/lu/circl/mispbump/cam/AutoFitTextureView.java rename app/src/main/java/{de/overview/wg/its => lu/circl}/mispbump/cam/CameraFragment.java (83%) create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/MispOrganisation.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/MispRestClient.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/Server.java create mode 100644 app/src/main/java/lu/circl/mispbump/restful_client/User.java create mode 100644 app/src/main/java/lu/circl/mispbump/security/AESSecurity.java create mode 100644 app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java delete mode 100644 app/src/main/res/anim/slide_down.xml delete mode 100644 app/src/main/res/anim/slide_up.xml create mode 100644 app/src/main/res/drawable/ic_account_circle.xml rename app/src/main/res/drawable/{icon_cloud_download.xml => ic_cloud_download_black_24dp.xml} (100%) rename app/src/main/res/drawable/{icon_cloud.xml => ic_cloud_download_light_24dp.xml} (87%) create mode 100644 app/src/main/res/drawable/ic_delete_forever.xml rename app/src/main/res/drawable/{icon_add.xml => ic_email_black_24dp.xml} (61%) create mode 100644 app/src/main/res/drawable/ic_help_outline_black_24dp.xml create mode 100644 app/src/main/res/drawable/ic_person.xml create mode 100644 app/src/main/res/drawable/ic_sync_black_24dp.xml delete mode 100644 app/src/main/res/drawable/icon_arrow_right.xml delete mode 100644 app/src/main/res/drawable/icon_check.xml delete mode 100644 app/src/main/res/drawable/icon_close.xml delete mode 100644 app/src/main/res/drawable/icon_cloud_upload.xml delete mode 100644 app/src/main/res/drawable/icon_contact.xml delete mode 100644 app/src/main/res/drawable/icon_forward.xml delete mode 100644 app/src/main/res/drawable/icon_hour_glass.xml delete mode 100644 app/src/main/res/drawable/icon_key.xml delete mode 100644 app/src/main/res/drawable/icon_retry.xml delete mode 100644 app/src/main/res/drawable/icon_round_check.xml delete mode 100644 app/src/main/res/drawable/icon_round_error.xml delete mode 100644 app/src/main/res/drawable/icon_settings.xml delete mode 100644 app/src/main/res/drawable/rounded_square.xml create mode 100644 app/src/main/res/layout/activity_aes.xml create mode 100644 app/src/main/res/layout/activity_home.xml create mode 100644 app/src/main/res/layout/activity_login.xml delete mode 100644 app/src/main/res/layout/activity_main.xml delete mode 100644 app/src/main/res/layout/activity_my_organisation.xml delete mode 100644 app/src/main/res/layout/activity_qr_sync.xml create mode 100644 app/src/main/res/layout/activity_start_up.xml create mode 100644 app/src/main/res/layout/activity_sync.xml delete mode 100644 app/src/main/res/layout/activity_upload.xml delete mode 100644 app/src/main/res/layout/dialog_enter_credentials.xml delete mode 100644 app/src/main/res/layout/dialog_public_key.xml delete mode 100644 app/src/main/res/layout/dialog_save_authkey.xml delete mode 100644 app/src/main/res/layout/dialog_select_delete_data.xml delete mode 100644 app/src/main/res/layout/dialog_sync_info.xml delete mode 100644 app/src/main/res/layout/row_org_info_entry.xml delete mode 100644 app/src/main/res/layout/row_synced_organisation.xml delete mode 100644 app/src/main/res/layout/row_upload_state.xml delete mode 100644 app/src/main/res/layout/view_organisation.xml delete mode 100644 app/src/main/res/layout/view_pk_info.xml create mode 100644 app/src/main/res/layout/viewholder_user.xml create mode 100644 app/src/main/res/menu/main_menu.xml create mode 100644 app/src/main/res/menu/menu_login.xml delete mode 100644 app/src/main/res/menu/menu_main.xml delete mode 100644 app/src/main/res/menu/menu_my_org.xml delete mode 100644 app/src/main/res/mipmap-hdpi/launcher_handshake_round.png delete mode 100644 app/src/main/res/mipmap-hdpi/launcher_handshake_square.png delete mode 100644 app/src/main/res/mipmap-hdpi/launcher_round_2.png delete mode 100644 app/src/main/res/mipmap-mdpi/launcher_handshake_round.png delete mode 100644 app/src/main/res/mipmap-mdpi/launcher_handshake_square.png delete mode 100644 app/src/main/res/mipmap-mdpi/launcher_round_2.png delete mode 100644 app/src/main/res/mipmap-xhdpi/launcher_handshake_round.png delete mode 100644 app/src/main/res/mipmap-xhdpi/launcher_handshake_square.png delete mode 100644 app/src/main/res/mipmap-xhdpi/launcher_round_2.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/launcher_handshake_round.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/launcher_handshake_square.png delete mode 100644 app/src/main/res/mipmap-xxhdpi/launcher_round_2.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/launcher_handshake_round.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/launcher_handshake_square.png delete mode 100644 app/src/main/res/mipmap-xxxhdpi/launcher_round_2.png create mode 100644 app/src/main/res/raw/misp.crt delete mode 100644 app/src/main/res/values-de/strings.xml rename app/src/test/java/{de/overview/wg/its => lu/circl}/mispbump/ExampleUnitTest.java (90%) diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml deleted file mode 100644 index a55e7a1..0000000 --- a/.idea/codeStyles/codeStyleConfig.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..15a15b2 --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..786a0ea --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,15 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 37a7509..10467e7 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -3,7 +3,4 @@ - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml index 319e325..86df06d 100644 --- a/.idea/modules.xml +++ b/.idea/modules.xml @@ -2,8 +2,8 @@ + - \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/uiDesigner.xml b/.idea/uiDesigner.xml deleted file mode 100644 index e96534f..0000000 --- a/.idea/uiDesigner.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index b623d6c..cdb0917 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,11 +1,11 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 27 + compileSdkVersion 28 defaultConfig { - applicationId "de.overview.wg.its.mispbump" - minSdkVersion 21 - targetSdkVersion 27 + applicationId "lu.circl.mispbump" + minSdkVersion 23 + targetSdkVersion 28 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -13,31 +13,37 @@ android { buildTypes { release { minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } } dependencies { - implementation 'com.android.support:appcompat-v7:27.1.1' - implementation 'com.android.support:design:27.1.1' - implementation 'com.android.support:gridlayout-v7:27.1.1' - implementation 'com.android.support:recyclerview-v7:27.1.1' - implementation 'com.android.support:cardview-v7:27.1.1' - implementation 'com.android.support.constraint:constraint-layout:1.1.2' - implementation 'com.android.support:preference-v7:27.1.1' - implementation 'com.android.support:preference-v14:27.1.1' + // retrofit + implementation 'com.squareup.retrofit2:retrofit:2.5.0' + implementation 'com.squareup.retrofit2:converter-gson:2.5.0' + implementation 'com.squareup.okhttp3:logging-interceptor:3.8.0' - implementation 'com.google.android.gms:play-services-vision:15.0.2' + // android + implementation 'com.android.support:appcompat-v7:28.0.0' + implementation 'com.android.support:design:28.0.0' + implementation 'com.android.support.constraint:constraint-layout:1.1.3' + implementation 'com.android.support:cardview-v7:28.0.0' + implementation 'com.android.support:recyclerview-v7:28.0.0' - implementation 'com.android.volley:volley:1.1.0' - implementation 'com.github.kenglxn.QRGen:android:2.5.0' - implementation 'org.mongodb:bson:3.8.0' - implementation 'com.google.code.gson:gson:2.8.5' + // barcode scanning + implementation 'com.google.android.gms:play-services-vision:17.0.2' - implementation fileTree(include: ['*.jar'], dir: 'libs') - implementation 'com.android.support:support-v4:27.1.1' + // barcode generation + implementation 'com.journeyapps:zxing-android-embedded:3.2.0@aar' + implementation 'com.google.zxing:core:3.3.0' + + // override due to play-services-vision version conflicts + implementation 'com.android.support:support-media-compat:28.0.0' + implementation 'com.android.support:support-v4:28.0.0' + + implementation fileTree(dir: 'libs', include: ['*.jar']) testImplementation 'junit:junit:4.12' androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' diff --git a/app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java b/app/src/androidTest/java/lu/circl/mispbump/ExampleInstrumentedTest.java similarity index 83% rename from app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java rename to app/src/androidTest/java/lu/circl/mispbump/ExampleInstrumentedTest.java index 7cb3cc1..75c255d 100644 --- a/app/src/androidTest/java/de/overview/wg/its/mispbump/ExampleInstrumentedTest.java +++ b/app/src/androidTest/java/lu/circl/mispbump/ExampleInstrumentedTest.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispbump; +package lu.circl.mispbump; import android.content.Context; import android.support.test.InstrumentationRegistry; @@ -21,6 +21,6 @@ public class ExampleInstrumentedTest { // Context of the app under test. Context appContext = InstrumentationRegistry.getTargetContext(); - assertEquals("de.overview.wg.its.mispbump", appContext.getPackageName()); + assertEquals("lu.circl.mispbump", appContext.getPackageName()); } } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index e03baac..8d40ef8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -1,44 +1,39 @@ + xmlns:tools="http://schemas.android.com/tools" + package="lu.circl.mispbump"> - - + + - - - - + + + + - - - - - - - - - - - - + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java deleted file mode 100644 index 7d8681d..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/MainActivity.java +++ /dev/null @@ -1,191 +0,0 @@ -package de.overview.wg.its.mispbump; - -import android.annotation.SuppressLint; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.drawable.Drawable; -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.content.ContextCompat; -import android.support.v4.graphics.drawable.DrawableCompat; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.DefaultItemAnimator; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.CheckBox; -import android.widget.TextView; -import de.overview.wg.its.mispbump.adapter.SyncedPartnerAdapter; -import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; -import de.overview.wg.its.mispbump.model.SyncedPartner; - -import java.util.ArrayList; -import java.util.List; - -/** - * - **/ - -@SuppressWarnings("ConstantConditions") -public class MainActivity extends AppCompatActivity { - - private List syncedPartnerList = new ArrayList<>(); - private SyncedPartnerAdapter syncedPartnerAdapter; - private TextView emptyPartnerListView; - private RecyclerView syncedPartnerRecyclerView; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - initializeViews(); - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_main, menu); - - // Make icon white (compat limitation in xml) - Drawable drawable = menu.findItem(R.id.menu_item_credential_settings).getIcon(); - drawable = DrawableCompat.wrap(drawable); - DrawableCompat.setTint(drawable, ContextCompat.getColor(this, R.color.colorWhite)); - menu.findItem(R.id.menu_item_credential_settings).setIcon(drawable); - - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - int id = item.getItemId(); - - switch (id) { - case R.id.menu_item_credential_settings: - startCredentialsActivity(); - return true; - - case R.id.menu_item_delete_local_data: - createSelectDeleteDialog(); - return true; - } - - return super.onOptionsItemSelected(item); - } - - - private void initializeViews() { - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - getSupportActionBar().setDisplayShowTitleEnabled(true); - - FloatingActionButton fab = findViewById(R.id.fab_continue_sync_info); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - startSyncActivity(); - } - }); - - emptyPartnerListView = findViewById(R.id.empty); - syncedPartnerRecyclerView = findViewById(R.id.recyclerView); - - syncedPartnerAdapter = new SyncedPartnerAdapter(this, syncedPartnerList); - RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(getApplicationContext()); - syncedPartnerRecyclerView.setLayoutManager(mLayoutManager); - syncedPartnerRecyclerView.setItemAnimator(new DefaultItemAnimator()); - syncedPartnerRecyclerView.setAdapter(syncedPartnerAdapter); - - refreshSyncedPartnerList(); - } - - private void createSelectDeleteDialog() { - - final PreferenceManager prefs = PreferenceManager.Instance(this); - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - - adb.setTitle("Delete Local Data"); - adb.setMessage("(Checked items will be deleted)"); - - @SuppressLint("InflateParams") - View checkBoxView = getLayoutInflater().inflate(R.layout.dialog_select_delete_data, null); - - final CheckBox checkSyncedPartner = checkBoxView.findViewById(R.id.check_synced_partner_list); - final CheckBox checkCredentials = checkBoxView.findViewById(R.id.check_credentials); - final CheckBox checkUserData = checkBoxView.findViewById(R.id.check_user_preferences); - - adb.setView(checkBoxView); - - adb.setPositiveButton(getResources().getString(R.string.delete), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - if (checkSyncedPartner.isChecked()) { - prefs.clearSyncedInformationPreferences(); - } - - if (checkCredentials.isChecked()) { - prefs.clearCredentialPreferences(); - } - - if (checkUserData.isChecked()) { - prefs.clearUserPreferences(); - } - } - }); - - adb.setNegativeButton(getResources().getString(android.R.string.cancel), null); - - Dialog d = adb.create(); - d.getWindow().setWindowAnimations(R.style.DialogAnimation); - d.show(); - } - - private void refreshSyncedPartnerList() { - // todo: uncomment - // syncedPartnerList = PreferenceManager.Instance(this).getSyncedPartnerList(); - - if (syncedPartnerList == null || syncedPartnerList.size() < 1) { - emptyPartnerListView.setVisibility(View.VISIBLE); - syncedPartnerRecyclerView.setVisibility(View.GONE); - } else { - emptyPartnerListView.setVisibility(View.GONE); - syncedPartnerAdapter.setSyncedPartnerList(syncedPartnerList); - } - } - - private void startSyncActivity() { - - PreferenceManager preferenceManager = PreferenceManager.Instance(this); - - if (preferenceManager.getMyOrganisation() == null || preferenceManager.getMyUser() == null) { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - adb.setTitle(getResources().getString(R.string.missing_local_information_title)); - adb.setMessage(getResources().getString(R.string.missing_local_information_message)); - - adb.setPositiveButton(getResources().getString(R.string.enter_credentials), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startCredentialsActivity(); - } - }); - - adb.setNegativeButton(android.R.string.cancel, null); - adb.show(); - - } else { - startActivity(new Intent(this, QrSyncActivity.class)); - } - - } - - private void startCredentialsActivity() { - startActivity(new Intent(this, MyOrganisationActivity.class)); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java deleted file mode 100644 index 7298823..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/MyOrganisationActivity.java +++ /dev/null @@ -1,333 +0,0 @@ -package de.overview.wg.its.mispbump; - -import android.app.Dialog; -import android.content.DialogInterface; -import android.os.Build; -import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.Snackbar; -import android.support.design.widget.TextInputLayout; -import android.support.v7.app.AlertDialog; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.support.v7.widget.DefaultItemAnimator; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.widget.Button; -import android.widget.CheckBox; -import android.widget.ProgressBar; -import com.android.volley.VolleyError; -import de.overview.wg.its.mispbump.adapter.OrganisationInfoEntryAdapter; -import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; -import de.overview.wg.its.mispbump.auxiliary.ReadableError; -import de.overview.wg.its.mispbump.model.Organisation; -import de.overview.wg.its.mispbump.model.StringPair; -import de.overview.wg.its.mispbump.model.User; -import de.overview.wg.its.mispbump.network.MispRequest; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.List; - -public class MyOrganisationActivity extends AppCompatActivity implements View.OnClickListener { - - private PreferenceManager preferenceManager; - private RecyclerView recyclerView; - private OrganisationInfoEntryAdapter adapter; - private View empty; - private ProgressBar progressBar; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_my_organisation); - - initializeContent(); - loadMyInformation(); - } - - @Override - public void onClick(View v) { - - int id = v.getId(); - - switch (id) { - case R.id.fab_download: - - enterCredentialsDialog(); - - break; - } - - } - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - getMenuInflater().inflate(R.menu.menu_my_org, menu); - return super.onCreateOptionsMenu(menu); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - - int id = item.getItemId(); - - switch (id) { - - case R.id.menu_delete_local_data: - deleteLocalDataDialog(); - break; - - case R.id.load_config: - - if (Build.VERSION.SDK_INT > 25) { - preferenceManager.setServerUrl("http://192.168.178.200"); - preferenceManager.setAutomationKey("d2UEstcJiySUWpsaeiXnEFGoI1xcWhAEIiVgZOmW"); - } else { - preferenceManager.setServerUrl("http://192.168.178.201"); - preferenceManager.setAutomationKey("eCcz0TTLEc8MeZihsoyyeqlYpd4V8PCDsDA4tM75"); - } - - break; - } - - return super.onOptionsItemSelected(item); - } - - - private void initializeContent() { - - Toolbar t = findViewById(R.id.toolbar); - setSupportActionBar(t); - - getSupportActionBar().setDisplayHomeAsUpEnabled(true); - getSupportActionBar().setDisplayShowTitleEnabled(true); - - empty = findViewById(R.id.empty); - progressBar = findViewById(R.id.progressBar); - - adapter = new OrganisationInfoEntryAdapter(this); - - recyclerView = findViewById(R.id.recyclerView); - recyclerView.setLayoutManager(new LinearLayoutManager(this)); - recyclerView.setItemAnimator(new DefaultItemAnimator()); - recyclerView.setAdapter(adapter); - - FloatingActionButton fab = findViewById(R.id.fab_download); - fab.setOnClickListener(this); - - preferenceManager = PreferenceManager.Instance(this); - } - - private void storeCredentials(String url, String automationKey, boolean saveAutomationKey) { - - if (saveAutomationKey) { - preferenceManager.setAutomationKey(automationKey); - } else { - preferenceManager.setAutomationKey(""); - } - - preferenceManager.setServerUrl(url); - } - - private void storeMyInformation(Organisation org, User user) { - - if (org != null) { - preferenceManager.setMyOrganisation(org); - } - - if (user != null) { - preferenceManager.setMyUser(user); - } - - } - - private void loadMyInformation() { - - empty.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - - Organisation myOrg = preferenceManager.getMyOrganisation(); - User myUser = preferenceManager.getMyUser(); - - visualizeInformation(myOrg, myUser); - } - - private void downloadOrganisationInformation(String url, String automationKey) { - - empty.setVisibility(View.GONE); - recyclerView.setVisibility(View.GONE); - progressBar.setVisibility(View.VISIBLE); - - final MispRequest mispRequest = MispRequest.Instance(this, false); - mispRequest.setServerCredentials(url, automationKey); - - final User myUser = new User(); - final Organisation myOrganisation = new Organisation(); - - mispRequest.getMyUser(new MispRequest.UserCallback() { - @Override - public void onResult(JSONObject jsonUser) { - try { - - myUser.fromJSON(jsonUser); - - } catch (JSONException e) { - - alert(e.getMessage()); - - return; - } - - mispRequest.getOrganisation(myUser.getId(), new MispRequest.OrganisationCallback() { - @Override - public void onResult(JSONObject organisationInformation) { - try { - - myOrganisation.fromJSON(organisationInformation); - - storeMyInformation(myOrganisation, myUser); - visualizeInformation(myOrganisation, myUser); - - } catch (JSONException e) { - - alert(e.getMessage()); - visualizeInformation(null, null); - - return; - } - } - - @Override - public void onError(VolleyError volleyError) { - alert(ReadableError.toReadable(volleyError)); - visualizeInformation(null, null); - } - }); - } - - @Override - public void onError(VolleyError volleyError) { - alert(ReadableError.toReadable(volleyError)); - visualizeInformation(null, null); - } - }); - } - - private void visualizeInformation(Organisation org, User user) { - - progressBar.setVisibility(View.GONE); - - if (org != null && user != null) { - - empty.setVisibility(View.GONE); - recyclerView.setVisibility(View.VISIBLE); - - } else { - - empty.setVisibility(View.VISIBLE); - recyclerView.setVisibility(View.GONE); - - return; - } - - getSupportActionBar().setTitle(org.getName()); - - List orgInfoEntries = new ArrayList<>(); - - orgInfoEntries.add(new StringPair("Description", org.getDescription())); - orgInfoEntries.add(new StringPair("Nationality", org.getNationality())); - orgInfoEntries.add(new StringPair("Sector", org.getSector())); - orgInfoEntries.add(new StringPair("User Count", "" + org.getUserCount())); - orgInfoEntries.add(new StringPair("Email", user.getEmail())); - orgInfoEntries.add(new StringPair("UUID", org.getUuid())); - - adapter.setList(orgInfoEntries); - - } - - private void enterCredentialsDialog() { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - LayoutInflater inflater = getLayoutInflater(); - - adb.setTitle("MISP Credentials"); - - View v = inflater.inflate(R.layout.dialog_enter_credentials, null); - adb.setView(v); - - final CheckBox saveAutomationKey = v.findViewById(R.id.check_save_authkey); - final TextInputLayout serverUrlLayout = v.findViewById(R.id.input_layout_server_url); - final TextInputLayout automationKeyLayout = v.findViewById(R.id.input_layout_automation_key); - - saveAutomationKey.setChecked(preferenceManager.saveAuthKeyEnabled()); - serverUrlLayout.getEditText().setText(preferenceManager.getMyServerUrl()); - automationKeyLayout.getEditText().setText(preferenceManager.getMyServerAutomationKey()); - - adb.setPositiveButton("Download", null); - adb.setNegativeButton(android.R.string.cancel, null); - - final Dialog dialog = adb.create(); - dialog.show(); - - Button posButton = ((AlertDialog) dialog).getButton(AlertDialog.BUTTON_POSITIVE); - - posButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - String url = serverUrlLayout.getEditText().getText().toString(); - String automationKey = automationKeyLayout.getEditText().getText().toString(); - - boolean validCredentials = true; - - if (url.equals("")) { - validCredentials = false; - serverUrlLayout.setError(getString(R.string.error_url_required)); - } - - if (automationKey.equals("")) { - validCredentials = false; - automationKeyLayout.setError(getString(R.string.error_automation_key)); - } - - boolean save = saveAutomationKey.isChecked(); - preferenceManager.setSaveAuthKeyEnabled(save); - - if (validCredentials) { - dialog.dismiss(); - storeCredentials(url, automationKey, save); - downloadOrganisationInformation(url, automationKey); - } - } - }); - } - - private void deleteLocalDataDialog() { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - - adb.setTitle("Delete Local Data"); - - adb.setMessage(getString(R.string.delete_local_data_msg)); - - adb.setPositiveButton(getString(R.string.delete), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - preferenceManager.clearCredentialPreferences(); - } - }); - - adb.setNegativeButton(android.R.string.cancel, null); - - adb.create().show(); - } - - private void alert(String message) { - Snackbar.make(findViewById(R.id.coordinator), message, Snackbar.LENGTH_LONG).show(); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java deleted file mode 100644 index 7d073ba..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/QrSyncActivity.java +++ /dev/null @@ -1,456 +0,0 @@ -package de.overview.wg.its.mispbump; - -import android.animation.Animator; -import android.annotation.SuppressLint; -import android.app.AlertDialog; -import android.app.Dialog; -import android.content.DialogInterface; -import android.content.Intent; -import android.graphics.Point; -import android.os.Bundle; -import android.support.design.widget.FloatingActionButton; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentTransaction; -import android.support.v7.app.AppCompatActivity; -import android.util.Log; -import android.view.*; -import android.view.animation.DecelerateInterpolator; -import android.widget.ImageButton; -import android.widget.ImageView; -import android.widget.TextView; -import com.google.gson.Gson; -import de.overview.wg.its.mispbump.auxiliary.AESSecurity; -import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; -import de.overview.wg.its.mispbump.auxiliary.RandomString; -import de.overview.wg.its.mispbump.auxiliary.TempAuth; -import de.overview.wg.its.mispbump.cam.CameraFragment; -import de.overview.wg.its.mispbump.model.*; -import net.glxn.qrgen.android.QRCode; -import org.json.JSONException; - -public class QrSyncActivity extends AppCompatActivity implements View.OnClickListener { - - private enum ScanState { - public_key, - information - } - - private ScanState currentScanState; - - private FloatingActionButton proceedToSyncInfoFab, proceedToSyncUploadFab; - private PreferenceManager preferenceManager; - private View qrBackground; - private ImageView qrImage; - private CameraFragment cameraFragment; - private AESSecurity cryptography; - - private SyncInformationQr receivedSyncInfo; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); - setContentView(R.layout.activity_qr_sync); - - initializeContent(); - startPublicKeyExchange(); - } - - @Override - public void onClick(View v) { - - int id = v.getId(); - - switch (id) { - - case R.id.fab_continue_sync_info: - acceptProceedDialog(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startSyncInformationExchange(); - } - }); - break; - - case R.id.fab_continue_sync_upload: - - acceptProceedDialog(new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - startSyncUpload(); - } - }); - - break; - - case R.id.close: - finish(); - break; - } - } - - - private void initializeContent() { - - proceedToSyncInfoFab = findViewById(R.id.fab_continue_sync_info); - proceedToSyncInfoFab.hide(); - proceedToSyncInfoFab.setOnClickListener(this); - - proceedToSyncUploadFab = findViewById(R.id.fab_continue_sync_upload); - proceedToSyncUploadFab.hide(); - proceedToSyncUploadFab.setOnClickListener(this); - - ImageButton close = findViewById(R.id.close); - close.setOnClickListener(this); - - qrBackground = findViewById(R.id.qr_background); - qrBackground.setVisibility(View.INVISIBLE); - qrImage = findViewById(R.id.qr_imageView); - - preferenceManager = PreferenceManager.Instance(this); - cryptography = AESSecurity.getInstance(); - - cameraFragment = new CameraFragment(); - FragmentManager manager = getSupportFragmentManager(); - FragmentTransaction transaction = manager.beginTransaction(); - String camTag = cameraFragment.getClass().getSimpleName(); - transaction.replace(R.id.fragment_container, cameraFragment, camTag); - transaction.commit(); - - } - - private void startPublicKeyExchange() { - - currentScanState = ScanState.public_key; - cameraFragment.setReadQrEnabled(true); - - TextView info = findViewById(R.id.qr_info); - info.setText(getText(R.string.public_key)); - - - User myUser = preferenceManager.getMyUser(); - Organisation myOrg = preferenceManager.getMyOrganisation(); - String pubKey = AESSecurity.publicKeyToString(cryptography.getPublicKey()); - - PublicKeyQr publicKeyQr = new PublicKeyQr(myOrg.getName(), myUser.getEmail(), pubKey); - - showQr(publicKeyQr.toJSON().toString()); - } - - private void receivedPublicKey(PublicKeyQr publicKeyQr) { - cryptography.setForeignPublicKey(AESSecurity.publicKeyFromString(publicKeyQr.getKey())); - - runOnUiThread(new Runnable() { - @Override - public void run() { - proceedToSyncInfoFab.show(); - } - }); - } - - private void startSyncInformationExchange() { - - currentScanState = ScanState.information; - cameraFragment.setReadQrEnabled(true); - - TextView info = findViewById(R.id.qr_info); - info.setText(getString(R.string.sync_information)); - - Organisation myOrg = preferenceManager.getMyOrganisation(); - - proceedToSyncInfoFab.setVisibility(View.GONE); - cameraFragment.setReadQrEnabled(true); - - TempAuth.TMP_AUTH_KEY = new RandomString(40).nextString(); - - Server serverForMeOnOtherInstance = new Server(); - serverForMeOnOtherInstance.setAuthkey(TempAuth.TMP_AUTH_KEY); - serverForMeOnOtherInstance.setName("SyncServer for " + myOrg.getName()); - serverForMeOnOtherInstance.setUrl(preferenceManager.getMyServerUrl()); - - final SyncInformationQr siqr = new SyncInformationQr( - preferenceManager.getMyOrganisation(), - serverForMeOnOtherInstance, - preferenceManager.getMyUser()); - - - showQr(cryptography.encrypt(siqr.toJSON().toString())); - - } - - private void receivedSyncInformation(SyncInformationQr syncInformationQr) { - - receivedSyncInfo = syncInformationQr; - - runOnUiThread(new Runnable() { - @Override - public void run() { - proceedToSyncUploadFab.setVisibility(View.VISIBLE); - } - }); - - } - - public void onReadQrCode(String qrData) { - - switch (currentScanState) { - case public_key: - - try { - - publicKeyReceivedDialog(new PublicKeyQr(qrData)); - - } catch (JSONException e) { - notExpectedFormatDialog(); - } - - break; - - case information: - - try { - - syncInformationReceivedDialog(new SyncInformationQr(cryptography.decrypt(qrData))); - - } catch (JSONException e) { - notExpectedFormatDialog(); - } - - break; - } - - cameraFragment.setReadQrEnabled(false); - } - - private void showQr(String qrData) { - generateQr(qrData); - - if (qrBackground.getVisibility() == View.VISIBLE) { // First close if visible - circularReveal(qrBackground, false, 300, 0); // close directly - circularReveal(qrBackground, true, 300, 350); // open 250ms later - } else { - circularReveal(qrBackground, true, 300, 0); // if not visible just open directly - } - } - - private void hideQr() { - if (qrBackground.getVisibility() == View.VISIBLE) { - circularReveal(qrBackground, false, 200, 0); - } - } - - private void generateQr(String data) { - Display display = getWindowManager().getDefaultDisplay(); - Point size = new Point(); - display.getSize(size); - - int width = (int) (size.x * 0.8f); - - //noinspection SuspiciousNameCombination - qrImage.setImageBitmap(QRCode.from(data) - .withColor(0xFF000000, 0x00FFFFFF) - .withSize(width, width) - .bitmap()); - } - - private void startSyncUpload() { - Intent i = new Intent(this, SyncUploadActivity.class); - i.putExtra(SyncUploadActivity.PARTNER_INFO_BUNDLE_KEY, new Gson().toJson(receivedSyncInfo)); - startActivity(i); - finish(); - } - - private void publicKeyReceivedDialog(final PublicKeyQr pkqr) { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - LayoutInflater inflater = getLayoutInflater(); - - @SuppressLint("InflateParams") - View title = inflater.inflate(R.layout.dialog_public_key, null); - adb.setCustomTitle(title); - - View pkInfoView = inflater.inflate(R.layout.view_pk_info, null); - - TextView name = pkInfoView.findViewById(R.id.pk_info_organisation_name); - name.setText(pkqr.getOrganisation()); - - TextView email = pkInfoView.findViewById(R.id.pk_info_email); - email.setText(pkqr.getEmail()); - - adb.setView(pkInfoView); - - adb.setPositiveButton(getString(R.string.accept), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - receivedPublicKey(pkqr); - } - }); - - adb.setNegativeButton(getString(R.string.reject), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - cameraFragment.setReadQrEnabled(true); - } - }); - - adb.setCancelable(false); - - Dialog d = adb.create(); - - //noinspection ConstantConditions - d.getWindow().setWindowAnimations(R.style.DialogAnimation); - d.getWindow().setDimAmount(0.8f); - d.show(); - } - - private void syncInformationReceivedDialog(final SyncInformationQr siqr) { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - LayoutInflater inflater = getLayoutInflater(); - - @SuppressLint("InflateParams") - View title = inflater.inflate(R.layout.dialog_sync_info, null); - adb.setCustomTitle(title); - - @SuppressLint("InflateParams") - View orgView = inflater.inflate(R.layout.view_organisation, null); - - TextView orgTitle = orgView.findViewById(R.id.organisation_title); - orgTitle.setText(siqr.getOrganisation().getName()); - - TextView orgUuid = orgView.findViewById(R.id.organisation_uuid); - orgUuid.setText(siqr.getOrganisation().getUuid()); - - TextView orgDesc = orgView.findViewById(R.id.organisation_description); - orgDesc.setText(siqr.getOrganisation().getDescription()); - - TextView orgNat = orgView.findViewById(R.id.organisation_nationality); - orgNat.setText(siqr.getOrganisation().getNationality()); - - TextView orgSec = orgView.findViewById(R.id.organisation_sector); - orgSec.setText(siqr.getOrganisation().getSector()); - - TextView orgUser = orgView.findViewById(R.id.organisation_user_count); - orgUser.setText("" + siqr.getOrganisation().getUserCount()); - - adb.setView(orgView); - - adb.setPositiveButton(getString(R.string.accept), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - receivedSyncInformation(siqr); - } - }); - - adb.setNegativeButton(getString(R.string.reject), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - cameraFragment.setReadQrEnabled(true); - } - }); - - Dialog d = adb.create(); - //noinspection ConstantConditions - d.getWindow().setWindowAnimations(R.style.DialogAnimation); - d.getWindow().setDimAmount(0.8f); - - d.show(); - } - - private void acceptProceedDialog(Dialog.OnClickListener posListener) { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - - adb.setTitle(getString(R.string.proceed)); - - if (currentScanState == ScanState.public_key) { - adb.setMessage(getString(R.string.request_scanned_pk)); - } else { - adb.setMessage(getString(R.string.request_scanned_si)); - } - - adb.setPositiveButton(getString(R.string.yes), posListener); - adb.setNegativeButton(getString(R.string.no), null); - - adb.create().show(); - } - - private void notExpectedFormatDialog() { - - AlertDialog.Builder adb = new AlertDialog.Builder(this); - - switch (currentScanState) { - case public_key: - adb.setTitle("Public Key Expected"); - adb.setMessage("Please tell your Sync Partner to go back to the Public Key exchange"); - break; - - case information: - adb.setTitle("Sync Information Expected"); - adb.setMessage("Please tell your Sync Partner to proceed to the Sync Information exchange"); - break; - } - - adb.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - cameraFragment.setReadQrEnabled(true); - } - }); - - } - - private void circularReveal(final View v, final boolean open, final long duration, final long startDelay) { - - v.post(new Runnable() { - @Override - public void run() { - int cx = v.getWidth() / 2; - int cy = v.getHeight() / 2; - - float finalRadius = (float) Math.hypot(cx, cy); - - Animator anim; - - if (open) { - anim = ViewAnimationUtils.createCircularReveal(v, cx, cy, 0, finalRadius); - } else { - anim = ViewAnimationUtils.createCircularReveal(v, cx, cy, finalRadius, 0); - } - - anim.setInterpolator(new DecelerateInterpolator()); - anim.setDuration(duration); - - anim.addListener(new Animator.AnimatorListener() { - @Override - public void onAnimationStart(Animator animation) { - qrBackground.setVisibility(View.VISIBLE); - } - - @Override - public void onAnimationEnd(Animator animation) { - if (!open) { - qrBackground.setVisibility(View.INVISIBLE); - } - } - - @Override - public void onAnimationCancel(Animator animation) { - - } - - @Override - public void onAnimationRepeat(Animator animation) { - - } - }); - - anim.setStartDelay(startDelay); - - anim.start(); - - } - }); - - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java b/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java deleted file mode 100644 index 358801f..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/SyncUploadActivity.java +++ /dev/null @@ -1,470 +0,0 @@ -package de.overview.wg.its.mispbump; - -import android.support.design.widget.FloatingActionButton; -import android.support.v7.app.AppCompatActivity; -import android.os.Bundle; -import android.support.v7.widget.DefaultItemAnimator; -import android.support.v7.widget.LinearLayoutManager; -import android.support.v7.widget.RecyclerView; -import android.support.v7.widget.Toolbar; -import android.view.View; -import com.android.volley.VolleyError; -import com.google.gson.Gson; -import de.overview.wg.its.mispbump.adapter.UploadStateAdapter; -import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; -import de.overview.wg.its.mispbump.auxiliary.ReadableError; -import de.overview.wg.its.mispbump.auxiliary.TempAuth; -import de.overview.wg.its.mispbump.model.*; -import de.overview.wg.its.mispbump.network.MispRequest; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.List; - -public class SyncUploadActivity extends AppCompatActivity implements View.OnClickListener { - - static final String PARTNER_INFO_BUNDLE_KEY = "partner_info"; - - private FloatingActionButton fabStart, fabFinish, fabRetry; - - private MispRequest mispRequest; - - private Organisation partnerOrganisation; - private Server partnerServer; - private User partnerSyncUser; - - private UploadStateAdapter uploadStateAdapter; - private UploadState[] uploadStates; - private int currentTask = 0; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_upload); - - initializeContent(); - } - - @Override - public void onClick(View v) { - int id = v.getId(); - - if (id == R.id.fab_start) { - startUpload(); - fabStart.setVisibility(View.GONE); - } - - if (id == R.id.fab_retry) { - fabRetry.setVisibility(View.GONE); - fabFinish.setVisibility(View.GONE); - - //TODO retry implementation - } - - if (id == R.id.fab_finish) { - finish(); - } - } - - - private void initializeContent() { - - // Toolbar - - Toolbar toolbar = findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - - getSupportActionBar().setDisplayShowHomeEnabled(false); - getSupportActionBar().setDisplayHomeAsUpEnabled(false); - getSupportActionBar().setDisplayShowTitleEnabled(true); - - // FABs - - fabStart = findViewById(R.id.fab_start); - fabStart.setVisibility(View.VISIBLE); - fabStart.setOnClickListener(this); - - fabFinish = findViewById(R.id.fab_finish); - fabFinish.setVisibility(View.GONE); - fabFinish.setOnClickListener(this); - - fabRetry = findViewById(R.id.fab_retry); - fabRetry.setVisibility(View.GONE); - fabRetry.setOnClickListener(this); - - // RecyclerView - - RecyclerView recyclerView = findViewById(R.id.recyclerView); - uploadStateAdapter = new UploadStateAdapter(); - RecyclerView.LayoutManager mLayoutManager = new LinearLayoutManager(this); - recyclerView.setLayoutManager(mLayoutManager); - recyclerView.setItemAnimator(new DefaultItemAnimator()); - recyclerView.setAdapter(uploadStateAdapter); - - // UploadStates - - uploadStates = new UploadState[6]; - - uploadStates[0] = new UploadState("Validate upload information"); - uploadStates[1] = new UploadState("Check connection to server"); - uploadStates[2] = new UploadState("Create local organisation"); - uploadStates[3] = new UploadState("Create sync user / add to organisation"); - uploadStates[4] = new UploadState("Create external organisation"); - uploadStates[5] = new UploadState("Create sync server"); - - uploadStateAdapter.setStates(uploadStates); - - // Request - - mispRequest = MispRequest.Instance(this, true); - } - - private void startUpload() { - currentTask = 0; - executeTask(currentTask); - } - - private void undoTask(int index) { - switch (index) { - - case 2: - createOrganisation(uploadStates[index], true); - break; - - case 3: - createSyncUser(uploadStates[index], true); - break; - - case 4: - createExternalOrganisation(uploadStates[index], true); - break; - - case 5: - createSyncServer(uploadStates[index], true); - break; - - } - } - - private void executeTask(int index) { - - switch (index) { - case 0: - checkBundle(uploadStates[index]); - break; - - case 1: - checkConnection(uploadStates[index]); - break; - - case 2: - createOrganisation(uploadStates[index], false); - break; - - case 3: - createSyncUser(uploadStates[index], false); - break; - - case 4: - createExternalOrganisation(uploadStates[index], false); - break; - - case 5: - createSyncServer(uploadStates[index], false); - break; - - } - - uploadStateAdapter.notifyDataSetChanged(); - } - - private void executeNextTask() { - - currentTask++; - - if (currentTask > uploadStates.length) { - addToSyncedList(); - } - - executeTask(currentTask); - } - - private void setApplicationError(boolean canRetry) { - - setErrorOnRemainingTasks(); - - uploadStateAdapter.notifyDataSetChanged(); - - fabFinish.setVisibility(View.VISIBLE); - - if (canRetry) { - fabRetry.setVisibility(View.VISIBLE); - } - } - - private void setErrorOnRemainingTasks() { - - boolean errorFound = false; - - for(UploadState state : uploadStates) { - - if (!errorFound && state.getCurrentState() == UploadState.State.ERROR) { - errorFound = true; - continue; - } - - if (errorFound) { - state.setFollowError(); - } - } - } - - // Upload States - - private void checkBundle(UploadState state) { - state.setInProgress(); - - state.setDone(); - executeNextTask(); - - if(true) { - return; - } - - Bundle b = getIntent().getExtras(); - - if (b != null) { - - String info = b.getString(PARTNER_INFO_BUNDLE_KEY); - - SyncInformationQr partnerInformation = new Gson().fromJson(info, SyncInformationQr.class); - - partnerOrganisation = partnerInformation.getOrganisation(); - partnerServer = partnerInformation.getServer(); - partnerSyncUser = partnerInformation.getUser(); - - if (partnerOrganisation == null || partnerServer == null || partnerSyncUser == null) { - state.setError("Partners information format is incorrect"); - setApplicationError(false); - } else { - state.setDone(); - executeNextTask(); - } - - } else { - state.setError("Partners information format is incorrect"); - setApplicationError(false); - } - } - - private void checkConnection(final UploadState state) { - state.setInProgress(); - state.setDone(); - executeNextTask(); - - if(true) { - return; - } - - mispRequest.testConnection(new MispRequest.ConnectionCallback() { - @Override - public void onResult(boolean connected) { - if (connected) { - state.setDone(); - executeNextTask(); - } else { - state.setError("Could not connect to server"); - setApplicationError(true); - } - } - }); - } - - private void createOrganisation(final UploadState state, boolean undo) { - - state.setInProgress(); - state.setDone(); - executeNextTask(); - - if (true) { - return; - } - - if (!undo) { - mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() { - @Override - public void onResult(JSONObject organisationInformation) { - try { - - partnerSyncUser.setOrgId(new Organisation(organisationInformation).getId()); - - state.setDone(); - executeNextTask(); - - } catch (JSONException e) { - state.setError("Unknown error: could not read server response"); - e.printStackTrace(); - } - - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - setApplicationError(true); - } - }); - } else { - mispRequest.removeOrganisation(partnerOrganisation.getId(), new MispRequest.DeleteCallback() { - @Override - public void onSuccess() { - state.setDone(); - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - } - }); - } - } - - private void createSyncUser(final UploadState state, boolean undo) { - - state.setInProgress(); - state.setDone(); - executeNextTask(); - if (true) { - return; - } - - partnerSyncUser.setAuthkey(TempAuth.TMP_AUTH_KEY); - partnerSyncUser.setRoleId(User.RoleId.SYNC_USER); - - if (!undo) { - mispRequest.addUser(partnerSyncUser, new MispRequest.UserCallback() { - @Override - public void onResult(JSONObject myUserInformation) { - state.setDone(); - executeNextTask(); - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - setApplicationError(true); - } - }); - } else { - mispRequest.removeUser(partnerSyncUser.getId(), new MispRequest.DeleteCallback() { - @Override - public void onSuccess() { - state.setDone(); - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - } - }); - } - } - - private void createExternalOrganisation(final UploadState state, boolean undo) { - - - state.setInProgress(); - -// executeNextTask(); - if (true) { - return; - } - - final String originalOrgName = partnerOrganisation.getName(); - - if (!undo) { - partnerOrganisation.setName(partnerOrganisation.getName() + " (Remote)"); - partnerOrganisation.setLocal(false); - - mispRequest.addOrganisation(partnerOrganisation, new MispRequest.OrganisationCallback() { - - @Override - public void onResult(JSONObject organisationInformation) { - try { - - int extOrgId = new Organisation(organisationInformation).getId(); - partnerServer.setRemoteOrgId(extOrgId); - partnerServer.setPush(true); - - // Reset partner organisation name because it will show as (remote) name in syncedList - partnerOrganisation.setName(originalOrgName); - - state.setDone(); - executeNextTask(); - - } catch (JSONException e) { - state.setError("Could not interpret server response"); - } - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - setApplicationError(true); - } - }); - } else { - mispRequest.removeOrganisation(partnerOrganisation.getId(), new MispRequest.DeleteCallback() { - @Override - public void onSuccess() { - state.setDone(); - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - } - }); - } - } - - private void createSyncServer(final UploadState state, boolean undo) { - state.setInProgress(); - - if (true) { - return; - } - - if (!undo) { - mispRequest.addServer(partnerServer, new MispRequest.ServerCallback() { - @Override - public void onResult(JSONObject servers) { - state.setDone(); - executeNextTask(); - } - - @Override - public void onError(VolleyError volleyError) { - state.setError(ReadableError.toReadable(volleyError)); - } - }); - } - } - - private void addToSyncedList() { - - if(true) { - return; - } - - PreferenceManager preferenceManager = PreferenceManager.Instance(this); - - List syncedPartnerList = preferenceManager.getSyncedPartnerList(); - - SyncedPartner sp = new SyncedPartner(partnerOrganisation.getName(), partnerServer.getUrl()); - sp.generateTimeStamp(); - - syncedPartnerList.add(sp); - preferenceManager.setSyncedPartnerList(syncedPartnerList); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java deleted file mode 100644 index 58c81c5..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/adapter/OrganisationInfoEntryAdapter.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.overview.wg.its.mispbump.adapter; - -import android.content.ClipData; -import android.content.ClipboardManager; -import android.content.Context; -import android.support.annotation.NonNull; -import android.support.design.widget.Snackbar; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import android.widget.Toast; -import de.overview.wg.its.mispbump.model.StringPair; -import de.overview.wg.its.mispbump.R; - -import java.util.ArrayList; -import java.util.List; - -public class OrganisationInfoEntryAdapter extends RecyclerView.Adapter { - - private Context context; - private List list = new ArrayList<>(); - - class MyViewHolder extends RecyclerView.ViewHolder { - - View container; - TextView title, value; - - private MyViewHolder(View view) { - super(view); - - this.title = view.findViewById(R.id.title); - this.value = view.findViewById(R.id.value); - this.container = view.findViewById(R.id.container); - } - } - - public OrganisationInfoEntryAdapter(Context context) { - this.context = context; - } - - @NonNull - @Override - public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View row = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_org_info_entry, parent, false); - return new OrganisationInfoEntryAdapter.MyViewHolder(row); - } - - @Override - public void onBindViewHolder(@NonNull MyViewHolder holder, final int position) { - holder.title.setText(list.get(position).key); - holder.value.setText(list.get(position).value); - - holder.container.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - ClipData data = ClipData.newPlainText(list.get(position).key, list.get(position).value); - ClipboardManager m = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE); - m.setPrimaryClip(data); - - Toast.makeText(context, context.getText(R.string.copied_to_clipboard), Toast.LENGTH_SHORT).show(); - } - }); - } - - @Override - public int getItemCount() { - return list.size(); - } - - public void setList(List list) { - this.list = list; - notifyDataSetChanged(); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java deleted file mode 100644 index 47661cf..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/adapter/SyncedPartnerAdapter.java +++ /dev/null @@ -1,92 +0,0 @@ -package de.overview.wg.its.mispbump.adapter; - -import android.app.AlertDialog; -import android.content.Context; -import android.content.DialogInterface; -import android.content.Intent; -import android.net.Uri; -import android.support.annotation.NonNull; -import android.support.v7.widget.CardView; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.TextView; -import de.overview.wg.its.mispbump.R; -import de.overview.wg.its.mispbump.model.SyncedPartner; - -import java.util.List; - -public class SyncedPartnerAdapter extends RecyclerView.Adapter { - - private List syncedPartnerList; - private Context context; - - class MyViewHolder extends RecyclerView.ViewHolder { - - CardView cardView; - TextView title, dateAdded, url; - - MyViewHolder(View view) { - super(view); - - cardView = view.findViewById(R.id.card_synced_org); - title = view.findViewById(R.id.title); - dateAdded = view.findViewById(R.id.dateSynced); - url = view.findViewById(R.id.url); - } - } - - public SyncedPartnerAdapter(Context context, List syncedPartnerList) { - this.syncedPartnerList = syncedPartnerList; - this.context = context; - } - - public void setSyncedPartnerList(List syncedPartnerList) { - this.syncedPartnerList = syncedPartnerList; - notifyDataSetChanged(); - } - - @NonNull - @Override - public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_synced_organisation, parent, false); - return new MyViewHolder(itemView); - } - - @Override - public void onBindViewHolder(@NonNull final MyViewHolder holder, int position) { - final SyncedPartner syncedPartner = syncedPartnerList.get(position); - - holder.title.setText(syncedPartner.getName()); - holder.url.setText(syncedPartner.getUrl()); - holder.dateAdded.setText(syncedPartner.getSyncDate()); - - holder.cardView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - - AlertDialog.Builder adb = new AlertDialog.Builder(context); - - adb.setTitle(context.getString(R.string.dialog_open_browser_title)); - adb.setMessage(context.getString(R.string.dialog_open_in_browser_msg, syncedPartner.getUrl())); - - adb.setPositiveButton(context.getString(R.string.open), new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse(syncedPartner.getUrl())); - context.startActivity(browser); - } - }); - - adb.setNegativeButton(context.getString(android.R.string.cancel), null); - adb.create().show(); - } - }); - } - - @Override - public int getItemCount() { - return syncedPartnerList.size(); - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java b/app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java deleted file mode 100644 index 9400d77..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/adapter/UploadStateAdapter.java +++ /dev/null @@ -1,102 +0,0 @@ -package de.overview.wg.its.mispbump.adapter; - -import android.support.annotation.NonNull; -import android.support.v7.widget.RecyclerView; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.ImageView; -import android.widget.ProgressBar; -import android.widget.TextView; -import de.overview.wg.its.mispbump.R; -import de.overview.wg.its.mispbump.model.UploadState; - -import java.util.ArrayList; -import java.util.List; - -public class UploadStateAdapter extends RecyclerView.Adapter { - - private UploadState[] states; - - class MyViewHolder extends RecyclerView.ViewHolder { - - private TextView title, error; - private ImageView pendingIcon, errorIcon, doneIcon; - private ProgressBar progressBar; - - private MyViewHolder(View view) { - - super(view); - - title = view.findViewById(R.id.title); - error = view.findViewById(R.id.state_error_text); - - pendingIcon = view.findViewById(R.id.state_pending); - errorIcon = view.findViewById(R.id.state_error); - doneIcon = view.findViewById(R.id.state_done); - progressBar = view.findViewById(R.id.state_in_progress); - - } - - private void setState(UploadState.State state) { - - error.setVisibility(View.GONE); - errorIcon.setVisibility(View.GONE); - pendingIcon.setVisibility(View.GONE); - doneIcon.setVisibility(View.GONE); - progressBar.setVisibility(View.GONE); - - switch (state) { - case PENDING: - pendingIcon.setVisibility(View.VISIBLE); - break; - - case IN_PROGRESS: - progressBar.setVisibility(View.VISIBLE); - break; - - case DONE: - doneIcon.setVisibility(View.VISIBLE); - break; - - case ERROR: - errorIcon.setVisibility(View.VISIBLE); - error.setVisibility(View.VISIBLE); - break; - - case FOLLOW_ERROR: - errorIcon.setVisibility(View.VISIBLE); - break; - } - } - } - - public void setStates(UploadState[] states) { - this.states = states; - notifyDataSetChanged(); - } - - @NonNull - @Override - public UploadStateAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - - View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.row_upload_state, parent, false); - return new UploadStateAdapter.MyViewHolder(itemView); - - } - - @Override - public void onBindViewHolder(@NonNull UploadStateAdapter.MyViewHolder holder, int position) { - UploadState state = states[position]; - - holder.title.setText(state.getTitle()); - holder.error.setText(state.getErrorMessage()); - holder.setState(states[position].getCurrentState()); - } - - @Override - public int getItemCount() { - return states.length; - } - -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java deleted file mode 100644 index a50d8db..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/AESSecurity.java +++ /dev/null @@ -1,157 +0,0 @@ -package de.overview.wg.its.mispbump.auxiliary; - -import android.util.Base64; -import android.util.Log; - -import javax.crypto.*; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.SecretKeySpec; -import java.security.*; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; -import java.util.Arrays; - -public class AESSecurity { - - private static final String TAG = "MISP_LOGGING"; - - private static final String ENCRYPT_ALGORITHM = "AES/CBC/PKCS5Padding"; - private static final String KEY_PAIR_ALGORITHM = "EC"; - private static final int KEY_SIZE = 521; // 224 | 256 | 384 | 521 - private static final String KEY_AGREEMENT_ALGORITHM = "ECDH"; - - private static AESSecurity instance; - - private PublicKey publickey; - private KeyAgreement keyAgreement; - - private byte[] sharedSecret; - private IvParameterSpec ivParameterSpec; - - private AESSecurity() { - initialize(); - } - - /*** - * Generates a public and a private key using an elliptic curve algorithm (256 bit) - * The private key is fed into the key agreement instance - */ - private void initialize() { - - try { - KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM); - kpg.initialize(KEY_SIZE); - - KeyPair kp = kpg.generateKeyPair(); - publickey = kp.getPublic(); - - keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM); - keyAgreement.init(kp.getPrivate()); - - } catch (NoSuchAlgorithmException | InvalidKeyException e) { - e.printStackTrace(); - } - } - - /*** - * Generates a shared secret with a given public key - * @param publickey - */ - public void setForeignPublicKey(PublicKey publickey) { - - try { - - keyAgreement.doPhase(publickey, true); - - byte[] tmpSharedSecret = keyAgreement.generateSecret(); - - sharedSecret = Arrays.copyOfRange(tmpSharedSecret, 0, 32); - - byte[] inputVector = Arrays.copyOfRange(sharedSecret, 32, 48); - - ivParameterSpec = new IvParameterSpec(inputVector); - - } catch (InvalidKeyException e) { - e.printStackTrace(); - } - } - - public String encrypt(String data) { - try { - - Key key = generateKey(); - Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM); - - try { - c.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - } - - byte[] encVal = c.doFinal(data.getBytes()); - return Base64.encodeToString(encVal, 0); - - } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return data; - } - - public String decrypt(String data) { - try { - Key key = generateKey(); - - Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM); - - try { - c.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); - } catch (InvalidAlgorithmParameterException e) { - e.printStackTrace(); - } - - byte[] decoded = Base64.decode(data, 0); - byte[] decValue = c.doFinal(decoded); - return new String(decValue); - } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) { - e.printStackTrace(); - } - return data; - } - - public PublicKey getPublicKey() { - return publickey; - } - - private Key generateKey() { - - return new SecretKeySpec(sharedSecret, ENCRYPT_ALGORITHM); - - } - - public static String publicKeyToString(PublicKey key) { - return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT); - } - - public static PublicKey publicKeyFromString(String key) { - - try { - - byte[] input = Base64.decode(key, Base64.DEFAULT); - return KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(input)); - - } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { - e.printStackTrace(); - } - - return null; - } - - public static AESSecurity getInstance() { - - if(instance == null) { - instance = new AESSecurity(); - } - - return instance; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java deleted file mode 100644 index 009f838..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/PreferenceManager.java +++ /dev/null @@ -1,142 +0,0 @@ -package de.overview.wg.its.mispbump.auxiliary; - -import android.content.Context; -import android.content.SharedPreferences; -import com.google.gson.Gson; -import com.google.gson.reflect.TypeToken; -import de.overview.wg.its.mispbump.model.Organisation; -import de.overview.wg.its.mispbump.model.SyncedPartner; -import de.overview.wg.its.mispbump.model.User; -import org.json.JSONException; -import org.json.JSONObject; - -import java.lang.reflect.Type; -import java.util.List; - -public class PreferenceManager { - - private static PreferenceManager instance; - - private SharedPreferences userPreferences; - private SharedPreferences credentialPreferences; - private SharedPreferences syncedInstancesPreferences; - - private static final String CREDENTIAL_PREFERENCE = "de.overview.wg.its.mispauth.credential_preference"; - private static final String SAVED_INSTANCES_PREFERENCE = "de.overview.wg.its.mispauth.saved_instances_preference"; - private static final String USER_PREFERENCE = "de.overview.wg.its.mispauth.user_preferences"; - - private static String PREF_KEY_SERVER_URL = "key_server_url"; - private static String PREF_KEY_SERVER_API_KEY = "key_server_api_key"; - private static String PREF_KEY_MY_ORGANISATION = "key_my_organisation"; - private static String PREF_KEY_MY_USER = "key_my_user"; - private static String PREF_KEY_SAVE_AUTHKEY_ENABLED = "key_save_authkey_enabled"; - private static String PREF_KEY_SYNCED_ORGANISATIONS = "key_synced_organisations"; - - private PreferenceManager(Context context) { - credentialPreferences = context.getSharedPreferences(CREDENTIAL_PREFERENCE, Context.MODE_PRIVATE); - syncedInstancesPreferences = context.getSharedPreferences(SAVED_INSTANCES_PREFERENCE, Context.MODE_PRIVATE); - userPreferences = context.getSharedPreferences(USER_PREFERENCE, Context.MODE_PRIVATE); - } - - public List getSyncedPartnerList() { - String list = syncedInstancesPreferences.getString(PREF_KEY_SYNCED_ORGANISATIONS, ""); - Type type = new TypeToken>() {}.getType(); - return new Gson().fromJson(list, type); - } - public void setSyncedPartnerList(List syncedPartnerList) { - String json = new Gson().toJson(syncedPartnerList); - SharedPreferences.Editor editor = syncedInstancesPreferences.edit(); - editor.putString(PREF_KEY_SYNCED_ORGANISATIONS, json); - editor.apply(); - } - - public boolean saveAuthKeyEnabledExists() { - return userPreferences.contains(PREF_KEY_SAVE_AUTHKEY_ENABLED); - } - public boolean saveAuthKeyEnabled() { - return userPreferences.getBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, false); - } - public void setSaveAuthKeyEnabled(boolean save) { - SharedPreferences.Editor editor = userPreferences.edit(); - editor.putBoolean(PREF_KEY_SAVE_AUTHKEY_ENABLED, save); - editor.apply(); - } - - /** - * @return own Organisation if available, else null - */ - public Organisation getMyOrganisation() { - try { - JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_ORGANISATION, "")); - Organisation org = new Organisation(); - org.fromJSON(jsonObject); - return org; - } catch (JSONException e) { - e.printStackTrace(); - } - - return null; - } - public void setMyOrganisation(Organisation org) { - SharedPreferences.Editor editor = credentialPreferences.edit(); - editor.putString(PREF_KEY_MY_ORGANISATION, org.toJSON().toString()); - editor.apply(); - } - - public User getMyUser() { - try { - JSONObject jsonObject = new JSONObject(credentialPreferences.getString(PREF_KEY_MY_USER, "")); - User user = new User(); - user.fromJSON(jsonObject); - return user; - } catch (JSONException e) { - e.printStackTrace(); - } - - return null; - } - public void setMyUser(User user) { - SharedPreferences.Editor editor = credentialPreferences.edit(); - editor.putString(PREF_KEY_MY_USER, user.toJSON().toString()); - editor.apply(); - } - - public String getMyServerUrl() { - return credentialPreferences.getString(PREF_KEY_SERVER_URL, ""); - } - public void setServerUrl(String serverUrl) { - SharedPreferences.Editor editor = credentialPreferences.edit(); - editor.putString(PREF_KEY_SERVER_URL, serverUrl); - editor.apply(); - } - - public String getMyServerAutomationKey() { - return credentialPreferences.getString(PREF_KEY_SERVER_API_KEY, ""); - } - public void setAutomationKey(String apiKey) { - SharedPreferences.Editor editor = credentialPreferences.edit(); - editor.putString(PREF_KEY_SERVER_API_KEY, apiKey); - editor.apply(); - } - - - public void clearUserPreferences() { - userPreferences.edit().clear().apply(); - } - public void clearCredentialPreferences() { - credentialPreferences.edit().clear().apply(); - } - public void clearSyncedInformationPreferences() { - syncedInstancesPreferences.edit().clear().apply(); - } - - - public static PreferenceManager Instance(Context context) { - if(instance == null) { - instance = new PreferenceManager(context); - } - - return instance; - } -} - diff --git a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java deleted file mode 100644 index 0cac2c8..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/RandomString.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.overview.wg.its.mispbump.auxiliary; - -import java.security.SecureRandom; -import java.util.Locale; -import java.util.Objects; -import java.util.Random; - -public class RandomString { - - @SuppressWarnings("SpellCheckingInspection") - private static final String upper = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - private static final String lower = upper.toLowerCase(Locale.ROOT); - private static final String digits = "0123456789"; - private static final String alphaNum = upper + lower + digits; - - private final Random random; - private final char[] symbols; - private final char[] buf; - - private RandomString(int length, Random random, String symbols) { - - if (length < 1) { - throw new IllegalArgumentException(); - } - if (symbols.length() < 2) { - throw new IllegalArgumentException(); - } - - this.random = Objects.requireNonNull(random); - this.symbols = symbols.toCharArray(); - this.buf = new char[length]; - - } - private RandomString(int length, Random random) { - this(length, random, alphaNum); - } - public RandomString(int length) { - this(length, new SecureRandom()); - } - - public String nextString() { - - for (int idx = 0; idx < buf.length; ++idx) { - buf[idx] = symbols[random.nextInt(symbols.length)]; - } - - return new String(buf); - } - -} \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java deleted file mode 100644 index 722bde3..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/ReadableError.java +++ /dev/null @@ -1,49 +0,0 @@ -package de.overview.wg.its.mispbump.auxiliary; - -import com.android.volley.*; -import org.json.JSONException; -import org.json.JSONObject; - -import java.nio.charset.StandardCharsets; - -public class ReadableError { - - public static String toReadable(VolleyError volleyError) { - - if (volleyError.networkResponse != null) { - try { - JSONObject response = new JSONObject(new String(volleyError.networkResponse.data, StandardCharsets.UTF_8)); - JSONObject error = response.getJSONObject("errors"); - - String name = response.getString("name"); - String errorName = error.getJSONArray("name").get(0).toString(); - - if (!errorName.equals("")) { - return errorName; - } else if (!name.equals("")) { - return name; - } - - } catch (JSONException e) { - e.printStackTrace(); - } - } - - if (volleyError instanceof NoConnectionError) { - return "Connection failed"; - } else if (volleyError instanceof TimeoutError) { - return "Connection timed out"; - } else if (volleyError instanceof NetworkError) { - return "Network error"; - } else if (volleyError instanceof AuthFailureError) { - return "Authentication failed"; - } else if (volleyError instanceof ServerError) { - return "Server error"; - } else if (volleyError instanceof ParseError) { - return "Parsing error"; - } - - return volleyError.toString(); - } - -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java b/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java deleted file mode 100644 index db88858..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/auxiliary/TempAuth.java +++ /dev/null @@ -1,7 +0,0 @@ -package de.overview.wg.its.mispbump.auxiliary; - -public class TempAuth { - - public static String TMP_AUTH_KEY; - -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java b/app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java deleted file mode 100644 index 75960cd..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/cam/AutoFitTextureView.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.overview.wg.its.mispbump.cam; - -/* - * Copyright 2014 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -import android.content.Context; -import android.util.AttributeSet; -import android.view.TextureView; - -/** - * A {@link TextureView} that can be adjusted to a specified aspect ratio. - */ -public class AutoFitTextureView extends TextureView { - - private int mRatioWidth = 0; - private int mRatioHeight = 0; - - public AutoFitTextureView(Context context) { - this(context, null); - } - - public AutoFitTextureView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - } - - /** - * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio - * calculated from the parameters. Note that the actual sizes of parameters don't matter, that - * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result. - * - * @param width Relative horizontal size - * @param height Relative vertical size - */ - public void setAspectRatio(int width, int height) { - if (width < 0 || height < 0) { - throw new IllegalArgumentException("Size cannot be negative."); - } - mRatioWidth = width; - mRatioHeight = height; - requestLayout(); - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - int width = MeasureSpec.getSize(widthMeasureSpec); - int height = MeasureSpec.getSize(heightMeasureSpec); - if (0 == mRatioWidth || 0 == mRatioHeight) { - setMeasuredDimension(width, height); - } else { - if (width < height * mRatioWidth / mRatioHeight) { - setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); - } else { - setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); - } - } - } - -} \ No newline at end of file diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java b/app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java deleted file mode 100644 index 2b68655..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/Organisation.java +++ /dev/null @@ -1,193 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import org.json.JSONException; -import org.json.JSONObject; - -public class Organisation { - - public static final String ROOT_KEY = "Organisation"; - - private static String ID_KEY = "id"; - private static String NAME_KEY = "name"; - private static String DATE_CREATED_KEY = "date_created"; - private static String DATE_MODIFIED_KEY = "date_modified"; - private static String TYPE_KEY = "type"; - private static String NATIONALITY_KEY = "nationality"; - private static String SECTOR_KEY = "sector"; - private static String CONTACTS_KEY = "contacts"; - private static String DESCRIPTION_KEY = "description"; - private static String LOCAL_KEY = "local"; - private static String UUID_KEY = "uuid"; - private static String RESTRICTED_TO_DOMAIN_KEY = "restricted_to_domain"; - private static String CREATED_BY_KEY = "created_by"; - private static String USER_COUNT_KEY = "user_count"; - - private int id; - private String name; - private String dateCreated, dateModified; - private String type; - private String nationality; - private String sector; - private String contacts; - private String description; - private boolean local; - private String uuid; - private String restrictedToDomain; - private int createdBy; - private int userCount; - - public Organisation() {} - - public Organisation(JSONObject json) throws JSONException { - fromJSON(json); - } - public void fromJSON(JSONObject org) throws JSONException { - - id = org.optInt(ID_KEY, -1); - dateCreated = org.optString(DATE_CREATED_KEY); - dateModified = org.optString(DATE_MODIFIED_KEY); - name = org.optString(NAME_KEY); - type = org.optString(TYPE_KEY); - nationality = org.optString(NATIONALITY_KEY); - sector = org.optString(SECTOR_KEY); - contacts = org.optString(CONTACTS_KEY); - description = org.optString(DESCRIPTION_KEY); - local = org.optBoolean(LOCAL_KEY, true); - uuid = org.optString(UUID_KEY); - restrictedToDomain = org.optString(RESTRICTED_TO_DOMAIN_KEY); - createdBy = org.optInt(CREATED_BY_KEY, -1); - userCount = org.optInt(USER_COUNT_KEY); - - } - - public JSONObject toJSON() { - return toJSON(false); - } - public JSONObject toJSON(boolean minimal) { - JSONObject org = new JSONObject(); - - try { - org.putOpt(NAME_KEY, name); - org.putOpt(DESCRIPTION_KEY, description); - org.putOpt(NATIONALITY_KEY, nationality); - org.putOpt(SECTOR_KEY, sector); - org.putOpt(USER_COUNT_KEY, userCount); - - if (!minimal) { - org.putOpt(ID_KEY, id); - org.putOpt(UUID_KEY, uuid); - org.putOpt(TYPE_KEY, type); - org.putOpt(CONTACTS_KEY, contacts); - org.putOpt(DATE_CREATED_KEY, dateCreated); - org.putOpt(DATE_MODIFIED_KEY, dateModified); - org.putOpt(LOCAL_KEY, local); - org.putOpt(RESTRICTED_TO_DOMAIN_KEY, restrictedToDomain); - org.putOpt(CREATED_BY_KEY, createdBy); - } - - } catch (JSONException e) { - e.printStackTrace(); - } - - return org; - } - - - public void setName(String name) { - this.name = name; - } - public String getName() { - return name; - } - - public String getDescription() { - return description; - } - public void setDescription(String description) { - this.description = description; - } - - public String getSector() { - return sector; - } - public void setSector(String sector) { - this.sector = sector; - } - - public String getNationality() { - return nationality; - } - public void setNationality(String nationality) { - this.nationality = nationality; - } - - public int getId() { - return id; - } - public void setId(int id) { - this.id = id; - } - - public String getDateCreated() { - return dateCreated; - } - public void setDateCreated(String dateCreated) { - this.dateCreated = dateCreated; - } - - public String getDateModified() { - return dateModified; - } - public void setDateModified(String dateModified) { - this.dateModified = dateModified; - } - - public String getType() { - return type; - } - public void setType(String type) { - this.type = type; - } - - public String getContacts() { - return contacts; - } - public void setContacts(String contacts) { - this.contacts = contacts; - } - - public boolean isLocal() { - return local; - } - public void setLocal(boolean local) { - this.local = local; - } - - public String getUuid() { - return uuid; - } - public void setUuid(String uuid) { - this.uuid = uuid; - } - - public String getRestrictedToDomain() { - return restrictedToDomain; - } - public void setRestrictedToDomain(String restrictedToDomain) { - this.restrictedToDomain = restrictedToDomain; - } - - public int getCreatedBy() { - return createdBy; - } - public void setCreatedBy(int createdBy) { - this.createdBy = createdBy; - } - - public int getUserCount() { - return userCount; - } - public void setUserCount(int userCount) { - this.userCount = userCount; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java b/app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java deleted file mode 100644 index 50a1602..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/PublicKeyQr.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import org.json.JSONException; -import org.json.JSONObject; - -public class PublicKeyQr { - - private static final String KEY_ORG = "org"; - private static final String KEY_EMAIL = "email"; - private static final String KEY_KEY = "key"; - - private String organisation, email, key; - - public PublicKeyQr(JSONObject qr) throws JSONException { - organisation = qr.getString(KEY_ORG); - email = qr.getString(KEY_EMAIL); - key = qr.getString(KEY_KEY); - } - public PublicKeyQr(String qr) throws JSONException { - JSONObject json = new JSONObject(qr); - - organisation = json.getString(KEY_ORG); - email = json.getString(KEY_EMAIL); - key = json.getString(KEY_KEY); - } - public PublicKeyQr(String organisation, String email, String key) { - this.organisation = organisation; - this.email = email; - this.key = key; - } - - public JSONObject toJSON() { - try { - JSONObject json = new JSONObject(); - - json.put(KEY_ORG, organisation); - json.put(KEY_EMAIL, email); - json.put(KEY_KEY, key); - - return json; - - } catch (JSONException e) { - - return null; - } - } - - public String getOrganisation() { - return organisation; - } - public String getEmail() { - return email; - } - public String getKey() { - return key; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/Server.java b/app/src/main/java/de/overview/wg/its/mispbump/model/Server.java deleted file mode 100644 index dd03b8a..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/Server.java +++ /dev/null @@ -1,105 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import org.json.JSONException; -import org.json.JSONObject; - -public class Server { - - public static final String ROOT_KEY = "Server"; - - private static final String URL_KEY = "url"; - private static final String NAME_KEY = "name"; - private static final String REMOTE_ORG_ID_KEY = "remote_org_id"; - private static final String AUTHKEY_KEY = "authkey"; - private static final String PUSH_KEY = "push"; - private static final String PULL_KEY = "pull"; - - private String url; - private String name; - private int remoteOrgId; - private String authkey; - private boolean push, pull; - - public Server() { } - public Server(JSONObject json) throws JSONException { - fromJSON(json); - } - - public void fromJSON(JSONObject server) throws JSONException { - url = server.optString(URL_KEY); - name = server.optString(NAME_KEY); - remoteOrgId = server.optInt(REMOTE_ORG_ID_KEY, -1); - authkey = server.optString(AUTHKEY_KEY); - push = server.optBoolean(PUSH_KEY, false); - pull = server.optBoolean(PULL_KEY, false); - } - - public JSONObject toJSON() { - return toJSON(false); - } - public JSONObject toJSON(boolean minimal) { - - JSONObject jsonObject = new JSONObject(); - - try { - jsonObject.putOpt(URL_KEY, url); - jsonObject.putOpt(NAME_KEY, name); - jsonObject.putOpt(AUTHKEY_KEY, authkey); - - if (!minimal) { - jsonObject.putOpt(REMOTE_ORG_ID_KEY, remoteOrgId); - jsonObject.putOpt(PUSH_KEY, push); - jsonObject.putOpt(PULL_KEY, pull); - } - - } catch (JSONException e) { - e.printStackTrace(); - } - - return jsonObject; - } - - - public String getUrl() { - return url; - } - public void setUrl(String url) { - this.url = url; - } - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - - public int getRemoteOrgId() { - return remoteOrgId; - } - public void setRemoteOrgId(int remoteOrgId) { - this.remoteOrgId = remoteOrgId; - } - - public String getAuthkey() { - return authkey; - } - public void setAuthkey(String authkey) { - this.authkey = authkey; - } - - public boolean isPush() { - return push; - } - public void setPush(boolean push) { - this.push = push; - } - - public boolean isPull() { - return pull; - } - public void setPull(boolean pull) { - this.pull = pull; - } - -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java b/app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java deleted file mode 100644 index 5e24034..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/StringPair.java +++ /dev/null @@ -1,11 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -public class StringPair { - - public String key, value; - - public StringPair(String key, String value) { - this.key = key; - this.value = value; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java deleted file mode 100644 index 6d19675..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/SyncInformationQr.java +++ /dev/null @@ -1,50 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import org.json.JSONArray; -import org.json.JSONException; - -public class SyncInformationQr { - - private Organisation organisation; - private Server server; - private User user; - - public SyncInformationQr(Organisation organisation, Server server, User user) { - this.organisation = organisation; - this.server = server; - this.user = user; - } - public SyncInformationQr(String stringArray) throws JSONException { - fromJSON(new JSONArray(stringArray)); - } - - private void fromJSON(JSONArray array) throws JSONException { - int length = array.length(); - - if (length == 3) { - organisation = new Organisation(array.getJSONObject(0)); - server = new Server(array.getJSONObject(1)); - user = new User(array.getJSONObject(2)); - } - } - - public JSONArray toJSON() { - JSONArray array = new JSONArray(); - - array.put(organisation.toJSON(true)); - array.put(server.toJSON(true)); - array.put(user.toJSON(true)); - - return array; - } - - public Organisation getOrganisation() { - return organisation; - } - public Server getServer() { - return server; - } - public User getUser() { - return user; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java b/app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java deleted file mode 100644 index 261b6fa..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/SyncedPartner.java +++ /dev/null @@ -1,48 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import android.annotation.SuppressLint; - -import java.sql.Timestamp; -import java.text.SimpleDateFormat; - -public class SyncedPartner { - - @SuppressLint("SimpleDateFormat") - private static final SimpleDateFormat dateFormat = new SimpleDateFormat("dd.MM.yyyy"); - - private String name; - private String url; - private String syncDate; - - public SyncedPartner(String name, String url) { - this.name = name; - this.url = url; - } - - public void generateTimeStamp() { - syncDate = dateFormat.format(new Timestamp(System.currentTimeMillis())); - } - - // GETTER & SETTER - - public String getName() { - return name; - } - public void setName(String name) { - this.name = name; - } - - public String getUrl() { - return url; - } - public void setUrl(String url) { - this.url = url; - } - - public String getSyncDate() { - return syncDate; - } - public void setSyncDate(String syncDate) { - this.syncDate = syncDate; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java b/app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java deleted file mode 100644 index 3538e27..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/UploadState.java +++ /dev/null @@ -1,57 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -public class UploadState { - - public enum State { - PENDING, - IN_PROGRESS, - DONE, - ERROR, - FOLLOW_ERROR - } - private State currentState = State.PENDING; - private String title, error; - - - public UploadState(String title) { - this.title = title; - } - - public String getTitle() { - return title; - } - - public void setTitle(String title) { - this.title = title; - } - - public String getErrorMessage() { - return error; - } - - public void setError(String error) { - this.error = error; - this.currentState = State.ERROR; - } - - public void setDone() { - this.currentState = State.DONE; - } - - public void setInProgress() { - this.currentState = State.IN_PROGRESS; - } - - public void setPending() { - this.currentState = State.PENDING; - } - - public void setFollowError () { - this.currentState = State.FOLLOW_ERROR; - } - - public State getCurrentState() { - return currentState; - } - -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/model/User.java b/app/src/main/java/de/overview/wg/its/mispbump/model/User.java deleted file mode 100644 index 44b23fe..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/model/User.java +++ /dev/null @@ -1,301 +0,0 @@ -package de.overview.wg.its.mispbump.model; - -import org.json.JSONException; -import org.json.JSONObject; - -public class User { - - // todo: must be configable? Roles can be edited on instance - public interface RoleId { - int ADMIN = 1; - int ORG_ADMIN = 2; - int USER = 3; - int PUBLISHER = 4; - int SYNC_USER = 5; - int READ_ONLY = 6; - } - - public static final String ROOT_KEY = "User"; - - private static String ID_KEY = "id"; - private static String PASSWORD_KEY = "password"; - private static String ORG_ID_KEY = "org_id"; - private static String EMAIL_KEY = "email"; - private static String AUTOALERT_KEY = "autoalert"; - private static String AUTHKEY_KEY = "authkey"; - private static String INVITED_BY_KEY = "invited_by"; - private static String GPGKEY_KEY = "gpgkey"; - private static String CERTIF_PUBLIC = "certif_public"; - private static String NIDS_SID = "nids_sid"; - private static String TERMS_ACCEPTED_KEY = "termsaccepted"; - private static String NEWSREAD_KEY = "newsread"; - private static String ROLE_ID_KEY = "role_id"; - private static String CHANGE_PW_KEY = "change_pw"; - private static String CONTACT_ALERT_KEY = "contactalert"; - private static String DISABLED_KEY = "disabled"; - private static String EXPIRATION_KEY = "expiration"; - private static String CURRENT_LOGIN_KEY = "current_login"; - private static String LAST_LOGIN_KEY = "last_login"; - private static String FORCE_LOGOUT_KEY = "force_logout"; - private static String DATE_CREATED_KEY = "date_created"; - private static String DATE_MODIFIED_KEY = "date_modified"; - - private int id; - private String password; - private int orgId; - private String email; - private boolean autoAlert; - private String authkey; - private int invitedBy; - private String gpgKey; - private String certifPublic; - private int nidsSid; - private boolean termsAccepted; - private int newsRead; // Integer?? - private int roleId; - private String changePw; - private boolean contactAlert; - private boolean disabled; - private String expiration; - private String currentLogin; - private String lastLogin; - private boolean forceLogout; - private String dateCreated; - private String dateModified; - - public User() {} - - public User(JSONObject user) throws JSONException { - fromJSON(user); - } - - public void fromJSON(JSONObject user) throws JSONException { - - id = user.optInt(ID_KEY, -1); - password = user.optString(PASSWORD_KEY); - orgId = user.optInt(ORG_ID_KEY, -1); - email = user.optString(EMAIL_KEY); - autoAlert = user.optBoolean(AUTOALERT_KEY); - authkey = user.optString(AUTHKEY_KEY); - invitedBy = user.optInt(INVITED_BY_KEY, -1); - gpgKey = user.optString(GPGKEY_KEY); - certifPublic = user.optString(CERTIF_PUBLIC); - nidsSid = user.optInt(NIDS_SID); - termsAccepted = user.optBoolean(TERMS_ACCEPTED_KEY, false); - newsRead = user.optInt(NEWSREAD_KEY); - roleId = user.optInt(ROLE_ID_KEY, -1); - changePw = user.optString(CHANGE_PW_KEY); - contactAlert = user.optBoolean(CONTACT_ALERT_KEY, true); - disabled = user.optBoolean(DISABLED_KEY, false); - expiration = user.optString(EXPIRATION_KEY); - currentLogin = user.optString(CURRENT_LOGIN_KEY); - lastLogin = user.optString(LAST_LOGIN_KEY); - forceLogout = user.optBoolean(FORCE_LOGOUT_KEY); - dateCreated = user.optString(DATE_CREATED_KEY); - dateModified = user.optString(DATE_MODIFIED_KEY); - - } - public JSONObject toJSON() { - return toJSON(false); - } - public JSONObject toJSON(boolean forSyncQR) { - JSONObject user = new JSONObject(); - - try { - - user.putOpt(EMAIL_KEY, email); - - if (!forSyncQR) { - - user.putOpt(ID_KEY, id); - user.putOpt(ORG_ID_KEY, orgId); - user.putOpt(AUTHKEY_KEY, authkey); - user.putOpt(ROLE_ID_KEY, roleId); - user.putOpt(PASSWORD_KEY, password); - user.putOpt(CHANGE_PW_KEY, changePw); - user.putOpt(TERMS_ACCEPTED_KEY, termsAccepted); - user.putOpt(CERTIF_PUBLIC, certifPublic); - user.putOpt(GPGKEY_KEY, gpgKey); - user.putOpt(AUTOALERT_KEY, autoAlert); - user.putOpt(INVITED_BY_KEY, invitedBy); - user.putOpt(NIDS_SID, nidsSid); - user.putOpt(NEWSREAD_KEY, newsRead); - user.putOpt(CONTACT_ALERT_KEY, contactAlert); - user.putOpt(DISABLED_KEY, disabled); - user.putOpt(EXPIRATION_KEY, expiration); - user.putOpt(CURRENT_LOGIN_KEY, currentLogin); - user.putOpt(LAST_LOGIN_KEY, lastLogin); - user.putOpt(FORCE_LOGOUT_KEY, forceLogout); - user.putOpt(DATE_CREATED_KEY, dateCreated); - user.putOpt(DATE_MODIFIED_KEY, dateModified); - - } - - } catch (JSONException e) { - e.printStackTrace(); - } - - return user; - } - - public void clearForStorage() { - setAuthkey(""); - setGpgKey(""); - setCertifPublic(""); - } - - - public int getId() { - return id; - } - public void setId(int id) { - this.id = id; - } - - public String getPassword() { - return password; - } - public void setPassword(String password) { - this.password = password; - } - - public int getOrgId() { - return orgId; - } - public void setOrgId(int orgId) { - this.orgId = orgId; - } - - public String getEmail() { - return email; - } - public void setEmail(String email) { - this.email = email; - } - - public boolean isAutoAlert() { - return autoAlert; - } - public void setAutoAlert(boolean autoAlert) { - this.autoAlert = autoAlert; - } - - public String getAuthkey() { - return authkey; - } - public void setAuthkey(String authkey) { - this.authkey = authkey; - } - - public int getInvitedBy() { - return invitedBy; - } - public void setInvitedBy(int invitedBy) { - this.invitedBy = invitedBy; - } - - public String getGpgKey() { - return gpgKey; - } - public void setGpgKey(String gpgKey) { - this.gpgKey = gpgKey; - } - - public String getCertifPublic() { - return certifPublic; - } - public void setCertifPublic(String certifPublic) { - this.certifPublic = certifPublic; - } - - public int getNidsSid() { - return nidsSid; - } - public void setNidsSid(int nidsSid) { - this.nidsSid = nidsSid; - } - - public boolean isTermsAccepted() { - return termsAccepted; - } - public void setTermsAccepted(boolean termsAccepted) { - this.termsAccepted = termsAccepted; - } - - public int getNewsRead() { - return newsRead; - } - public void setNewsRead(int newsRead) { - this.newsRead = newsRead; - } - - public int getRoleId() { - return roleId; - } - public void setRoleId(int roleId) { - this.roleId = roleId; - } - - public String getChangePw() { - return changePw; - } - public void setChangePw(String changePw) { - this.changePw = changePw; - } - - public boolean isContactAlert() { - return contactAlert; - } - public void setContactAlert(boolean contactAlert) { - this.contactAlert = contactAlert; - } - - public boolean isDisabled() { - return disabled; - } - public void setDisabled(boolean disabled) { - this.disabled = disabled; - } - - public String getExpiration() { - return expiration; - } - public void setExpiration(String expiration) { - this.expiration = expiration; - } - - public String getCurrentLogin() { - return currentLogin; - } - public void setCurrentLogin(String currentLogin) { - this.currentLogin = currentLogin; - } - - public String getLastLogin() { - return lastLogin; - } - public void setLastLogin(String lastLogin) { - this.lastLogin = lastLogin; - } - - public boolean isForceLogout() { - return forceLogout; - } - public void setForceLogout(boolean forceLogout) { - this.forceLogout = forceLogout; - } - - public String getDateCreated() { - return dateCreated; - } - public void setDateCreated(String dateCreated) { - this.dateCreated = dateCreated; - } - - public String getDateModified() { - return dateModified; - } - public void setDateModified(String dateModified) { - this.dateModified = dateModified; - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java b/app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java deleted file mode 100644 index 7cbaff1..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/network/JsonArrayRequestWithJsonObject.java +++ /dev/null @@ -1,42 +0,0 @@ -package de.overview.wg.its.mispbump.network; - -import com.android.volley.NetworkResponse; -import com.android.volley.ParseError; -import com.android.volley.Response; -import com.android.volley.toolbox.HttpHeaderParser; -import com.android.volley.toolbox.JsonRequest; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.io.UnsupportedEncodingException; - -public class JsonArrayRequestWithJsonObject extends JsonRequest { - /** - * Creates a new request. - * @param method the HTTP method to use - * @param url URL to fetch the JSON from - * @param jsonRequest A {@link JSONObject} to post with the request. Null is allowed and - * indicates no parameters will be posted along with request. - * @param listener Listener to receive the JSON response - * @param errorListener Error listener, or null to ignore errors. - */ - - public JsonArrayRequestWithJsonObject(int method, String url, JSONObject jsonRequest, Response.Listener listener, Response.ErrorListener errorListener) { - super(method, url, (jsonRequest == null) ? null : jsonRequest.toString(), listener, errorListener); - } - - @Override - protected Response parseNetworkResponse(NetworkResponse response) { - try { - - String jsonString = new String(response.data, HttpHeaderParser.parseCharset(response.headers, PROTOCOL_CHARSET)); - return Response.success(new JSONArray(jsonString), HttpHeaderParser.parseCacheHeaders(response)); - - } catch (UnsupportedEncodingException | JSONException e) { - - return Response.error(new ParseError(e)); - - } - } -} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java b/app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java deleted file mode 100644 index 5c06071..0000000 --- a/app/src/main/java/de/overview/wg/its/mispbump/network/MispRequest.java +++ /dev/null @@ -1,432 +0,0 @@ -package de.overview.wg.its.mispbump.network; - -import android.content.Context; -import android.support.annotation.Nullable; -import com.android.volley.Request; -import com.android.volley.RequestQueue; -import com.android.volley.Response; -import com.android.volley.VolleyError; -import com.android.volley.toolbox.JsonObjectRequest; -import com.android.volley.toolbox.Volley; -import de.overview.wg.its.mispbump.auxiliary.PreferenceManager; -import de.overview.wg.its.mispbump.model.Organisation; -import de.overview.wg.its.mispbump.model.Server; -import de.overview.wg.its.mispbump.model.User; -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.Map; - -/** - * JSON based API to communicate with MISP-Instances - */ -public class MispRequest { - - private static MispRequest instance; - - private RequestQueue requestQueue; - private PreferenceManager preferenceManager; - private String serverUrl, automationKey; - - /** - * @param context for Volley Request Q and PreferenceManager - */ - private MispRequest(Context context, boolean loadSavedCredentials) { - requestQueue = Volley.newRequestQueue(context); - - if (loadSavedCredentials) { - preferenceManager = PreferenceManager.Instance(context); - loadSavedCredentials(); - } - } - - private void loadSavedCredentials() { - serverUrl = preferenceManager.getMyServerUrl(); - automationKey = preferenceManager.getMyServerAutomationKey(); - } - - public void testConnection(final ConnectionCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - callback.onResult(true); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onResult(false); - } - }; - - Request r = objectRequest(Request.Method.GET, - serverUrl + "/servers/getPyMISPVersion.json", - null, - listener, - errorListener); - - requestQueue.add(r); - } - - public void getOrganisations(final OrganisationsCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONArray response) { - - JSONArray resultArray = new JSONArray(); - - int orgCount = response.length(); - - for (int i = 0; i < orgCount; i++) { - try { - resultArray.put(response.getJSONObject(i).getJSONObject("Organisation")); - } catch (JSONException e) { - e.printStackTrace(); - } - } - - callback.onResult(resultArray); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - Request r = arrayRequestWithJsonObject( - Request.Method.GET, - serverUrl + "/organisations/index", - null, - listener, - errorListener); - - requestQueue.add(r); - } - - /** - * @param orgId organisation ID on the MISP-Instance - * @param callback returns a single Organisation-JSON - */ - public void getOrganisation(int orgId, final OrganisationCallback callback) { - - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - try { - callback.onResult(response.getJSONObject(Organisation.ROOT_KEY)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - - Request r = objectRequest(Request.Method.GET, - serverUrl + "/organisations/view/" + orgId, - null, - listener, - errorListener); - - requestQueue.add(r); - } - - /** - * Typically used to get the organisation linked with this user - * - * @param callback return user associated with this API-Key - */ - public void getMyUser(final UserCallback callback) { - - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - - try { - callback.onResult(response.getJSONObject(User.ROOT_KEY)); - return; - } catch (JSONException e) { - e.printStackTrace(); - } - - callback.onResult(response); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - if (serverUrl.isEmpty() || automationKey.isEmpty()) { - return; - } - - Request r = objectRequest( - Request.Method.GET, - serverUrl + "/users/view/me", - null, - listener, - errorListener); - - requestQueue.add(r); - } - - /** - * @param organisation The organisation that will be added - * @param callback returns complete organisation JSON - */ - public void addOrganisation(Organisation organisation, final OrganisationCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - try { - callback.onResult(response.getJSONObject(Organisation.ROOT_KEY)); - } catch (JSONException e) { - e.printStackTrace(); - } - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - Request r = objectRequest( - Request.Method.POST, - serverUrl + "/admin/organisations/add", - organisation.toJSON(), - listener, - errorListener - ); - - requestQueue.add(r); - } - - public void removeOrganisation(int organisationID, final DeleteCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - callback.onSuccess(); - } - }; - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError volleyError) { - callback.onError(volleyError); - } - }; - - Request r = objectRequest( - Request.Method.POST, - serverUrl + "/admin/organisations/delete/" + organisationID, - null, - listener, - errorListener - ); - - requestQueue.add(r); - } - - public void addUser(User user, final UserCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - try { - callback.onResult(response.getJSONObject(User.ROOT_KEY)); - return; - } catch (JSONException e) { - e.printStackTrace(); - } - - callback.onResult(response); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - Request r = objectRequest( - Request.Method.POST, - serverUrl + "/admin/users/add", - user.toJSON(), - listener, - errorListener - ); - - requestQueue.add(r); - } - - public void removeUser(int userID, final DeleteCallback callback) { - - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - callback.onSuccess(); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - Request r = objectRequest( - Request.Method.POST, - serverUrl + "/admin/users/delete/" + userID, - null, - listener, - errorListener - ); - - requestQueue.add(r); - } - - public void addServer(Server server, final ServerCallback callback) { - Response.Listener listener = new Response.Listener() { - @Override - public void onResponse(JSONObject response) { - try { - callback.onResult(response.getJSONObject(Server.ROOT_KEY)); - return; - } catch (JSONException e) { - e.printStackTrace(); - } - - callback.onResult(response); - } - }; - - Response.ErrorListener errorListener = new Response.ErrorListener() { - @Override - public void onErrorResponse(VolleyError error) { - callback.onError(error); - } - }; - - Request r = objectRequest( - Request.Method.POST, - serverUrl + "/servers/add", - server.toJSON(), - listener, - errorListener - ); - - requestQueue.add(r); - } - - public void removeServer(Server server, final DeleteCallback callback) { - - } - - - private JsonArrayRequestWithJsonObject arrayRequestWithJsonObject(int method, String url, - @Nullable JSONObject body, - Response.Listener listener, - Response.ErrorListener errorListener) { - - return new JsonArrayRequestWithJsonObject(method, url, body, listener, errorListener) { - @Override - public Map getHeaders() { - Map params = new HashMap<>(); - - params.put("Authorization", automationKey); - params.put("Accept", "application/json"); - params.put("Content-Type", "application/json; utf-8"); - - return params; - } - }; - } - - private JsonObjectRequest objectRequest(int method, String url, - @Nullable JSONObject body, - Response.Listener listener, - Response.ErrorListener errorListener) { - - return new JsonObjectRequest(method, url, body, listener, errorListener) { - @Override - public Map getHeaders() { - Map params = new HashMap<>(); - - params.put("Authorization", automationKey); - params.put("Accept", "application/json"); - params.put("Content-Type", "application/json; utf-8"); - - return params; - } - }; - } - - public void setServerCredentials(String serverUrl, String automationKey) { - this.serverUrl = serverUrl; - this.automationKey = automationKey; - } - - public static MispRequest Instance(Context context, boolean loadSavedCredentials) { - - if (instance == null) { - instance = new MispRequest(context, loadSavedCredentials); - } - - return instance; - } - - - public interface DeleteCallback { - void onSuccess(); - - void onError(VolleyError volleyError); - } - - public interface ConnectionCallback { - void onResult(boolean connected); - } - - public interface OrganisationsCallback { - void onResult(JSONArray organisations); - - void onError(VolleyError volleyError); - } - - public interface OrganisationCallback { - void onResult(JSONObject organisationInformation); - - void onError(VolleyError volleyError); - } - - public interface UserCallback { - void onResult(JSONObject userInformation); - - void onError(VolleyError volleyError); - } - - public interface ServerCallback { - void onResult(JSONObject server); - - void onError(VolleyError volleyError); - } -} diff --git a/app/src/main/java/lu/circl/mispbump/AESActivity.java b/app/src/main/java/lu/circl/mispbump/AESActivity.java new file mode 100644 index 0000000..c4836a0 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/AESActivity.java @@ -0,0 +1,65 @@ +package lu.circl.mispbump; + +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; + +import lu.circl.mispbump.security.AESSecurity; + +public class AESActivity extends AppCompatActivity { + + private TextView info; + private Button button; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_aes); + + // populate Toolbar (Actionbar) + Toolbar myToolbar = findViewById(R.id.toolbar); + setSupportActionBar(myToolbar); + + ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setDisplayHomeAsUpEnabled(true); + } + + info = findViewById(R.id.aes_info); + button = findViewById(R.id.aes_button); + + button.setOnClickListener(onButtonClick); + } + + private View.OnClickListener onButtonClick = new View.OnClickListener() { + @Override + public void onClick(View v) { + AESSecurity sec1 = new AESSecurity(); + AESSecurity sec2 = new AESSecurity(); + + String message = "Geheimer Text von A als auch von B ..."; + + String pub1 = sec1.getPublicKey().toString(); + info.setText("A PK: " + pub1 + "\n"); + + String pub2 = sec2.getPublicKey().toString(); + info.append("B PK: " + pub2 + "\n"); + + sec1.setForeignPublicKey(sec2.getPublicKey()); + sec2.setForeignPublicKey(sec1.getPublicKey()); + info.append("\n-- public keys wurden ausgetauscht --\n\n"); + + String enc1 = sec1.encrypt(message); + info.append("A encrypted: " + enc1 + "\n"); + String enc2 = sec2.encrypt(message); + info.append("B encrypted: " + enc2 + "\n\n"); + + info.append("A entschlüsselt B's Nachricht: " + sec1.decrypt(enc2) + "\n"); + info.append("B entschlüsselt A's Nachricht: " + sec2.decrypt(enc1) + "\n"); + } + }; +} diff --git a/app/src/main/java/lu/circl/mispbump/HomeActivity.java b/app/src/main/java/lu/circl/mispbump/HomeActivity.java new file mode 100644 index 0000000..1f5666e --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/HomeActivity.java @@ -0,0 +1,120 @@ +package lu.circl.mispbump; + +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.design.widget.FloatingActionButton; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AlertDialog; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.TextView; + +import lu.circl.mispbump.auxiliary.PreferenceManager; +import lu.circl.mispbump.restful_client.Organisation; +import lu.circl.mispbump.restful_client.User; +import lu.circl.mispbump.security.KeyStoreWrapper; + +public class HomeActivity extends AppCompatActivity { + + private static final String TAG = "HomeActivity"; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_home); + + // populate Toolbar (Actionbar) + Toolbar myToolbar = findViewById(R.id.toolbar); + setSupportActionBar(myToolbar); + + ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setDisplayHomeAsUpEnabled(false); + } + + populateViewsWithInfo(); + + FloatingActionButton sync_fab = findViewById(R.id.home_fab); + sync_fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent i = new Intent(getApplicationContext(), SyncActivity.class); + startActivity(i); + } + }); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.main_menu, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + + case R.id.aes: + Intent i = new Intent(getApplicationContext(), AESActivity.class); + startActivity(i); + return true; + + case R.id.main_menu_clear_and_logout: + clearDeviceAndLogOut(); + return true; + + default: + // invoke superclass to handle unrecognized item (eg. homeAsUp) + return super.onOptionsItemSelected(item); + + } + } + + + private void populateViewsWithInfo() { + PreferenceManager preferenceManager = PreferenceManager.getInstance(this); + + User user = preferenceManager.getUserInfo(); + Organisation org = preferenceManager.getUserOrganisation(); + + TextView orgTitle = findViewById(R.id.home_org_name); + TextView orgDesc = findViewById(R.id.home_org_desc); + + orgTitle.setText(org.name); + orgDesc.setText(org.description); + } + + private void clearDeviceAndLogOut() { + + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setTitle("Clear all saved data and logout"); + builder.setMessage("Do you really want to delete all data and logout?"); + builder.setNegativeButton("Discard", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + } + }); + + builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + PreferenceManager prefs = PreferenceManager.getInstance(getApplicationContext()); + prefs.clearAllData(); + KeyStoreWrapper.deleteAllStoredKeys(); + + Intent login = new Intent(getApplicationContext(), LoginActivity.class); + startActivity(login); + finish(); + } + }); + + builder.create().show(); + } + +} diff --git a/app/src/main/java/lu/circl/mispbump/LoginActivity.java b/app/src/main/java/lu/circl/mispbump/LoginActivity.java new file mode 100644 index 0000000..038fa39 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/LoginActivity.java @@ -0,0 +1,175 @@ +package lu.circl.mispbump; + +import android.app.AlertDialog; +import android.content.DialogInterface; +import android.content.Intent; +import android.os.Bundle; +import android.support.constraint.ConstraintLayout; +import android.support.design.widget.Snackbar; +import android.support.design.widget.TextInputLayout; +import android.support.v7.app.ActionBar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.text.TextUtils; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.widget.Button; +import android.widget.ProgressBar; + +import java.util.Objects; + +import lu.circl.mispbump.auxiliary.PreferenceManager; +import lu.circl.mispbump.restful_client.MispRestClient; +import lu.circl.mispbump.restful_client.Organisation; +import lu.circl.mispbump.restful_client.User; + +public class LoginActivity extends AppCompatActivity { + + private ConstraintLayout constraintLayout; + private TextInputLayout serverUrl; + private TextInputLayout serverAutomationKey; + private ProgressBar progressBar; + + private PreferenceManager preferenceManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_login); + + // populate Toolbar (Actionbar) + Toolbar myToolbar = findViewById(R.id.toolbar); + setSupportActionBar(myToolbar); + + ActionBar ab = getSupportActionBar(); + if (ab != null) { + ab.setDisplayHomeAsUpEnabled(false); + } + + constraintLayout = findViewById(R.id.login_root); + progressBar = findViewById(R.id.login_progressbar); + serverUrl = findViewById(R.id.login_server_url); + serverAutomationKey = findViewById(R.id.login_automation_key); + Button downloadInfoButton = findViewById(R.id.login_download_button); + + downloadInfoButton.setOnClickListener(onClickDownload); + + preferenceManager = PreferenceManager.getInstance(this); + } + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + getMenuInflater().inflate(R.menu.menu_login, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()) { + case R.id.menu_login_help: + showHelpDialog(); + return true; + + default: + // invoke superclass to handle unrecognized item (eg. homeAsUp) + return super.onOptionsItemSelected(item); + + } + } + + private void showHelpDialog() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setTitle(R.string.app_name); + builder.setMessage("You need to have admin rights in order to create sync users and so on"); + + builder.setPositiveButton("Got it", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.dismiss(); + } + }); + + AlertDialog dialog = builder.create(); + dialog.show(); + } + + private View.OnClickListener onClickDownload = new View.OnClickListener() { + @Override + public void onClick(View v) { + + String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString(); + String authkey = Objects.requireNonNull(serverAutomationKey.getEditText()).getText().toString(); + + boolean error = false; + + serverUrl.setError(null); + serverAutomationKey.setError(null); + + if(!isValidUrl(url)) { + error = true; + serverUrl.setError("Invalid Server URL"); + } + + if(!isValidAutomationKey(authkey)) { + error = true; + serverAutomationKey.setError("Invalid automation key"); + } + + if (error) { + return; + } + + // save authkey and url for login + preferenceManager.setAutomationKey(authkey); + preferenceManager.setServerUrl(url); + + // instance of MispRestClient with given URL + final MispRestClient mispRestClient = new MispRestClient(getApplicationContext()); + + // display progress bar + progressBar.setVisibility(View.VISIBLE); + + // get my user information and the organisation associated with my user + mispRestClient.getMyUser(new MispRestClient.UserCallback() { + @Override + public void success(final User user) { + + preferenceManager.setUserInfo(user); + + mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() { + @Override + public void success(Organisation organisation) { + preferenceManager.setUserOrgInfo(organisation); + progressBar.setVisibility(View.GONE); + Intent home = new Intent(getApplicationContext(), HomeActivity.class); + startActivity(home); + finish(); + } + + @Override + public void failure(String error) { + progressBar.setVisibility(View.GONE); + Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show(); + } + }); + } + + @Override + public void failure(String error) { + progressBar.setVisibility(View.GONE); + Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show(); + } + }); + } + }; + + private boolean isValidUrl(String url) { + return url.startsWith("https://") || url.startsWith("http://"); + } + + private boolean isValidAutomationKey(String automationKey) { + return !TextUtils.isEmpty(automationKey); + } +} diff --git a/app/src/main/java/lu/circl/mispbump/StartUpActivity.java b/app/src/main/java/lu/circl/mispbump/StartUpActivity.java new file mode 100644 index 0000000..db0a671 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/StartUpActivity.java @@ -0,0 +1,33 @@ +package lu.circl.mispbump; + +import android.content.Intent; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; + +import lu.circl.mispbump.auxiliary.PreferenceManager; +import lu.circl.mispbump.restful_client.User; + +public class StartUpActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + if (isUserLoggedIn()) { + Intent home = new Intent(this, HomeActivity.class); + startActivity(home); + } else { + Intent login = new Intent(this, LoginActivity.class); + startActivity(login); + } + + // closes the activity thus prevents going back to this (empty) activity + finish(); + } + + private boolean isUserLoggedIn() { + PreferenceManager preferenceManager = PreferenceManager.getInstance(this); + User user = preferenceManager.getUserInfo(); + return user != null; + } +} diff --git a/app/src/main/java/lu/circl/mispbump/SyncActivity.java b/app/src/main/java/lu/circl/mispbump/SyncActivity.java new file mode 100644 index 0000000..8469adc --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/SyncActivity.java @@ -0,0 +1,234 @@ +package lu.circl.mispbump; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Point; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v7.app.AppCompatActivity; +import android.os.Bundle; +import android.view.View; +import android.widget.ImageView; +import android.widget.TextView; +import android.widget.Toast; + +import com.google.zxing.BarcodeFormat; +import com.google.zxing.EncodeHintType; +import com.google.zxing.MultiFormatWriter; +import com.google.zxing.WriterException; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import com.journeyapps.barcodescanner.BarcodeEncoder; + +import java.nio.IntBuffer; +import java.nio.ShortBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import lu.circl.mispbump.cam.CameraFragment; +import lu.circl.mispbump.restful_client.MispRestClient; +import lu.circl.mispbump.restful_client.MispServer; +import lu.circl.mispbump.restful_client.Organisation; +import lu.circl.mispbump.restful_client.Server; +import lu.circl.mispbump.restful_client.User; +import lu.circl.mispbump.security.AESSecurity; + +public class SyncActivity extends AppCompatActivity { + + private static final String TAG = "SyncActivity"; + private CameraFragment cameraFragment; + + private MispRestClient restClient; + private ImageView qrCodeView; + + private AESSecurity aesSecurity; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_sync); + + qrCodeView = findViewById(R.id.qrcode); + aesSecurity = AESSecurity.getInstance(); + + showPublicKeyQr(); + enableCameraFragment(); + } + + private void enableCameraFragment() { + cameraFragment = new CameraFragment(); + FragmentManager fragmentManager = getSupportFragmentManager(); + FragmentTransaction transaction = fragmentManager.beginTransaction(); + transaction.replace(R.id.sync_fragment_container, cameraFragment, cameraFragment.getClass().getSimpleName()); + transaction.commit(); + + cameraFragment.setReadQrEnabled(true); + cameraFragment.setOnQrAvailableListener(resultCallback); + } + + private void showPublicKeyQr() { + Bitmap bm = generateQrCodeFromString(aesSecurity.getPublicKey().toString()); + qrCodeView.setImageBitmap(bm); + qrCodeView.setVisibility(View.VISIBLE); + } + + private CameraFragment.QrResultCallback resultCallback = new CameraFragment.QrResultCallback() { + @Override + public void qrDataResult(String qrData) { + // TODO validate data + cameraFragment.setReadQrEnabled(false); + MakeToast(qrData); + } + }; + + private void MakeToast(final String message) { + this.runOnUiThread(new Runnable() { + @Override + public void run() { + Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show(); + } + }); + } + + private Bitmap generateQrCodeFromString(String content) { + + Point displaySize = new Point(); + this.getWindowManager().getDefaultDisplay().getSize(displaySize); + + int size = displaySize.x; + + if (displaySize.x > displaySize.y) { + size = displaySize.y; + } + + size = (int)(size * 0.8); + + try { + MultiFormatWriter multiFormatWriter = new MultiFormatWriter(); + + Map hints = new HashMap<>(); + hints.put(EncodeHintType.MARGIN, 0); + + BitMatrix bitMatrix = multiFormatWriter.encode(content, BarcodeFormat.QR_CODE, size, size, hints); + return createBitmap(bitMatrix); + } catch (WriterException e) { + e.printStackTrace(); + } + + return null; + } + + private Bitmap createBitmap(BitMatrix matrix) { + int width = matrix.getWidth(); + int height = matrix.getHeight(); + int[] pixels = new int[width * height]; + for (int y = 0; y < height; y++) { + int offset = y * width; + for (int x = 0; x < width; x++) { + pixels[offset + x] = matrix.get(x, y) ? 0xFF000000 : 0x55FFFFFF; + } + } + + Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); + bitmap.setPixels(pixels, 0, width, 0, 0, width, height); + return bitmap; + } + +// private View.OnClickListener onAddUser = new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// +// User user = new User(1, "felixpk@outlook.de", MispRestClient.roleId.SYNC_USER.value()); +// +// restClient.addUser(user, new MispRestClient.UserCallback() { +// @Override +// public void success(User user) { +// resultView.setText(user.toString()); +// } +// +// @Override +// public void failure(String error) { +// resultView.setText(error); +// } +// }); +// } +// }; +// +// private View.OnClickListener onAddOrganisation = new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// Organisation organisation = new Organisation("API Organisation 2", "API Generated Organisation"); +// organisation.local = true; +// organisation.nationality = "Buxdehude"; +// +// restClient.addOrganisation(organisation, new MispRestClient.OrganisationCallback() { +// @Override +// public void success(Organisation organisation) { +// resultView.setText(organisation.toString()); +// } +// +// @Override +// public void failure(String error) { +// resultView.setText(error); +// } +// }); +// } +// }; +// +// private View.OnClickListener onAddServer = new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// +// Organisation organisation = new Organisation("", ""); +// Server server = new Server("API Remote Server", "https://127.0.0.1", "0000000000000000000000000000000000000000", 1); +// +// MispServer mispServer = new MispServer(server, organisation, organisation); +// +// +// restClient.addServer(mispServer, new MispRestClient.ServerCallback() { +// @Override +// public void success(List servers) { +// +// } +// +// @Override +// public void success(MispServer server) { +// +// } +// +// @Override +// public void failure(String error) { +// +// } +// }); +// } +// }; +// +// private View.OnClickListener onGetServers = new View.OnClickListener() { +// @Override +// public void onClick(View v) { +// restClient.getServers(new MispRestClient.ServerCallback() { +// @Override +// public void success(List servers) { +// for (MispServer server : servers) { +// resultView.append(server.server.toString() + "\n\n"); +// resultView.append(server.organisation.toString() + "\n\n"); +// resultView.append(server.remoteOrg.toString()); +// } +// } +// +// @Override +// public void success(MispServer server) { +// +// } +// +// @Override +// public void failure(String error) { +// resultView.setText(error); +// } +// }); +// } +// }; +} diff --git a/app/src/main/java/lu/circl/mispbump/adapters/UserAdapter.java b/app/src/main/java/lu/circl/mispbump/adapters/UserAdapter.java new file mode 100644 index 0000000..b48afad --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/adapters/UserAdapter.java @@ -0,0 +1,60 @@ +package lu.circl.mispbump.adapters; + +import android.support.v7.widget.RecyclerView; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import java.util.ArrayList; +import java.util.List; + +import lu.circl.mispbump.R; +import lu.circl.mispbump.auxiliary.KeyValue; +import lu.circl.mispbump.restful_client.Organisation; +import lu.circl.mispbump.restful_client.User; + +public class UserAdapter extends RecyclerView.Adapter { + + private List> data = new ArrayList<>(); + + static class UserViewHolder extends RecyclerView.ViewHolder { + TextView title; + TextView description; + + UserViewHolder(View v) { + super(v); + title = v.findViewById(R.id.viewholder_user_title); + description = v.findViewById(R.id.viewholder_user_description); + } + } + + public UserAdapter(User user, Organisation organisation) { + data.add(new KeyValue<>("UUID", organisation.uuid)); + data.add(new KeyValue<>("Name", organisation.name)); + data.add(new KeyValue<>("Description", organisation.description)); + data.add(new KeyValue<>("Nationality", organisation.nationality)); + data.add(new KeyValue<>("Email", user.email)); +// data.add(new KeyValue<>("ID", "" + user.value)); +// data.add(new KeyValue<>("Organisation ID", "" + user.org_id)); +// data.add(new KeyValue<>("Role ID", "" + user.role_id)); + } + + @Override + public UserAdapter.UserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.viewholder_user, parent, false); + return new UserViewHolder(v); + } + + @Override + public void onBindViewHolder(UserViewHolder holder, int position) { + holder.title.setText(data.get(position).key); + holder.description.setText(data.get(position).value); + } + + @Override + public int getItemCount() { + return data.size(); + } + +} diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/KeyValue.java b/app/src/main/java/lu/circl/mispbump/auxiliary/KeyValue.java new file mode 100644 index 0000000..fe9b2e9 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/auxiliary/KeyValue.java @@ -0,0 +1,11 @@ +package lu.circl.mispbump.auxiliary; + +public class KeyValue { + public K key; + public V value; + + public KeyValue(K key, V value) { + this.key = key; + this.value = value; + } +} diff --git a/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java new file mode 100644 index 0000000..1906186 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/auxiliary/PreferenceManager.java @@ -0,0 +1,312 @@ +package lu.circl.mispbump.auxiliary; + +import android.content.Context; +import android.content.SharedPreferences; + +import com.google.gson.Gson; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; + +import javax.crypto.BadPaddingException; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.NoSuchPaddingException; + +import lu.circl.mispbump.restful_client.Organisation; +import lu.circl.mispbump.restful_client.User; +import lu.circl.mispbump.security.KeyStoreWrapper; + +public class PreferenceManager { + + + private static final String PREFERENCES_FILE = "user_settings"; + + private static final String SAVE_CREDENTIALS = "save_credentials"; + private static final String SERVER_URL = "server_url"; + private static final String AUTOMATION_KEY = "user_automation"; + + private static final String USER_INFOS = "user_infos"; + private static final String USER_ORG_INFOS = "user_org_infos"; + + private SharedPreferences preferences; + private static PreferenceManager instance; + + private PreferenceManager(Context context) { + preferences = context.getSharedPreferences(PREFERENCES_FILE, Context.MODE_PRIVATE); + } + + /** + * Helper class to save and retrieve (sensitive) information to and from SharedPreferences. + * @param context for accessing the SharedPreferences file. + * @return singleton instance + */ + public static PreferenceManager getInstance(Context context) { + if(instance == null) { + instance = new PreferenceManager(context); + } + + return instance; + } + + + /** + * Saves user infos from "users/view/me" (encrypted) + * @param user + */ + public void setUserInfo(User user) { + try { + String userStr = new Gson().toJson(user); + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS); + String encryptedUserInfo = keyStoreWrapper.encrypt(userStr); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(USER_INFOS, encryptedUserInfo); + editor.apply(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + } + + /** + * + * @return decrypted user info if any, else null + */ + public User getUserInfo() { + + if (!preferences.contains(USER_INFOS)) { + return null; + } + + try { + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_INFO_ALIAS); + String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_INFOS, "")); + return new Gson().fromJson(decrypted, User.class); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + + return null; + } + + + /** + * Save user org infos from "organisations/view/{orgId}" (encrypted) + * @param organisation Object representation of json organisation information + */ + public void setUserOrgInfo(Organisation organisation) { + try { + String orgStr = new Gson().toJson(organisation); + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS); + String encrypted = keyStoreWrapper.encrypt(orgStr); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(USER_ORG_INFOS, encrypted); + editor.apply(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + + } + + /** + * + * @return decrypted user org info if any, else null + */ + public Organisation getUserOrganisation() { + + if(!preferences.contains(USER_ORG_INFOS)) { + return null; + } + + try { + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_ORGANISATION_INFO_ALIAS); + String decrypted = keyStoreWrapper.decrypt(preferences.getString(USER_ORG_INFOS, "")); + return new Gson().fromJson(decrypted, Organisation.class); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + + return null; + } + + + /** + * Saves the encrypted auth key/automation key + * @param automationKey + */ + public void setAutomationKey(String automationKey) { + try { + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(AUTOMATION_KEY, keyStoreWrapper.encrypt(automationKey)); + editor.apply(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + } + + public String getAutomationKey() { + + if (!preferences.contains(AUTOMATION_KEY)) { + return ""; + } + + try { + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS); + return keyStoreWrapper.decrypt(preferences.getString(AUTOMATION_KEY, "")); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + + return ""; + } + + public void clearAutomationKey() { + // remove the key from KeyStore + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS); + keyStoreWrapper.deleteStoredKey(); + + SharedPreferences.Editor editor = preferences.edit(); + editor.remove(AUTOMATION_KEY); + editor.apply(); + } + + + /** + * Saves the encrypted URL of Misp Server + * @param serverUrl + */ + public void setServerUrl(String serverUrl) { + try { + + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS); + SharedPreferences.Editor editor = preferences.edit(); + editor.putString(SERVER_URL, keyStoreWrapper.encrypt(serverUrl)); + editor.apply(); + + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + } + + public String getServerUrl() { + + if (!preferences.contains(SERVER_URL)) { + return ""; + } + + try { + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS); + return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, "")); + + } catch (NoSuchPaddingException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } catch (InvalidKeyException e) { + e.printStackTrace(); + } catch (BadPaddingException e) { + e.printStackTrace(); + } catch (IllegalBlockSizeException e) { + e.printStackTrace(); + } + + return ""; + } + + public void clearServerUrl() { + // remove the key from KeyStore + KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS); + keyStoreWrapper.deleteStoredKey(); + + SharedPreferences.Editor editor = preferences.edit(); + editor.remove(SERVER_URL); + editor.apply(); + } + + + /** + * Set if credentials (authkey & server url) should be saved locally. + * @param save enable or disable + */ + public void setSaveCredentials(boolean save) { + SharedPreferences.Editor editor = preferences.edit(); + editor.putBoolean(SAVE_CREDENTIALS, save); + editor.apply(); + } + + public boolean getSaveCredentials() { + return preferences.getBoolean(SAVE_CREDENTIALS, false); + } + + + public void clearAllData() { + SharedPreferences.Editor editor = preferences.edit(); + editor.clear(); + editor.apply(); + } +} diff --git a/app/src/main/java/lu/circl/mispbump/cam/AutoFitTextureView.java b/app/src/main/java/lu/circl/mispbump/cam/AutoFitTextureView.java new file mode 100644 index 0000000..1574f8f --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/cam/AutoFitTextureView.java @@ -0,0 +1,76 @@ +package lu.circl.mispbump.cam; + +/* + * Copyright 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import android.content.Context; +import android.util.AttributeSet; +import android.view.TextureView; + +/** + * A {@link TextureView} that can be adjusted to a specified aspect ratio. + */ +public class AutoFitTextureView extends TextureView { + + private int mRatioWidth = 0; + private int mRatioHeight = 0; + + public AutoFitTextureView(Context context) { + this(context, null); + } + + public AutoFitTextureView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public AutoFitTextureView(Context context, AttributeSet attrs, int defStyle) { + super(context, attrs, defStyle); + } + + /** + * Sets the aspect ratio for this view. The size of the view will be measured based on the ratio + * calculated from the parameters. Note that the actual sizes of parameters don't matter, that + * is, calling setAspectRatio(2, 3) and setAspectRatio(4, 6) make the same result. + * + * @param width Relative horizontal size + * @param height Relative vertical size + */ + public void setAspectRatio(int width, int height) { + if (width < 0 || height < 0) { + throw new IllegalArgumentException("Size cannot be negative."); + } + mRatioWidth = width; + mRatioHeight = height; + requestLayout(); + } + + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + super.onMeasure(widthMeasureSpec, heightMeasureSpec); + int width = MeasureSpec.getSize(widthMeasureSpec); + int height = MeasureSpec.getSize(heightMeasureSpec); + if (0 == mRatioWidth || 0 == mRatioHeight) { + setMeasuredDimension(width, height); + } else { + if (width < height * mRatioWidth / mRatioHeight) { + setMeasuredDimension(width, width * mRatioHeight / mRatioWidth); + } else { + setMeasuredDimension(height * mRatioWidth / mRatioHeight, height); + } + } + } + +} diff --git a/app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java b/app/src/main/java/lu/circl/mispbump/cam/CameraFragment.java similarity index 83% rename from app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java rename to app/src/main/java/lu/circl/mispbump/cam/CameraFragment.java index 5e9a40a..c36f236 100644 --- a/app/src/main/java/de/overview/wg/its/mispbump/cam/CameraFragment.java +++ b/app/src/main/java/lu/circl/mispbump/cam/CameraFragment.java @@ -1,4 +1,4 @@ -package de.overview.wg.its.mispbump.cam; +package lu.circl.mispbump.cam; import android.Manifest; import android.app.Activity; @@ -18,6 +18,7 @@ import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.params.StreamConfigurationMap; import android.media.Image; import android.media.ImageReader; +import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; @@ -33,11 +34,10 @@ import android.util.SparseArray; import android.util.SparseIntArray; import android.view.*; import android.widget.Toast; + import com.google.android.gms.vision.Frame; import com.google.android.gms.vision.barcode.Barcode; import com.google.android.gms.vision.barcode.BarcodeDetector; -import de.overview.wg.its.mispbump.QrSyncActivity; -import de.overview.wg.its.mispbump.R; import java.util.ArrayList; import java.util.Arrays; @@ -47,19 +47,87 @@ import java.util.List; import java.util.concurrent.Semaphore; import java.util.concurrent.TimeUnit; +import lu.circl.mispbump.R; + public class CameraFragment extends Fragment implements ActivityCompat.OnRequestPermissionsResultCallback { - private QrSyncActivity parentActivity; + private class ImageProcessingThread extends Thread { + + private boolean isRunning = true; + private int lastAccessedIndex = 0; + private Bitmap[] processQueue = new Bitmap[10]; + + ImageProcessingThread() { + Log.i(TAG, "Image worker thread created"); + } + + void addToQueue(Bitmap bitmap) { + + if (lastAccessedIndex == 10) { + lastAccessedIndex = 0; + } + + processQueue[lastAccessedIndex] = bitmap; + lastAccessedIndex++; + } + + @Override + public void run() { + while (isRunning) { + + if (!readQrEnabled) { + continue; + } + + int usedSlots = 0; + + for (int i = 0; i < processQueue.length; i++) { + + if (processQueue[i] == null) { + continue; + } + + usedSlots++; + + SparseArray barcodes = barcodeDetector.detect(new Frame.Builder().setBitmap(processQueue[i]).build()); + + if (barcodes.size() > 0) { + if (qrResultCallback != null) { + + qrResultCallback.qrDataResult(barcodes.valueAt(0).rawValue); + + try { + sleep(100); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } else { + Log.i(TAG, "QrResultCallback not attached"); + } + } + + processQueue[i] = null; + } + + try { + sleep(250); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Log.i(TAG, "slots in use: " + usedSlots); + } + } + } + + private QrResultCallback qrResultCallback; @Override public void onAttach(Context context) { super.onAttach(context); - parentActivity = (QrSyncActivity) context; } - /** - * Conversion from screen rotation to JPEG orientation. - */ private static final SparseIntArray ORIENTATIONS = new SparseIntArray(); private static final int REQUEST_CAMERA_PERMISSION = 1; private static final String FRAGMENT_DIALOG = "dialog"; @@ -71,10 +139,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest ORIENTATIONS.append(Surface.ROTATION_270, 180); } - /** - * Tag for the {@link Log}. - */ - private static final String TAG = "MISP_LOG"; + private static final String TAG = "CameraFragment"; /** * Max preview width that is guaranteed by Camera2 API @@ -92,8 +157,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest */ private final TextureView.SurfaceTextureListener mSurfaceTextureListener = new TextureView.SurfaceTextureListener() { + boolean processing = false; + @Override public void onSurfaceTextureAvailable(SurfaceTexture texture, int width, int height) { + Log.i(TAG, "Width: " + width + "; height: " + height); openCamera(width, height); } @@ -108,11 +176,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } @Override - public void onSurfaceTextureUpdated(SurfaceTexture texture) { - } - + public void onSurfaceTextureUpdated(SurfaceTexture texture) { } }; + private ImageProcessingThread imageProcessingThread; + /** * ID of the current {@link CameraDevice}. */ @@ -121,12 +189,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest /** * An {@link AutoFitTextureView} for camera preview. */ - private AutoFitTextureView mTextureView; + private AutoFitTextureView autoFitTextureView; /** * A {@link CameraCaptureSession } for camera preview. */ - private CameraCaptureSession mCaptureSession; + private CameraCaptureSession previewCaptureSession; /** * A reference to the opened {@link CameraDevice}. @@ -182,36 +250,22 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest private Handler mBackgroundHandler; /** - * An {@link ImageReader} that handles still image capture. + * An {@link ImageReader} that handles still bitmap capture. */ - private ImageReader mImageReader; + private ImageReader stillImageReader; /** * This a callback object for the {@link ImageReader}. "onImageAvailable" will be called when a - * still image is ready to be saved. + * still bitmap is ready to be saved. */ private final ImageReader.OnImageAvailableListener mOnImageAvailableListener = new ImageReader.OnImageAvailableListener() { @Override public void onImageAvailable(ImageReader reader) { - Image image = reader.acquireNextImage(); Bitmap bitmap = YUV2Bitmap(image); - - if (bitmap != null && readQrEnabled) { - - Frame frame = new Frame.Builder().setBitmap(bitmap).build(); - SparseArray barcodes = barcodeDetector.detect(frame); - - if (barcodes.size() > 0) { - parentActivity.onReadQrCode(barcodes.valueAt(0).rawValue); - } - } - - if (image != null) { - image.close(); - } + imageProcessingThread.addToQueue(bitmap); + image.close(); } - }; /** @@ -266,10 +320,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest // Collect the supported resolutions that are at least as big as the preview Surface List bigEnough = new ArrayList<>(); + // Collect the supported resolutions that are smaller than the preview Surface List notBigEnough = new ArrayList<>(); int w = aspectRatio.getWidth(); int h = aspectRatio.getHeight(); + for (Size option : choices) { if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight && option.getHeight() == option.getWidth() * h / w) { if (option.getWidth() >= textureViewWidth && option.getHeight() >= textureViewHeight) { @@ -294,19 +350,15 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - View v = inflater.inflate(R.layout.fragment_camera, container, false); - initRenderScript(); - setUpBarcodeDetector(); - return v; } @Override public void onViewCreated(final View view, Bundle savedInstanceState) { - mTextureView = view.findViewById(R.id.texture); + autoFitTextureView = view.findViewById(R.id.texture); } @Override @@ -319,14 +371,17 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest super.onResume(); startBackgroundThread(); + imageProcessingThread = new ImageProcessingThread(); + imageProcessingThread.start(); + // When the screen is turned off and turned back on, the SurfaceTexture is already // available, and "onSurfaceTextureAvailable" will not be called. In that case, we can open // a camera and start preview from here (otherwise, we wait until the surface is ready in // the SurfaceTextureListener). - if (mTextureView.isAvailable()) { - openCamera(mTextureView.getWidth(), mTextureView.getHeight()); + if (autoFitTextureView.isAvailable()) { + openCamera(autoFitTextureView.getWidth(), autoFitTextureView.getHeight()); } else { - mTextureView.setSurfaceTextureListener(mSurfaceTextureListener); + autoFitTextureView.setSurfaceTextureListener(mSurfaceTextureListener); } } @@ -334,6 +389,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest public void onPause() { closeCamera(); stopBackgroundThread(); + + if (imageProcessingThread.isAlive()) { + imageProcessingThread.isRunning = false; + } + super.onPause(); } @@ -365,31 +425,35 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest @SuppressWarnings("SuspiciousNameCombination") private void setUpCameraOutputs(int width, int height) { Activity activity = getActivity(); + assert activity != null; CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); try { for (String cameraId : manager.getCameraIdList()) { + CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId); - // We don't use a front facing camera in this sample. Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING); + if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) { continue; } StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP); + if (map == null) { continue; } - // For still image captures, we use the largest available size. + // For still bitmap captures, we use the largest available size. Size largest = Collections.max(Arrays.asList(map.getOutputSizes(ImageFormat.YUV_420_888)), new CompareSizesByArea()); - mImageReader = ImageReader.newInstance(largest.getWidth() / 8, largest.getHeight() / 8, ImageFormat.YUV_420_888, 2); - mImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); + stillImageReader = ImageReader.newInstance(largest.getWidth() / 8, largest.getHeight() / 8, ImageFormat.YUV_420_888, 2); + stillImageReader.setOnImageAvailableListener(mOnImageAvailableListener, mBackgroundHandler); // Find out if we need to swap dimension to get the preview size relative to sensor coordinate. int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation(); + //noinspection ConstantConditions int mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION); boolean swappedDimensions = false; @@ -433,6 +497,12 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest maxPreviewHeight = MAX_PREVIEW_HEIGHT; } + Size[] sizes = map.getOutputSizes(SurfaceTexture.class); + + for (Size size : sizes) { + Log.i(TAG, size.toString()); + } + // Danger, W.R.! Attempting to use too large a preview size could exceed the camera // bus' bandwidth limitation, resulting in gorgeous previews but the storage of // garbage capture data. @@ -442,10 +512,11 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest // We fit the aspect ratio of TextureView to the size of preview we picked. int orientation = getResources().getConfiguration().orientation; + if (orientation == Configuration.ORIENTATION_LANDSCAPE) { - mTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight()); + autoFitTextureView.setAspectRatio(mPreviewSize.getWidth(), mPreviewSize.getHeight()); } else { - mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth()); + autoFitTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth()); } mCameraId = cameraId; @@ -464,8 +535,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest * Opens the camera specified by {@link CameraFragment#mCameraId}. */ private void openCamera(int width, int height) { + Activity activity = getActivity(); - if (ContextCompat.checkSelfPermission(getActivity(), Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { + if (ContextCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { requestCameraPermission(); return; } @@ -473,7 +545,6 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest setUpCameraOutputs(width, height); configureTransform(width, height); - Activity activity = getActivity(); CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE); try { @@ -497,9 +568,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest try { mCameraOpenCloseLock.acquire(); - if (null != mCaptureSession) { - mCaptureSession.close(); - mCaptureSession = null; + if (null != previewCaptureSession) { + previewCaptureSession.close(); + previewCaptureSession = null; } if (null != mCameraDevice) { @@ -507,9 +578,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest mCameraDevice = null; } - if (null != mImageReader) { - mImageReader.close(); - mImageReader = null; + if (null != stillImageReader) { + stillImageReader.close(); + stillImageReader = null; } } catch (InterruptedException e) { @@ -547,23 +618,23 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest */ private void createCameraPreviewSession() { try { - SurfaceTexture texture = mTextureView.getSurfaceTexture(); - assert texture != null; + // from AutoFitTextureView + SurfaceTexture texture = autoFitTextureView.getSurfaceTexture(); // We configure the size of default buffer to be the size of camera preview we want. texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight()); // This is the output Surface we need to start preview. Surface surface = new Surface(texture); - Surface mImageSurface = mImageReader.getSurface(); + Surface mImageSurface = stillImageReader.getSurface(); // We set up a CaptureRequest.Builder with the output Surface. - mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); + mPreviewRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW); // TEMPLATE_ZERO_SHUTTER_LAG mPreviewRequestBuilder.addTarget(surface); mPreviewRequestBuilder.addTarget(mImageSurface); // Here, we create a CameraCaptureSession for camera preview. - mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()), + mCameraDevice.createCaptureSession(Arrays.asList(surface, stillImageReader.getSurface()), new CameraCaptureSession.StateCallback() { @Override @@ -574,14 +645,14 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } // When the session is ready, we start displaying the preview. - mCaptureSession = cameraCaptureSession; + previewCaptureSession = cameraCaptureSession; try { // Auto focus should be continuous for camera preview. - mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); + mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE); // CONTROL_AF_MODE_CONTINUOUS_PICTURE // Finally, we start displaying the camera preview. mPreviewRequest = mPreviewRequestBuilder.build(); - mCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler); + previewCaptureSession.setRepeatingRequest(mPreviewRequest, null, mBackgroundHandler); } catch (CameraAccessException e) { e.printStackTrace(); } @@ -599,26 +670,28 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } /** - * Configures the necessary {@link android.graphics.Matrix} transformation to `mTextureView`. + * Configures the necessary {@link android.graphics.Matrix} transformation to `autoFitTextureView`. * This method should be called after the camera preview size is determined in - * setUpCameraOutputs and also the size of `mTextureView` is fixed. + * setUpCameraOutputs and also the size of `autoFitTextureView` is fixed. * - * @param viewWidth The width of `mTextureView` - * @param viewHeight The height of `mTextureView` + * @param viewWidth The width of `autoFitTextureView` + * @param viewHeight The height of `autoFitTextureView` */ private void configureTransform(int viewWidth, int viewHeight) { Activity activity = getActivity(); - if (null == mTextureView || null == mPreviewSize || null == activity) { + if (null == autoFitTextureView || null == mPreviewSize || null == activity) { return; } int rotation = activity.getWindowManager().getDefaultDisplay().getRotation(); + Matrix matrix = new Matrix(); RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth()); float centerX = viewRect.centerX(); float centerY = viewRect.centerY(); + if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) { bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY()); matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL); @@ -630,7 +703,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } else if (Surface.ROTATION_180 == rotation) { matrix.postRotate(180, centerX, centerY); } - mTextureView.setTransform(matrix); + autoFitTextureView.setTransform(matrix); } /** @@ -710,6 +783,10 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } + public interface QrResultCallback { + void qrDataResult(String qrData); + } + private boolean readQrEnabled = true; private BarcodeDetector barcodeDetector; private RenderScript renderScript; @@ -763,9 +840,7 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest } public void setReadQrEnabled(boolean enabled) { - Log.d(TAG, "setReadQrEnabled() called with: enabled = [" + enabled + "]"); - readQrEnabled = enabled; } @@ -778,4 +853,9 @@ public class CameraFragment extends Fragment implements ActivityCompat.OnRequest Toast.makeText(getActivity(), "Could not setup QR-Code scanner!", Toast.LENGTH_SHORT).show(); } } -} \ No newline at end of file + + public void setOnQrAvailableListener(QrResultCallback callback) { + qrResultCallback = callback; + } +} + diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispOrganisation.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispOrganisation.java new file mode 100644 index 0000000..5bd9cd4 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispOrganisation.java @@ -0,0 +1,10 @@ +package lu.circl.mispbump.restful_client; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class MispOrganisation { + @SerializedName("Organisation") + @Expose + public Organisation organisation; +} diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispRestClient.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestClient.java new file mode 100644 index 0000000..da61799 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestClient.java @@ -0,0 +1,346 @@ +package lu.circl.mispbump.restful_client; + +import android.annotation.SuppressLint; +import android.content.Context; + +import java.io.IOException; +import java.security.cert.CertificateException; +import java.util.List; + +import javax.net.ssl.HostnameVerifier; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocketFactory; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; + +import lu.circl.mispbump.auxiliary.PreferenceManager; +import okhttp3.Interceptor; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.logging.HttpLoggingInterceptor; +import retrofit2.Call; +import retrofit2.Callback; +import retrofit2.Response; +import retrofit2.Retrofit; +import retrofit2.converter.gson.GsonConverterFactory; + +public class MispRestClient { + + // callbacks and interfaces + + public enum roleId { + ADMIN(1), ORG_ADMIN(2), USER(3), PUBLISHER(4), SYNC_USER(5), READ_ONLY(6); + + private final int id; + + roleId(int id) { this.id = id; } + + public int value() { return id; } + } + + public interface UserCallback { + void success(User user); + void failure(String error); + } + + public interface OrganisationCallback { + void success(Organisation organisation); + void failure(String error); + } + + public interface ServerCallback { + void success(List servers); + void success(MispServer server); + void failure(String error); + } + + // fields + + private PreferenceManager preferenceManager; + private MispRestService mispRestService; + + /** + * Initializes the rest client to communicate with a MISP instance. + * @param context needed to access the preferences for loading credentials + */ + public MispRestClient(Context context) { + preferenceManager = PreferenceManager.getInstance(context); + + try { + Retrofit retrofit = new Retrofit.Builder() + .baseUrl(preferenceManager.getServerUrl()) + .addConverterFactory(GsonConverterFactory.create()) + .client(getUnsafeOkHttpClient()) + .build(); + + mispRestService = retrofit.create(MispRestService.class); + } catch (IllegalArgumentException e) { + throw new RuntimeException(e); + } + } + + /** + * For development only! + * Accepts all certificates so self signed certs are also accepted. + * @return OkHttpClient which accepts all certificates + */ + private OkHttpClient getUnsafeOkHttpClient() { + try { + // Create a trust manager that does not validate certificate chains + final TrustManager[] trustAllCerts = new TrustManager[] { + new X509TrustManager() { + @SuppressLint("TrustAllX509TrustManager") + @Override + public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @SuppressLint("TrustAllX509TrustManager") + @Override + public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException { + } + + @Override + public java.security.cert.X509Certificate[] getAcceptedIssuers() { + return new java.security.cert.X509Certificate[]{}; + } + } + }; + + // Install the all-trusting trust manager + final SSLContext sslContext = SSLContext.getInstance("SSL"); + sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); + + // Create an ssl socket factory with our all-trusting manager + final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); + + OkHttpClient.Builder builder = new OkHttpClient.Builder(); + builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]); + builder.hostnameVerifier(new HostnameVerifier() { + @Override + public boolean verify(String hostname, SSLSession session) { + return true; + } + }); + + // create logging interceptor + HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); + interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); + builder.addInterceptor(interceptor); + + // create authorization interceptor + builder.addInterceptor(new Interceptor() { + @Override + public okhttp3.Response intercept(Chain chain) throws IOException { + Request.Builder ongoing = chain.request().newBuilder(); + ongoing.addHeader("Accept", "application/json"); + ongoing.addHeader("Content-Type", "application/json"); + ongoing.addHeader("Authorization", preferenceManager.getAutomationKey()); + return chain.proceed(ongoing.build()); + } + }); + + return builder.build(); + } catch (Exception e) { + throw new RuntimeException(e); + } + } + + // user routes + + /** + * Fetches information about the user that is associated with saved auth key. + * @param callback wrapper to return a user directly + */ + public void getMyUser(final UserCallback callback) { + Call call = mispRestService.getMyUserInformation(); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(!response.isSuccessful()) { + callback.failure("" + response.code()); + } else { + if (response.body() != null) { + callback.success(response.body().user); + } else { + callback.failure("response body was null"); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + t.printStackTrace(); + callback.failure(t.getMessage()); + } + }); + } + + /** + * Get an user with specific ID. + * @param userId user identifier + * @param callback wrapper to return user directly + */ + public void getUser(int userId, final UserCallback callback) { + Call call = mispRestService.getUser(userId); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(!response.isSuccessful()) { + callback.failure("" + response.code()); + } else { + if (response.body() != null) { + callback.success(response.body().user); + } else { + callback.failure("response body was null"); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + t.printStackTrace(); + callback.failure(t.getMessage()); + } + }); + } + + /** + * Add a given user to the MISP instance referenced by url in preferences. + * @param user user to add + * @param callback wrapper to return the created user directly + */ + public void addUser(User user, final UserCallback callback) { + Call call = mispRestService.addUser(user); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (!response.isSuccessful()) { + callback.failure("" + response.code()); + return; + } + + callback.success(response.body().user); + } + + @Override + public void onFailure(Call call, Throwable t) { + callback.failure(t.getMessage()); + } + }); + } + + + // organisation routes + + /** + * Get an organisation by a given organisation id. + * @param orgId organisation identifier + * @param callback wrapper to return a organisation directly + */ + public void getOrganisation(int orgId, final OrganisationCallback callback) { + Call call = mispRestService.getOrganisation(orgId); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if(!response.isSuccessful()) { + callback.failure("" + response.code()); + } else { + if (response.body() != null) { + callback.success(response.body().organisation); + } else { + callback.failure("Response body was nul"); + } + } + } + + @Override + public void onFailure(Call call, Throwable t) { + callback.failure(t.getMessage()); + } + }); + } + + /** + * Add a given organisation to the MISP instance referenced by url in preferences. + * @param organisation organisation to add + * @param callback wrapper to return the created organisation directly + */ + public void addOrganisation(Organisation organisation, final OrganisationCallback callback) { + Call call = mispRestService.addOrganisation(organisation); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (!response.isSuccessful()) { + callback.failure("" + response.code()); + return; + } + + callback.success(response.body().organisation); + } + + @Override + public void onFailure(Call call, Throwable t) { + callback.failure(t.getMessage()); + } + }); + } + + // server routes + + /** + * Get all servers on MISP instance. + * @param callback wrapper to return a list of servers directly + */ + public void getServers(final ServerCallback callback) { + Call> call = mispRestService.getServers(); + + call.enqueue(new Callback>() { + @Override + public void onResponse(Call> call, Response> response) { + if (!response.isSuccessful()) { + callback.failure("" + response.code()); + return; + } + + callback.success(response.body()); + } + + @Override + public void onFailure(Call> call, Throwable t) { + callback.failure(t.getMessage()); + } + }); + } + + /** + * Add a server to the MISP instance + * @param server the server to create + * @param callback wrapper to return the created server directly + */ + public void addServer(MispServer server, final ServerCallback callback) { + Call call = mispRestService.addServer(server); + + call.enqueue(new Callback() { + @Override + public void onResponse(Call call, Response response) { + if (!response.isSuccessful()) { + callback.failure("" + response.code()); + return; + } + + callback.success(response.body()); + } + + @Override + public void onFailure(Call call, Throwable t) { + callback.failure(t.getMessage()); + } + }); + } +} diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java new file mode 100644 index 0000000..5ae9f93 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java @@ -0,0 +1,39 @@ +package lu.circl.mispbump.restful_client; + +import java.util.List; + +import retrofit2.Call; +import retrofit2.http.Body; +import retrofit2.http.GET; +import retrofit2.http.POST; +import retrofit2.http.Path; + +public interface MispRestService { + + // user routes + + @GET("users/view/me") + Call getMyUserInformation(); + + @GET("users/view/{value}") + Call getUser(@Path("value") int userId); + + @POST("admin/users/add") + Call addUser(@Body User user); + + // organisation routes + + @GET("organisations/view/{value}") + Call getOrganisation(@Path("value") int orgId); + + @POST("admin/organisations/add") + Call addOrganisation(@Body Organisation organisation); + + // server routes + + @GET("servers/index") + Call> getServers(); + + @POST("servers/add") + Call addServer(@Body MispServer server); +} diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java new file mode 100644 index 0000000..d8038b8 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java @@ -0,0 +1,28 @@ +package lu.circl.mispbump.restful_client; + +import java.util.List; +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class MispServer { + + public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) { + this.server = server; + this.organisation = organisation; + this.remoteOrg = remoteOrganisation; + } + + @SerializedName("Server") + @Expose + public Server server; + @SerializedName("Organisation") + @Expose + public Organisation organisation; + @SerializedName("RemoteOrg") + @Expose + public Organisation remoteOrg; + @SerializedName("User") + @Expose + public List user; + +} \ No newline at end of file diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java new file mode 100644 index 0000000..0c278a1 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java @@ -0,0 +1,12 @@ +package lu.circl.mispbump.restful_client; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class MispUser { + + @SerializedName("User") + @Expose + public User user; + +} \ No newline at end of file diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java b/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java new file mode 100644 index 0000000..7ec4fb4 --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java @@ -0,0 +1,82 @@ +package lu.circl.mispbump.restful_client; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +/** + * Information gathered from Misp API about a organisation. + */ +public class Organisation { + + public Organisation(String name) { + this.name = name; + } + + public Organisation(String name, String description) { + this.name = name; + this.description = description; + } + + @SerializedName("id") + @Expose + public Integer id; + @SerializedName("name") + @Expose + public String name; + @SerializedName("date_created") + @Expose + public String date_created; + @SerializedName("date_modified") + @Expose + public String date_modified; + @SerializedName("type") + @Expose + public String type; + @SerializedName("nationality") + @Expose + public String nationality; + @SerializedName("sector") + @Expose + public String sector; + @SerializedName("contacts") + @Expose + public String contacts; + @SerializedName("description") + @Expose + public String description; + @SerializedName("local") + @Expose + public Boolean local; + @SerializedName("uuid") + @Expose + public String uuid; + @SerializedName("restricted_to_domain") + @Expose + public String restricted_to_domain; + @SerializedName("created_by") + @Expose + public String created_by; + @SerializedName("user_count") + @Expose + public Integer user_count; + + @Override + public String toString() { + return "Organisation{" + + "id=" + id + + ", name='" + name + '\'' + + ", date_created='" + date_created + '\'' + + ", date_modified='" + date_modified + '\'' + + ", type='" + type + '\'' + + ", nationality='" + nationality + '\'' + + ", sector='" + sector + '\'' + + ", contacts='" + contacts + '\'' + + ", description='" + description + '\'' + + ", local=" + local + + ", uuid='" + uuid + '\'' + + ", restricted_to_domain='" + restricted_to_domain + '\'' + + ", created_by='" + created_by + '\'' + + ", user_count=" + user_count + + '}'; + } +} diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/Server.java b/app/src/main/java/lu/circl/mispbump/restful_client/Server.java new file mode 100644 index 0000000..0ec307c --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/Server.java @@ -0,0 +1,130 @@ +package lu.circl.mispbump.restful_client; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class Server { + + public Server(String name, String url, String authkey, Integer remote_org_id) { + this.name = name; + this.url = url; + this.authkey = authkey; + this.remote_org_id = remote_org_id; + } + + @SerializedName("id") + @Expose + public Integer id; + + @SerializedName("name") + @Expose + public String name; + + @SerializedName("url") + @Expose + public String url; + + @SerializedName("authkey") + @Expose + public String authkey; + + @SerializedName("org_id") + @Expose + public Integer org_id; + + @SerializedName("push") + @Expose + public Boolean push; + + @SerializedName("pull") + @Expose + public Boolean pull; + + @SerializedName("lastpulledid") + @Expose + public Object lastpulledid; + + @SerializedName("lastpushedid") + @Expose + public Object lastpushedid; + + @SerializedName("organization") + @Expose + public Object organization; + + @SerializedName("remote_org_id") + @Expose + public Integer remote_org_id; + + @SerializedName("publish_without_email") + @Expose + public Boolean publish_without_email; + + @SerializedName("unpublish_event") + @Expose + public Boolean unpublish_event; + + @SerializedName("self_signed") + @Expose + public Boolean self_signed; + + @SerializedName("pull_rules") + @Expose + public String pull_rules; + + @SerializedName("push_rules") + @Expose + public String push_rules; + + @SerializedName("cert_file") + @Expose + public Object cert_file; + + @SerializedName("client_cert_file") + @Expose + public Object client_cert_file; + + @SerializedName("internal") + @Expose + public Boolean internal; + + @SerializedName("skip_proxy") + @Expose + public Boolean skip_proxy; + + @SerializedName("caching_enabled") + @Expose + public Boolean caching_enabled; + + @SerializedName("cache_timestamp") + @Expose + public Boolean cache_timestamp; + + @Override + public String toString() { + return "Server{" + + "id=" + id + + ", name='" + name + '\'' + + ", url='" + url + '\'' + + ", authkey='" + authkey + '\'' + + ", org_id=" + org_id + + ", push=" + push + + ", pull=" + pull + + ", lastpulledid=" + lastpulledid + + ", lastpushedid=" + lastpushedid + + ", organization=" + organization + + ", remote_org_id=" + remote_org_id + + ", publish_without_email=" + publish_without_email + + ", unpublish_event=" + unpublish_event + + ", self_signed=" + self_signed + + ", pull_rules='" + pull_rules + '\'' + + ", push_rules='" + push_rules + '\'' + + ", cert_file=" + cert_file + + ", client_cert_file=" + client_cert_file + + ", internal=" + internal + + ", skip_proxy=" + skip_proxy + + ", caching_enabled=" + caching_enabled + + ", cache_timestamp=" + cache_timestamp + + '}'; + } +} diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/User.java b/app/src/main/java/lu/circl/mispbump/restful_client/User.java new file mode 100644 index 0000000..43873fd --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/restful_client/User.java @@ -0,0 +1,115 @@ +package lu.circl.mispbump.restful_client; + +import com.google.gson.annotations.Expose; +import com.google.gson.annotations.SerializedName; + +public class User { + + public User(Integer org_id, String email, Integer role_id) { + this.org_id = org_id; + this.email = email; + this.role_id = role_id; + } + + public User(Integer org_id, String email, Integer role_id, String password) { + this.password = password; + this.org_id = org_id; + this.email = email; + this.role_id = role_id; + } + + @SerializedName("id") + @Expose + public Integer id; + @SerializedName("password") + @Expose + public String password; + @SerializedName("org_id") + @Expose + public Integer org_id; + @SerializedName("email") + @Expose + public String email; + @SerializedName("autoalert") + @Expose + public Boolean autoalert; + @SerializedName("authkey") + @Expose + public String authkey; + @SerializedName("invited_by") + @Expose + public String invited_by; + @SerializedName("gpgkey") + @Expose + public Object gpgkey; + @SerializedName("certif_public") + @Expose + public String certif_public; + @SerializedName("nids_sid") + @Expose + public String nids_sid; + @SerializedName("termsaccepted") + @Expose + public Boolean termsaccepted; + @SerializedName("newsread") + @Expose + public String newsread; + @SerializedName("role_id") + @Expose + public Integer role_id; + @SerializedName("change_pw") + @Expose + public String change_pw; + @SerializedName("contactalert") + @Expose + public Boolean contactalert; + @SerializedName("disabled") + @Expose + public Boolean disabled; + @SerializedName("expiration") + @Expose + public Object expiration; + @SerializedName("current_login") + @Expose + public String current_login; + @SerializedName("last_login") + @Expose + public String last_login; + @SerializedName("force_logout") + @Expose + public Boolean force_logout; + @SerializedName("date_created") + @Expose + public Object date_created; + @SerializedName("date_modified") + @Expose + public String date_modified; + + @Override + public String toString() { + return "User{" + + "id='" + id + '\'' + + ", password='" + password + '\'' + + ", org_id='" + org_id + '\'' + + ", email='" + email + '\'' + + ", autoalert=" + autoalert + + ", authkey='" + authkey + '\'' + + ", invited_by='" + invited_by + '\'' + + ", gpgkey=" + gpgkey + + ", certif_public='" + certif_public + '\'' + + ", nids_sid='" + nids_sid + '\'' + + ", termsaccepted=" + termsaccepted + + ", newsread='" + newsread + '\'' + + ", role_id='" + role_id + '\'' + + ", change_pw='" + change_pw + '\'' + + ", contactalert=" + contactalert + + ", disabled=" + disabled + + ", expiration=" + expiration + + ", current_login='" + current_login + '\'' + + ", last_login='" + last_login + '\'' + + ", force_logout=" + force_logout + + ", date_created=" + date_created + + ", date_modified='" + date_modified + '\'' + + '}'; + } +} \ No newline at end of file diff --git a/app/src/main/java/lu/circl/mispbump/security/AESSecurity.java b/app/src/main/java/lu/circl/mispbump/security/AESSecurity.java new file mode 100644 index 0000000..427f87d --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/security/AESSecurity.java @@ -0,0 +1,154 @@ +package lu.circl.mispbump.security; + +import android.util.Base64; + +import javax.crypto.*; +import javax.crypto.spec.IvParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.*; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; + +public class AESSecurity { + + private static final String TAG = "MISP_LOGGING"; + + private static final String ENCRYPT_ALGORITHM = "AES/CBC/PKCS5Padding"; + private static final String KEY_PAIR_ALGORITHM = "EC"; + private static final int KEY_SIZE = 521; // 224 | 256 | 384 | 521 + private static final String KEY_AGREEMENT_ALGORITHM = "ECDH"; + + private static AESSecurity instance; + + private PublicKey publickey; + private KeyAgreement keyAgreement; + + private byte[] sharedSecret; + private IvParameterSpec ivParameterSpec; + + public AESSecurity() { + initialize(); + } + + /*** + * Generates a public and a private key using an elliptic curve algorithm (256 bit) + * The private key is fed into the key agreement instance + */ + private void initialize() { + + try { + KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM); + kpg.initialize(KEY_SIZE); + + KeyPair kp = kpg.generateKeyPair(); + publickey = kp.getPublic(); + + keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM); + keyAgreement.init(kp.getPrivate()); + + } catch (NoSuchAlgorithmException | InvalidKeyException e) { + e.printStackTrace(); + } + } + + /*** + * Generates a shared secret with a given public key + * @param publickey + */ + public void setForeignPublicKey(PublicKey publickey) { + + try { + keyAgreement.doPhase(publickey, true); + + byte[] tmpSharedSecret = keyAgreement.generateSecret(); + sharedSecret = Arrays.copyOfRange(tmpSharedSecret, 0, 32); + + byte[] inputVector = Arrays.copyOfRange(sharedSecret, 32, 48); + ivParameterSpec = new IvParameterSpec(inputVector); + + } catch (InvalidKeyException e) { + e.printStackTrace(); + } + } + + public String encrypt(String data) { + try { + + Key key = generateKey(); + Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM); + + try { + c.init(Cipher.ENCRYPT_MODE, key, ivParameterSpec); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + + byte[] encVal = c.doFinal(data.getBytes()); + return Base64.encodeToString(encVal, 0); + + } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return data; + } + + public String decrypt(String data) { + try { + Key key = generateKey(); + + Cipher c = Cipher.getInstance(ENCRYPT_ALGORITHM); + + try { + c.init(Cipher.DECRYPT_MODE, key, ivParameterSpec); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + + byte[] decoded = Base64.decode(data, 0); + byte[] decValue = c.doFinal(decoded); + return new String(decValue); + } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return data; + } + + public PublicKey getPublicKey() { + return publickey; + } + + private Key generateKey() { + + return new SecretKeySpec(sharedSecret, ENCRYPT_ALGORITHM); + + } + + public static String publicKeyToString(PublicKey key) { + return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT); + } + + public static PublicKey publicKeyFromString(String key) { + + try { + + byte[] input = Base64.decode(key, Base64.DEFAULT); + return KeyFactory.getInstance("EC").generatePublic(new X509EncodedKeySpec(input)); + + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + e.printStackTrace(); + } + + return null; + } + + public static AESSecurity getInstance() { + + if(instance == null) { + instance = new AESSecurity(); + } + + return instance; + } +} + diff --git a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java new file mode 100644 index 0000000..1396fae --- /dev/null +++ b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java @@ -0,0 +1,198 @@ +package lu.circl.mispbump.security; + +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.util.Base64; +import android.util.Log; + +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.UnrecoverableKeyException; +import java.security.cert.CertificateException; +import java.util.Enumeration; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; + +public class KeyStoreWrapper { + + private static final String TAG = "KeyStoreWrapper"; + + public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO"; + public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO"; + public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY"; + public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL"; + + private static final String KEYSTORE_PROVIDER = "AndroidKeyStore"; + private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + + private String KEYSTORE_ALIAS; + + public KeyStoreWrapper(String alias) { + KEYSTORE_ALIAS = alias; + } + + private boolean isInitialized() { + try { + KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER); + ks.load(null); + + if (ks.containsAlias(KEYSTORE_ALIAS)) { + return true; + } + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return false; + } + + + private SecretKey getStoredKey() { + try { + + KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER); + ks.load(null); + return (SecretKey) ks.getKey(KEYSTORE_ALIAS, null); + + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (UnrecoverableKeyException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + private SecretKey generateKey() { + try { + + // androids key generator + final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER); + + // specs for the generated key + final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEYSTORE_ALIAS, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setKeySize(256) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .build(); + + // initialize KeyGenerator and generate a secret key + keyGenerator.init(keyGenParameterSpec); + return keyGenerator.generateKey(); + + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (NoSuchProviderException e) { + e.printStackTrace(); + } catch (InvalidAlgorithmParameterException e) { + e.printStackTrace(); + } + + return null; + } + + + public void deleteStoredKey() { + try { + KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER); + ks.load(null); + ks.deleteEntry(KEYSTORE_ALIAS); + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public String encrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + SecretKey secretKey; + + if (isInitialized()) { + secretKey = getStoredKey(); + } else { + secretKey = generateKey(); + } + + final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + cipher.init(Cipher.ENCRYPT_MODE, secretKey); + + byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8)); + String encryptedDataString = Base64.encodeToString(encryptedData, Base64.DEFAULT); + String ivString = Base64.encodeToString(cipher.getIV(), Base64.DEFAULT); + + return ivString + ":::" + encryptedDataString; + } + + public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException { + + // extract iv from save data + String[] parts = input.split(":::"); + + byte[] iv = Base64.decode(parts[0], Base64.DEFAULT); + byte[] data = Base64.decode(parts[1], Base64.DEFAULT); + + final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + final GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv); + + cipher.init(Cipher.DECRYPT_MODE, getStoredKey(), gcmSpec); + + return new String(cipher.doFinal(data), StandardCharsets.UTF_8); + } + + + public static void deleteAllStoredKeys() { + try { + + KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER); + ks.load(null); + + Log.i(TAG, "Size: " + ks.size()); + + Enumeration aliases = ks.aliases(); + + while (aliases.hasMoreElements()) { + String alias = aliases.nextElement(); + ks.deleteEntry(alias); + } + + } catch (KeyStoreException e) { + e.printStackTrace(); + } catch (CertificateException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/app/src/main/res/anim/slide_down.xml b/app/src/main/res/anim/slide_down.xml deleted file mode 100644 index ad40deb..0000000 --- a/app/src/main/res/anim/slide_down.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/anim/slide_up.xml b/app/src/main/res/anim/slide_up.xml deleted file mode 100644 index a731689..0000000 --- a/app/src/main/res/anim/slide_up.xml +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml index 789e157..c7bd21d 100644 --- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -1,34 +1,34 @@ - - - - - - - - - + xmlns:aapt="http://schemas.android.com/aapt" + android:width="108dp" + android:height="108dp" + android:viewportHeight="108" + android:viewportWidth="108"> + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_account_circle.xml b/app/src/main/res/drawable/ic_account_circle.xml new file mode 100644 index 0000000..e14b3e0 --- /dev/null +++ b/app/src/main/res/drawable/ic_account_circle.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/icon_cloud_download.xml b/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml similarity index 100% rename from app/src/main/res/drawable/icon_cloud_download.xml rename to app/src/main/res/drawable/ic_cloud_download_black_24dp.xml diff --git a/app/src/main/res/drawable/icon_cloud.xml b/app/src/main/res/drawable/ic_cloud_download_light_24dp.xml similarity index 87% rename from app/src/main/res/drawable/icon_cloud.xml rename to app/src/main/res/drawable/ic_cloud_download_light_24dp.xml index 0f28023..0feb270 100644 --- a/app/src/main/res/drawable/icon_cloud.xml +++ b/app/src/main/res/drawable/ic_cloud_download_light_24dp.xml @@ -1,5 +1,5 @@ - + diff --git a/app/src/main/res/drawable/ic_delete_forever.xml b/app/src/main/res/drawable/ic_delete_forever.xml new file mode 100644 index 0000000..3047430 --- /dev/null +++ b/app/src/main/res/drawable/ic_delete_forever.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/icon_add.xml b/app/src/main/res/drawable/ic_email_black_24dp.xml similarity index 61% rename from app/src/main/res/drawable/icon_add.xml rename to app/src/main/res/drawable/ic_email_black_24dp.xml index 0258249..ce97ab8 100644 --- a/app/src/main/res/drawable/icon_add.xml +++ b/app/src/main/res/drawable/ic_email_black_24dp.xml @@ -5,5 +5,5 @@ android:viewportHeight="24.0"> + android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/> diff --git a/app/src/main/res/drawable/ic_help_outline_black_24dp.xml b/app/src/main/res/drawable/ic_help_outline_black_24dp.xml new file mode 100644 index 0000000..dbd0032 --- /dev/null +++ b/app/src/main/res/drawable/ic_help_outline_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml index 1fa43f1..2408e30 100644 --- a/app/src/main/res/drawable/ic_launcher_background.xml +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -1,74 +1,74 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + android:height="108dp" + android:width="108dp" + android:viewportHeight="108" + android:viewportWidth="108" + xmlns:android="http://schemas.android.com/apk/res/android"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/ic_person.xml b/app/src/main/res/drawable/ic_person.xml new file mode 100644 index 0000000..c902e21 --- /dev/null +++ b/app/src/main/res/drawable/ic_person.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml new file mode 100644 index 0000000..7ae478f --- /dev/null +++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/drawable/icon_arrow_right.xml b/app/src/main/res/drawable/icon_arrow_right.xml deleted file mode 100644 index 25fb386..0000000 --- a/app/src/main/res/drawable/icon_arrow_right.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_check.xml b/app/src/main/res/drawable/icon_check.xml deleted file mode 100644 index 459aef9..0000000 --- a/app/src/main/res/drawable/icon_check.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_close.xml b/app/src/main/res/drawable/icon_close.xml deleted file mode 100644 index ede4b71..0000000 --- a/app/src/main/res/drawable/icon_close.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_cloud_upload.xml b/app/src/main/res/drawable/icon_cloud_upload.xml deleted file mode 100644 index 7d0637d..0000000 --- a/app/src/main/res/drawable/icon_cloud_upload.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_contact.xml b/app/src/main/res/drawable/icon_contact.xml deleted file mode 100644 index 0d6b3bb..0000000 --- a/app/src/main/res/drawable/icon_contact.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_forward.xml b/app/src/main/res/drawable/icon_forward.xml deleted file mode 100644 index cf9e208..0000000 --- a/app/src/main/res/drawable/icon_forward.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_hour_glass.xml b/app/src/main/res/drawable/icon_hour_glass.xml deleted file mode 100644 index fa7abc6..0000000 --- a/app/src/main/res/drawable/icon_hour_glass.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_key.xml b/app/src/main/res/drawable/icon_key.xml deleted file mode 100644 index 2eddd16..0000000 --- a/app/src/main/res/drawable/icon_key.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_retry.xml b/app/src/main/res/drawable/icon_retry.xml deleted file mode 100644 index 794ca6a..0000000 --- a/app/src/main/res/drawable/icon_retry.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_round_check.xml b/app/src/main/res/drawable/icon_round_check.xml deleted file mode 100644 index 529c91e..0000000 --- a/app/src/main/res/drawable/icon_round_check.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - diff --git a/app/src/main/res/drawable/icon_round_error.xml b/app/src/main/res/drawable/icon_round_error.xml deleted file mode 100644 index cb3b30a..0000000 --- a/app/src/main/res/drawable/icon_round_error.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/icon_settings.xml b/app/src/main/res/drawable/icon_settings.xml deleted file mode 100644 index ce997a7..0000000 --- a/app/src/main/res/drawable/icon_settings.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - diff --git a/app/src/main/res/drawable/rounded_square.xml b/app/src/main/res/drawable/rounded_square.xml deleted file mode 100644 index e042271..0000000 --- a/app/src/main/res/drawable/rounded_square.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/activity_aes.xml b/app/src/main/res/layout/activity_aes.xml new file mode 100644 index 0000000..798d209 --- /dev/null +++ b/app/src/main/res/layout/activity_aes.xml @@ -0,0 +1,59 @@ + + + + + +