mirror of https://github.com/MISP/misp-bump
fix several issues
parent
c8c16dcb3c
commit
467f7541c7
|
@ -15,7 +15,7 @@
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme"
|
android:theme="@style/AppTheme"
|
||||||
tools:ignore="GoogleAppIndexingWarning">
|
tools:ignore="GoogleAppIndexingWarning">
|
||||||
|
<activity android:name=".activities.MainActivity"></activity>
|
||||||
<activity android:name=".activities.StartUpActivity">
|
<activity android:name=".activities.StartUpActivity">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
|
@ -23,7 +23,6 @@
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</activity>
|
</activity>
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.HomeActivity"
|
android:name=".activities.HomeActivity"
|
||||||
android:label="@string/home" />
|
android:label="@string/home" />
|
||||||
|
@ -32,8 +31,8 @@
|
||||||
android:label="@string/login" />
|
android:label="@string/login" />
|
||||||
<activity
|
<activity
|
||||||
android:name=".activities.SyncActivity"
|
android:name=".activities.SyncActivity"
|
||||||
android:label="@string/app_name"
|
android:label="@string/sync"
|
||||||
android:parentActivityName=".activities.HomeActivity"/>
|
android:parentActivityName=".activities.HomeActivity" />
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
|
@ -3,23 +3,45 @@ package lu.circl.mispbump.activities;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
import android.support.v7.app.AlertDialog;
|
import android.support.v7.app.AlertDialog;
|
||||||
import android.support.v7.app.AppCompatActivity;
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
import android.support.v7.widget.LinearLayoutManager;
|
||||||
|
import android.support.v7.widget.RecyclerView;
|
||||||
import android.support.v7.widget.Toolbar;
|
import android.support.v7.widget.Toolbar;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import lu.circl.mispbump.R;
|
import lu.circl.mispbump.R;
|
||||||
|
import lu.circl.mispbump.adapters.SyncAdapter;
|
||||||
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
|
import lu.circl.mispbump.restful_client.MispRestClient;
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
|
import lu.circl.mispbump.restful_client.User;
|
||||||
import lu.circl.mispbump.security.KeyStoreWrapper;
|
import lu.circl.mispbump.security.KeyStoreWrapper;
|
||||||
|
|
||||||
public class HomeActivity extends AppCompatActivity {
|
public class HomeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
public static final String TAG = "Home";
|
||||||
|
|
||||||
|
private CoordinatorLayout layout;
|
||||||
|
private TextView title;
|
||||||
|
|
||||||
|
private RecyclerView recyclerView;
|
||||||
|
|
||||||
|
private PreferenceManager preferenceManager;
|
||||||
|
private MispRestClient mispRestClient;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
@ -34,7 +56,28 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
ab.setDisplayHomeAsUpEnabled(false);
|
ab.setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
View titleView = getLayoutInflater().inflate(R.layout.actionbar_home, null);
|
||||||
|
title = titleView.findViewById(R.id.actionbar_title);
|
||||||
|
|
||||||
|
ActionBar.LayoutParams params = new ActionBar.LayoutParams(
|
||||||
|
ActionBar.LayoutParams.WRAP_CONTENT,
|
||||||
|
ActionBar.LayoutParams.MATCH_PARENT,
|
||||||
|
Gravity.CENTER);
|
||||||
|
|
||||||
|
ab.setCustomView(titleView, params);
|
||||||
|
ab.setDisplayShowCustomEnabled(true);
|
||||||
|
ab.setDisplayShowTitleEnabled(false);
|
||||||
|
|
||||||
|
layout = findViewById(R.id.layout);
|
||||||
|
|
||||||
|
recyclerView = findViewById(R.id.recyclerView);
|
||||||
|
recyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
|
preferenceManager = PreferenceManager.getInstance(this);
|
||||||
|
mispRestClient = new MispRestClient(this);
|
||||||
|
|
||||||
populateViewsWithInfo();
|
populateViewsWithInfo();
|
||||||
|
populateRecyclerView();
|
||||||
|
|
||||||
FloatingActionButton sync_fab = findViewById(R.id.home_fab);
|
FloatingActionButton sync_fab = findViewById(R.id.home_fab);
|
||||||
sync_fab.setOnClickListener(new View.OnClickListener() {
|
sync_fab.setOnClickListener(new View.OnClickListener() {
|
||||||
|
@ -54,29 +97,68 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(MenuItem item) {
|
public boolean onOptionsItemSelected(MenuItem item) {
|
||||||
switch (item.getItemId()) {
|
if (item.getItemId() == R.id.main_menu_clear_and_logout) {
|
||||||
case R.id.main_menu_clear_and_logout:
|
|
||||||
clearDeviceAndLogOut();
|
clearDeviceAndLogOut();
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (item.getItemId() == R.id.update) {
|
||||||
|
updateProfile();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
|
||||||
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void updateProfile() {
|
||||||
|
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);
|
||||||
|
populateViewsWithInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private void populateViewsWithInfo() {
|
private void populateViewsWithInfo() {
|
||||||
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
|
|
||||||
|
|
||||||
Organisation org = preferenceManager.getUserOrganisation();
|
Organisation org = preferenceManager.getUserOrganisation();
|
||||||
|
title.setText(org.name);
|
||||||
|
|
||||||
TextView orgTitle = findViewById(R.id.home_org_name);
|
TextView userCount = findViewById(R.id.user_count);
|
||||||
TextView orgDesc = findViewById(R.id.home_org_desc);
|
userCount.setText("" + org.user_count);
|
||||||
|
|
||||||
orgTitle.setText(org.name);
|
TextView sector = findViewById(R.id.sector);
|
||||||
orgDesc.setText(org.description);
|
sector.setText(org.sector);
|
||||||
|
|
||||||
|
TextView nationality = findViewById(R.id.nationality);
|
||||||
|
nationality.setText(org.nationality);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void populateRecyclerView() {
|
||||||
|
List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformation();
|
||||||
|
Log.i(TAG, "Size: " + uploadInformationList.size());
|
||||||
|
SyncAdapter syncAdapter = new SyncAdapter(uploadInformationList);
|
||||||
|
recyclerView.setAdapter(syncAdapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearDeviceAndLogOut() {
|
private void clearDeviceAndLogOut() {
|
||||||
|
@ -108,4 +190,9 @@ public class HomeActivity extends AppCompatActivity {
|
||||||
builder.create().show();
|
builder.create().show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onResume() {
|
||||||
|
super.onResume();
|
||||||
|
populateRecyclerView();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package lu.circl.mispbump.activities;
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
import android.app.AlertDialog;
|
|
||||||
import android.content.DialogInterface;
|
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.support.constraint.ConstraintLayout;
|
import android.support.constraint.ConstraintLayout;
|
||||||
|
@ -26,14 +24,66 @@ import lu.circl.mispbump.restful_client.MispRestClient;
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
import lu.circl.mispbump.restful_client.User;
|
import lu.circl.mispbump.restful_client.User;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This activity is shown when the current device has no misp user associated with it.
|
||||||
|
* Takes care of downloading all information necessary for a sync with other misp instances.
|
||||||
|
*/
|
||||||
public class LoginActivity extends AppCompatActivity {
|
public class LoginActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private PreferenceManager preferenceManager;
|
||||||
private ConstraintLayout constraintLayout;
|
private ConstraintLayout constraintLayout;
|
||||||
private TextInputLayout serverUrl;
|
|
||||||
private TextInputLayout serverAutomationKey;
|
private TextInputLayout serverAutomationKey;
|
||||||
|
private TextInputLayout serverUrl;
|
||||||
private ProgressBar progressBar;
|
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.appbar);
|
||||||
|
setSupportActionBar(myToolbar);
|
||||||
|
|
||||||
|
ActionBar ab = getSupportActionBar();
|
||||||
|
if (ab != null) {
|
||||||
|
ab.setDisplayHomeAsUpEnabled(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
constraintLayout = findViewById(R.id.layout);
|
||||||
|
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:
|
||||||
|
DialogManager.loginHelpDialog(LoginActivity.this);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// invoke superclass to handle unrecognized item (eg. homeAsUp)
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is called when the user clicks on the login button.
|
||||||
|
*/
|
||||||
private View.OnClickListener onClickDownload = new View.OnClickListener() {
|
private View.OnClickListener onClickDownload = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
|
@ -60,8 +110,9 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save authkey and url for login
|
// save authkey
|
||||||
preferenceManager.setAutomationKey(authkey);
|
preferenceManager.setAutomationKey(authkey);
|
||||||
|
// save url
|
||||||
preferenceManager.setServerUrl(url);
|
preferenceManager.setServerUrl(url);
|
||||||
|
|
||||||
// instance of MispRestClient with given URL
|
// instance of MispRestClient with given URL
|
||||||
|
@ -104,59 +155,22 @@ public class LoginActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
* Check if url is valid.
|
||||||
super.onCreate(savedInstanceState);
|
*
|
||||||
setContentView(R.layout.activity_login);
|
* @param url url to check
|
||||||
|
* @return true or false
|
||||||
// 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() {
|
|
||||||
DialogManager.loginHelpDialog(LoginActivity.this);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isValidUrl(String url) {
|
private boolean isValidUrl(String url) {
|
||||||
return url.startsWith("https://") || url.startsWith("http://");
|
return url.startsWith("https://") || url.startsWith("http://");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if automation key is valid.
|
||||||
|
*
|
||||||
|
* @param automationKey the key to check
|
||||||
|
* @return true or false
|
||||||
|
*/
|
||||||
private boolean isValidAutomationKey(String automationKey) {
|
private boolean isValidAutomationKey(String automationKey) {
|
||||||
return !TextUtils.isEmpty(automationKey);
|
return !TextUtils.isEmpty(automationKey);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.BottomNavigationView;
|
||||||
|
import android.support.v7.app.AppCompatActivity;
|
||||||
|
|
||||||
|
import lu.circl.mispbump.R;
|
||||||
|
|
||||||
|
public class MainActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
private BottomNavigationView bottomNavigationView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_main);
|
||||||
|
|
||||||
|
initializeViews();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void initializeViews() {
|
||||||
|
// bottomNavigationView = findViewById(R.id.bottom_navigation);
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,9 @@ package lu.circl.mispbump.activities;
|
||||||
|
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.design.widget.CoordinatorLayout;
|
||||||
import android.support.design.widget.FloatingActionButton;
|
import android.support.design.widget.FloatingActionButton;
|
||||||
|
import android.support.design.widget.Snackbar;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
import android.support.v4.app.FragmentTransaction;
|
import android.support.v4.app.FragmentTransaction;
|
||||||
import android.support.v7.app.ActionBar;
|
import android.support.v7.app.ActionBar;
|
||||||
|
@ -11,7 +13,6 @@ import android.support.v7.widget.Toolbar;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
import android.widget.Toast;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
|
||||||
|
@ -28,41 +29,72 @@ import lu.circl.mispbump.auxiliary.RandomString;
|
||||||
import lu.circl.mispbump.cam.CameraFragment;
|
import lu.circl.mispbump.cam.CameraFragment;
|
||||||
import lu.circl.mispbump.fragments.SyncOptionsFragment;
|
import lu.circl.mispbump.fragments.SyncOptionsFragment;
|
||||||
import lu.circl.mispbump.models.SyncInformation;
|
import lu.circl.mispbump.models.SyncInformation;
|
||||||
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
import lu.circl.mispbump.restful_client.MispRestClient;
|
import lu.circl.mispbump.restful_client.MispRestClient;
|
||||||
import lu.circl.mispbump.restful_client.MispServer;
|
import lu.circl.mispbump.restful_client.MispServer;
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
import lu.circl.mispbump.restful_client.Server;
|
import lu.circl.mispbump.restful_client.Server;
|
||||||
import lu.circl.mispbump.restful_client.User;
|
import lu.circl.mispbump.restful_client.User;
|
||||||
import lu.circl.mispbump.security.AESSecurity;
|
import lu.circl.mispbump.security.DiffieHellman;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Step 1: Add partner org as local org (uuid must be the same)
|
* This class provides the sync functionality.
|
||||||
* Step 2: Add SyncUser to local partner org
|
* It collects the necessary information, guides through the process and finally completes with
|
||||||
* Step 3: Add SyncServer with SyncUser's authkey
|
* the upload to the misp instance.
|
||||||
* <p>
|
|
||||||
* What do we need to transmit?
|
|
||||||
* 1. Own organisation details
|
|
||||||
* 2. Authkey of SyncUser
|
|
||||||
* 3. Server url
|
|
||||||
*/
|
*/
|
||||||
public class SyncActivity extends AppCompatActivity {
|
public class SyncActivity extends AppCompatActivity {
|
||||||
|
|
||||||
private static final String TAG = "SyncActivity";
|
private static final String TAG = "SyncActivity";
|
||||||
|
|
||||||
private AESSecurity aesSecurity;
|
private CoordinatorLayout layout;
|
||||||
private MispRestClient restClient;
|
|
||||||
private CameraFragment cameraFragment;
|
|
||||||
private ImageView qrCodeView;
|
private ImageView qrCodeView;
|
||||||
private FloatingActionButton continueButton;
|
private FloatingActionButton continueButton;
|
||||||
|
|
||||||
|
private CameraFragment cameraFragment;
|
||||||
|
private DiffieHellman diffieHellman;
|
||||||
|
private MispRestClient restClient;
|
||||||
|
|
||||||
|
private UploadInformation uploadInformation;
|
||||||
|
|
||||||
private SyncState currentSyncState = SyncState.publicKeyExchange;
|
private SyncState currentSyncState = SyncState.publicKeyExchange;
|
||||||
|
|
||||||
|
private PreferenceManager preferenceManager;
|
||||||
|
|
||||||
private enum SyncState {
|
private enum SyncState {
|
||||||
publicKeyExchange,
|
publicKeyExchange,
|
||||||
dataExchange
|
dataExchange
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
setContentView(R.layout.activity_sync);
|
||||||
|
|
||||||
|
Toolbar myToolbar = findViewById(R.id.appbar);
|
||||||
|
setSupportActionBar(myToolbar);
|
||||||
|
|
||||||
|
ActionBar ab = getSupportActionBar();
|
||||||
|
if (ab != null) {
|
||||||
|
ab.setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout = findViewById(R.id.layout);
|
||||||
|
|
||||||
|
qrCodeView = findViewById(R.id.qrcode);
|
||||||
|
continueButton = findViewById(R.id.continue_fab);
|
||||||
|
continueButton.setOnClickListener(onContinueClicked);
|
||||||
|
continueButton.hide();
|
||||||
|
|
||||||
|
diffieHellman = DiffieHellman.getInstance();
|
||||||
|
restClient = new MispRestClient(this);
|
||||||
|
|
||||||
|
preferenceManager = PreferenceManager.getInstance(this);
|
||||||
|
|
||||||
|
enableSyncOptionsFragment();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback to any
|
* This callback is called at the end of each sync step.
|
||||||
*/
|
*/
|
||||||
private View.OnClickListener onContinueClicked = new View.OnClickListener() {
|
private View.OnClickListener onContinueClicked = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -72,7 +104,6 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
|
|
||||||
switch (currentSyncState) {
|
switch (currentSyncState) {
|
||||||
case publicKeyExchange:
|
case publicKeyExchange:
|
||||||
|
|
||||||
DialogManager.confirmProceedDialog(SyncActivity.this,
|
DialogManager.confirmProceedDialog(SyncActivity.this,
|
||||||
new DialogManager.IDialogFeedback() {
|
new DialogManager.IDialogFeedback() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -85,13 +116,21 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void negative() {
|
public void negative() {
|
||||||
// do nothing, just wait
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case dataExchange:
|
case dataExchange:
|
||||||
// TODO upload
|
DialogManager.confirmProceedDialog(SyncActivity.this, new DialogManager.IDialogFeedback() {
|
||||||
|
@Override
|
||||||
|
public void positive() {
|
||||||
|
startUpload();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void negative() {
|
||||||
|
}
|
||||||
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -109,69 +148,151 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
switch (currentSyncState) {
|
switch (currentSyncState) {
|
||||||
case publicKeyExchange:
|
case publicKeyExchange:
|
||||||
try {
|
try {
|
||||||
final PublicKey pk = AESSecurity.publicKeyFromString(qrData);
|
final PublicKey pk = DiffieHellman.publicKeyFromString(qrData);
|
||||||
|
diffieHellman.setForeignPublicKey(pk);
|
||||||
|
|
||||||
DialogManager.publicKeyDialog(pk.toString(), SyncActivity.this,
|
runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
continueButton.show();
|
||||||
|
|
||||||
|
Snackbar sb = Snackbar.make(continueButton, "Public key received", Snackbar.LENGTH_LONG);
|
||||||
|
sb.setAction("Details", new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
DialogManager.publicKeyDialog(pk, SyncActivity.this, null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
sb.show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
||||||
|
Snackbar.make(layout, "Invalid key", Snackbar.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case dataExchange:
|
||||||
|
cameraFragment.setReadQrEnabled(false);
|
||||||
|
|
||||||
|
final SyncInformation remoteSyncInfo = new Gson().fromJson(diffieHellman.decrypt(qrData), SyncInformation.class);
|
||||||
|
|
||||||
|
DialogManager.syncInformationDialog(remoteSyncInfo,
|
||||||
|
SyncActivity.this,
|
||||||
new DialogManager.IDialogFeedback() {
|
new DialogManager.IDialogFeedback() {
|
||||||
@Override
|
@Override
|
||||||
public void positive() {
|
public void positive() {
|
||||||
aesSecurity.setForeignPublicKey(pk);
|
uploadInformation.remote = remoteSyncInfo;
|
||||||
continueButton.show();
|
continueButton.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void negative() {
|
public void negative() {
|
||||||
// enable qr read again to scan another pk
|
|
||||||
cameraFragment.setReadQrEnabled(true);
|
cameraFragment.setReadQrEnabled(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
|
|
||||||
MakeToast("Invalid key");
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
|
||||||
|
|
||||||
case dataExchange:
|
|
||||||
// disable qr read
|
|
||||||
cameraFragment.setReadQrEnabled(false);
|
|
||||||
|
|
||||||
String data = aesSecurity.decrypt(qrData);
|
|
||||||
SyncInformation info = new Gson().fromJson(data, SyncInformation.class);
|
|
||||||
|
|
||||||
Log.i(TAG, info.organisation.toString());
|
|
||||||
Log.i(TAG, info.user.toString());
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
private void startUpload() {
|
||||||
|
// check if misp instance is available
|
||||||
|
restClient.isAvailable(new MispRestClient.AvailableCallback() {
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
public void unavailable() {
|
||||||
super.onCreate(savedInstanceState);
|
Snackbar sb = Snackbar.make(layout, "MISP instance not available", Snackbar.LENGTH_LONG);
|
||||||
setContentView(R.layout.activity_sync);
|
sb.setAction("Retry", new View.OnClickListener() {
|
||||||
|
@Override
|
||||||
Toolbar myToolbar = findViewById(R.id.toolbar);
|
public void onClick(View v) {
|
||||||
setSupportActionBar(myToolbar);
|
startUpload(); // TODO check if this works
|
||||||
|
}
|
||||||
ActionBar ab = getSupportActionBar();
|
});
|
||||||
if (ab != null) {
|
sb.show();
|
||||||
ab.setDisplayHomeAsUpEnabled(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qrCodeView = findViewById(R.id.qrcode);
|
@Override
|
||||||
continueButton = findViewById(R.id.continue_fab);
|
public void available() {
|
||||||
continueButton.setOnClickListener(onContinueClicked);
|
|
||||||
continueButton.hide();
|
|
||||||
|
|
||||||
aesSecurity = AESSecurity.getInstance();
|
restClient.addOrganisation(uploadInformation.remote.organisation, new MispRestClient.OrganisationCallback() {
|
||||||
restClient = new MispRestClient(this);
|
@Override
|
||||||
|
public void success(final Organisation organisation) {
|
||||||
|
// create syncUser object from syncInfo
|
||||||
|
User syncUser = new User();
|
||||||
|
syncUser.org_id = organisation.id;
|
||||||
|
syncUser.role_id = User.ROLE_SYNC_USER;
|
||||||
|
|
||||||
enableSyncOptionsFragment();
|
// syncuser_ORG@REMOTE_ORG_EMAIL_DOMAIN
|
||||||
|
String emailSaveOrgName = organisation.name.replace(" ", "").toLowerCase();
|
||||||
|
syncUser.email = "syncuser_" + emailSaveOrgName + "@misp.de";
|
||||||
|
|
||||||
|
syncUser.password = uploadInformation.remote.syncUserPassword;
|
||||||
|
syncUser.authkey = uploadInformation.remote.syncUserAuthkey;
|
||||||
|
syncUser.termsaccepted = true;
|
||||||
|
|
||||||
|
// add user to local organisation
|
||||||
|
restClient.addUser(syncUser, new MispRestClient.UserCallback() {
|
||||||
|
@Override
|
||||||
|
public void success(User user) {
|
||||||
|
Server server = new Server();
|
||||||
|
server.name = organisation.name + "'s Sync Server";
|
||||||
|
server.url = uploadInformation.remote.baseUrl;
|
||||||
|
server.remote_org_id = organisation.id;
|
||||||
|
server.authkey = uploadInformation.local.syncUserAuthkey;
|
||||||
|
server.self_signed = true;
|
||||||
|
|
||||||
|
restClient.addServer(server, new MispRestClient.ServerCallback() {
|
||||||
|
@Override
|
||||||
|
public void success(List<MispServer> servers) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void success(MispServer server) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void success(Server server) {
|
||||||
|
uploadInformation.currentSyncStatus = UploadInformation.SyncStatus.COMPLETE;
|
||||||
|
preferenceManager.setUploadInformation(uploadInformation);
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
uploadInformation.currentSyncStatus = UploadInformation.SyncStatus.FAILURE;
|
||||||
|
preferenceManager.setUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
Log.e(TAG, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
uploadInformation.currentSyncStatus = UploadInformation.SyncStatus.FAILURE;
|
||||||
|
preferenceManager.setUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
Log.e(TAG, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void failure(String error) {
|
||||||
|
uploadInformation.currentSyncStatus = UploadInformation.SyncStatus.FAILURE;
|
||||||
|
preferenceManager.setUploadInformation(uploadInformation);
|
||||||
|
Snackbar.make(layout, error, Snackbar.LENGTH_LONG).show();
|
||||||
|
Log.e(TAG, error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates the camera fragment used to scan the QR codes.
|
* Creates the camera fragment used to scan the QR codes.
|
||||||
|
* Automatically starts processing images (search QR codes).
|
||||||
*/
|
*/
|
||||||
private void enableCameraFragment() {
|
private void enableCameraFragment() {
|
||||||
cameraFragment = new CameraFragment();
|
cameraFragment = new CameraFragment();
|
||||||
|
@ -185,7 +306,7 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* options for this particular sync
|
* Creates fragment to tweak sync options.
|
||||||
*/
|
*/
|
||||||
private void enableSyncOptionsFragment() {
|
private void enableSyncOptionsFragment() {
|
||||||
SyncOptionsFragment syncOptionsFragment = new SyncOptionsFragment();
|
SyncOptionsFragment syncOptionsFragment = new SyncOptionsFragment();
|
||||||
|
@ -205,39 +326,35 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display public key QR code.
|
* Display QR code that contains the public key .
|
||||||
*/
|
*/
|
||||||
private void showPublicKeyQr() {
|
private void showPublicKeyQr() {
|
||||||
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
||||||
Bitmap bm = qrCodeGenerator.generateQrCode(AESSecurity.publicKeyToString(aesSecurity.getPublicKey()));
|
Bitmap bm = qrCodeGenerator.generateQrCode(DiffieHellman.publicKeyToString(diffieHellman.getPublicKey()));
|
||||||
qrCodeView.setImageBitmap(bm);
|
qrCodeView.setImageBitmap(bm);
|
||||||
qrCodeView.setVisibility(View.VISIBLE);
|
qrCodeView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display sync info QR code.
|
* Display QR code that contains mandatory information for a sync.
|
||||||
*/
|
*/
|
||||||
private void showInformationQr() {
|
private void showInformationQr() {
|
||||||
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
|
PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
|
||||||
|
|
||||||
|
SyncInformation syncInformation = new SyncInformation();
|
||||||
|
|
||||||
|
syncInformation.organisation = preferenceManager.getUserOrganisation().syncOrganisation();
|
||||||
|
syncInformation.syncUserAuthkey = new RandomString(40).nextString();
|
||||||
|
syncInformation.baseUrl = preferenceManager.getServerUrl();
|
||||||
|
syncInformation.syncUserPassword = "abcdefghijklmnop";
|
||||||
|
|
||||||
|
uploadInformation = new UploadInformation(syncInformation);
|
||||||
|
|
||||||
|
// encrypt serialized content
|
||||||
|
String encrypted = diffieHellman.encrypt(new Gson().toJson(syncInformation));
|
||||||
|
|
||||||
|
// Generate QR code
|
||||||
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
QrCodeGenerator qrCodeGenerator = new QrCodeGenerator(this);
|
||||||
Gson gson = new Gson();
|
|
||||||
|
|
||||||
// my organisation
|
|
||||||
Organisation org = preferenceManager.getUserOrganisation();
|
|
||||||
User user = preferenceManager.getUserInfo();
|
|
||||||
|
|
||||||
Server server = new Server(
|
|
||||||
"SyncServer for " + org.name,
|
|
||||||
preferenceManager.getServerUrl(),
|
|
||||||
new RandomString(40).nextString(),
|
|
||||||
-1
|
|
||||||
);
|
|
||||||
|
|
||||||
MispServer mispServer = new MispServer(server, org, null);
|
|
||||||
|
|
||||||
SyncInformation syncInformation = new SyncInformation(user, org, server);
|
|
||||||
String encrypted = aesSecurity.encrypt(gson.toJson(syncInformation));
|
|
||||||
|
|
||||||
final Bitmap bm = qrCodeGenerator.generateQrCode(encrypted);
|
final Bitmap bm = qrCodeGenerator.generateQrCode(encrypted);
|
||||||
|
|
||||||
runOnUiThread(new Runnable() {
|
runOnUiThread(new Runnable() {
|
||||||
|
@ -249,61 +366,19 @@ public class SyncActivity extends AppCompatActivity {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPartnerOrg(Organisation organisation) {
|
// /**
|
||||||
restClient.addOrganisation(organisation, new MispRestClient.OrganisationCallback() {
|
// * Display toast on UI thread.
|
||||||
@Override
|
// *
|
||||||
public void success(Organisation organisation) {
|
// * @param message message to display
|
||||||
|
// */
|
||||||
}
|
// private void MakeToast(final String message) {
|
||||||
|
// this.runOnUiThread(new Runnable() {
|
||||||
@Override
|
// @Override
|
||||||
public void failure(String error) {
|
// public void run() {
|
||||||
|
// Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
private void addSyncUser(User user) {
|
|
||||||
restClient.addUser(user, new MispRestClient.UserCallback() {
|
|
||||||
@Override
|
|
||||||
public void success(User user) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failure(String error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addServer(MispServer server) {
|
|
||||||
restClient.addServer(server, new MispRestClient.ServerCallback() {
|
|
||||||
@Override
|
|
||||||
public void success(List<MispServer> servers) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void success(MispServer server) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void failure(String error) {
|
|
||||||
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void MakeToast(final String message) {
|
|
||||||
this.runOnUiThread(new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// private View.OnClickListener onGetServers = new View.OnClickListener() {
|
// private View.OnClickListener onGetServers = new View.OnClickListener() {
|
||||||
// @Override
|
// @Override
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
package lu.circl.mispbump.adapters;
|
||||||
|
|
||||||
|
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.Button;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import lu.circl.mispbump.R;
|
||||||
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
|
|
||||||
|
public class SyncAdapter extends RecyclerView.Adapter<SyncAdapter.SyncViewHolder> {
|
||||||
|
|
||||||
|
private List<UploadInformation> uploadInformationList;
|
||||||
|
|
||||||
|
static class SyncViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
TextView title, status;
|
||||||
|
ImageButton retry, delete;
|
||||||
|
|
||||||
|
SyncViewHolder(View v) {
|
||||||
|
super(v);
|
||||||
|
|
||||||
|
title = v.findViewById(R.id.title);
|
||||||
|
status = v.findViewById(R.id.syncStatus);
|
||||||
|
|
||||||
|
retry = v.findViewById(R.id.retry_button);
|
||||||
|
delete = v.findViewById(R.id.delete_button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyncAdapter(List<UploadInformation> uploadInformationList) {
|
||||||
|
this.uploadInformationList = uploadInformationList;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public SyncViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
|
||||||
|
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.viewholder_sync, viewGroup, false);
|
||||||
|
return new SyncViewHolder(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull SyncViewHolder syncViewHolder, int i) {
|
||||||
|
syncViewHolder.title.setText(uploadInformationList.get(i).remote.organisation.name);
|
||||||
|
|
||||||
|
switch (uploadInformationList.get(i).currentSyncStatus) {
|
||||||
|
case COMPLETE:
|
||||||
|
syncViewHolder.status.setText("Synced");
|
||||||
|
syncViewHolder.retry.setVisibility(View.GONE);
|
||||||
|
break;
|
||||||
|
case FAILURE:
|
||||||
|
syncViewHolder.status.setText("Error");
|
||||||
|
syncViewHolder.retry.setVisibility(View.VISIBLE);
|
||||||
|
break;
|
||||||
|
case PENDING:
|
||||||
|
syncViewHolder.status.setText("Pending");
|
||||||
|
syncViewHolder.retry.setVisibility(View.GONE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (uploadInformationList == null) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return uploadInformationList.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -5,7 +5,11 @@ import android.app.AlertDialog;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.DialogInterface;
|
import android.content.DialogInterface;
|
||||||
|
|
||||||
|
import java.security.PublicKey;
|
||||||
|
|
||||||
import lu.circl.mispbump.R;
|
import lu.circl.mispbump.R;
|
||||||
|
import lu.circl.mispbump.models.SyncInformation;
|
||||||
|
import lu.circl.mispbump.security.DiffieHellman;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and show dialogs.
|
* Creates and show dialogs.
|
||||||
|
@ -20,22 +24,61 @@ public class DialogManager {
|
||||||
* @param context needed to build and show the dialog
|
* @param context needed to build and show the dialog
|
||||||
* @param callback {@link IDialogFeedback}
|
* @param callback {@link IDialogFeedback}
|
||||||
*/
|
*/
|
||||||
public static void publicKeyDialog(String publicKey, Context context, final IDialogFeedback callback) {
|
public static void publicKeyDialog(PublicKey publicKey, Context context, final IDialogFeedback callback) {
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
adb.setTitle("Public Key Received");
|
adb.setTitle("Public Key");
|
||||||
adb.setMessage(publicKey);
|
|
||||||
|
String message = "Algorithm: " + publicKey.getAlgorithm() + "\n" +
|
||||||
|
"Format: " + publicKey.getFormat() + "\n" +
|
||||||
|
"Content: \n" + DiffieHellman.publicKeyToString(publicKey);
|
||||||
|
|
||||||
|
adb.setMessage(message);
|
||||||
|
adb.setPositiveButton("Okay", new DialogInterface.OnClickListener() {
|
||||||
|
@Override
|
||||||
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
|
callback.positive();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Activity act = (Activity) context;
|
||||||
|
|
||||||
|
act.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
adb.create().show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dialog to display a received public key.
|
||||||
|
*
|
||||||
|
* @param syncInformation {@link SyncInformation}
|
||||||
|
* @param context needed to build and show the dialog
|
||||||
|
* @param callback {@link IDialogFeedback}
|
||||||
|
*/
|
||||||
|
public static void syncInformationDialog(SyncInformation syncInformation, Context context, final IDialogFeedback callback) {
|
||||||
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
|
adb.setTitle("Sync information received");
|
||||||
|
adb.setMessage(syncInformation.organisation.name);
|
||||||
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
adb.setPositiveButton("Accept", new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
callback.positive();
|
callback.positive();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
adb.setNegativeButton("Reject", new DialogInterface.OnClickListener() {
|
adb.setNegativeButton("Reject", new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
callback.negative();
|
callback.negative();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Activity act = (Activity) context;
|
Activity act = (Activity) context;
|
||||||
|
@ -56,24 +99,27 @@ public class DialogManager {
|
||||||
*/
|
*/
|
||||||
public static void confirmProceedDialog(Context context, final IDialogFeedback callback) {
|
public static void confirmProceedDialog(Context context, final IDialogFeedback callback) {
|
||||||
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
final AlertDialog.Builder adb = new AlertDialog.Builder(context);
|
||||||
adb.setTitle("Really continue?");
|
adb.setTitle("Continue?");
|
||||||
adb.setMessage("Was this QR Code already scanned by your partner?");
|
adb.setMessage("Only continue if your partner already scanned this QR code");
|
||||||
adb.setPositiveButton("Yes, continue", new DialogInterface.OnClickListener() {
|
adb.setPositiveButton("Continue", new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
callback.positive();
|
callback.positive();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
adb.setNegativeButton("No, show QR Code", new DialogInterface.OnClickListener() {
|
adb.setNegativeButton("Show QR code again", new DialogInterface.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
public void onClick(DialogInterface dialog, int which) {
|
public void onClick(DialogInterface dialog, int which) {
|
||||||
|
if (callback != null) {
|
||||||
callback.negative();
|
callback.negative();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Activity act = (Activity) context;
|
Activity act = (Activity) context;
|
||||||
|
|
||||||
act.runOnUiThread(new Runnable() {
|
act.runOnUiThread(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
|
|
@ -2,10 +2,13 @@ package lu.circl.mispbump.auxiliary;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
import java.security.InvalidAlgorithmParameterException;
|
import java.security.InvalidAlgorithmParameterException;
|
||||||
import java.security.InvalidKeyException;
|
import java.security.InvalidKeyException;
|
||||||
import java.security.Key;
|
import java.security.Key;
|
||||||
|
@ -13,17 +16,23 @@ import java.security.KeyStore;
|
||||||
import java.security.KeyStoreException;
|
import java.security.KeyStoreException;
|
||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
import javax.crypto.IllegalBlockSizeException;
|
import javax.crypto.IllegalBlockSizeException;
|
||||||
import javax.crypto.NoSuchPaddingException;
|
import javax.crypto.NoSuchPaddingException;
|
||||||
|
|
||||||
|
import lu.circl.mispbump.models.UploadInformation;
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
import lu.circl.mispbump.restful_client.User;
|
import lu.circl.mispbump.restful_client.User;
|
||||||
import lu.circl.mispbump.security.KeyStoreWrapper;
|
import lu.circl.mispbump.security.KeyStoreWrapper;
|
||||||
|
|
||||||
|
import static android.support.constraint.Constraints.TAG;
|
||||||
|
|
||||||
public class PreferenceManager {
|
public class PreferenceManager {
|
||||||
|
|
||||||
|
private static final String TAG = "PreferenceManager";
|
||||||
|
|
||||||
private static final String PREFERENCES_FILE = "user_settings";
|
private static final String PREFERENCES_FILE = "user_settings";
|
||||||
|
|
||||||
|
@ -34,6 +43,8 @@ public class PreferenceManager {
|
||||||
private static final String USER_INFOS = "user_infos";
|
private static final String USER_INFOS = "user_infos";
|
||||||
private static final String USER_ORG_INFOS = "user_org_infos";
|
private static final String USER_ORG_INFOS = "user_org_infos";
|
||||||
|
|
||||||
|
private static final String UPLOAD_INFO = "upload_info";
|
||||||
|
|
||||||
private SharedPreferences preferences;
|
private SharedPreferences preferences;
|
||||||
private static PreferenceManager instance;
|
private static PreferenceManager instance;
|
||||||
|
|
||||||
|
@ -59,7 +70,7 @@ public class PreferenceManager {
|
||||||
/**
|
/**
|
||||||
* Saves user infos from "users/view/me" (encrypted)
|
* Saves user infos from "users/view/me" (encrypted)
|
||||||
*
|
*
|
||||||
* @param user
|
* @param user {@link User}
|
||||||
*/
|
*/
|
||||||
public void setUserInfo(User user) {
|
public void setUserInfo(User user) {
|
||||||
try {
|
try {
|
||||||
|
@ -178,7 +189,7 @@ public class PreferenceManager {
|
||||||
/**
|
/**
|
||||||
* Encrypts the automation key and stores it in preferences.
|
* Encrypts the automation key and stores it in preferences.
|
||||||
*
|
*
|
||||||
* @param automationKey
|
* @param automationKey key entered in {@link lu.circl.mispbump.activities.LoginActivity}
|
||||||
*/
|
*/
|
||||||
public void setAutomationKey(String automationKey) {
|
public void setAutomationKey(String automationKey) {
|
||||||
try {
|
try {
|
||||||
|
@ -202,7 +213,8 @@ public class PreferenceManager {
|
||||||
/**
|
/**
|
||||||
* Decrypts the stored automation key and returns it.
|
* Decrypts the stored automation key and returns it.
|
||||||
*
|
*
|
||||||
* @return the decr
|
* @return decrypted automation key associated with the current user. If no user exists an empty
|
||||||
|
* String is returned.
|
||||||
*/
|
*/
|
||||||
public String getAutomationKey() {
|
public String getAutomationKey() {
|
||||||
|
|
||||||
|
@ -316,6 +328,37 @@ public class PreferenceManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void setUploadInformation(UploadInformation uploadInformation) {
|
||||||
|
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, "");
|
||||||
|
|
||||||
|
Type type = new TypeToken<List<UploadInformation>>() {}.getType();
|
||||||
|
List<UploadInformation> dataList;
|
||||||
|
|
||||||
|
if (storedUploadInfoString.isEmpty()) {
|
||||||
|
dataList = new ArrayList<>();
|
||||||
|
} else {
|
||||||
|
dataList = new Gson().fromJson(storedUploadInfoString, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
dataList.add(uploadInformation);
|
||||||
|
|
||||||
|
SharedPreferences.Editor editor = preferences.edit();
|
||||||
|
editor.putString(UPLOAD_INFO, new Gson().toJson(dataList));
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<UploadInformation> getUploadInformation() {
|
||||||
|
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, "");
|
||||||
|
|
||||||
|
if (storedUploadInfoString.isEmpty()) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
Type type = new TypeToken<List<UploadInformation>>() {}.getType();
|
||||||
|
return new Gson().fromJson(storedUploadInfoString, type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set if credentials (authkey & server url) should be saved locally.
|
* Set if credentials (authkey & server url) should be saved locally.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package lu.circl.mispbump.models;
|
package lu.circl.mispbump.models;
|
||||||
|
|
||||||
import lu.circl.mispbump.restful_client.Organisation;
|
import lu.circl.mispbump.restful_client.Organisation;
|
||||||
import lu.circl.mispbump.restful_client.Server;
|
|
||||||
import lu.circl.mispbump.restful_client.User;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Class that holds the information needed synchronize two misp instances.
|
* A Class that holds the information needed synchronize two misp instances.
|
||||||
|
@ -10,13 +8,10 @@ import lu.circl.mispbump.restful_client.User;
|
||||||
*/
|
*/
|
||||||
public class SyncInformation {
|
public class SyncInformation {
|
||||||
|
|
||||||
public User user;
|
|
||||||
public Organisation organisation;
|
public Organisation organisation;
|
||||||
public Server server;
|
public String syncUserPassword;
|
||||||
|
public String syncUserAuthkey;
|
||||||
|
public String baseUrl;
|
||||||
|
|
||||||
public SyncInformation(User user, Organisation organisation, Server server) {
|
public SyncInformation() {}
|
||||||
this.user = user;
|
|
||||||
this.organisation = organisation;
|
|
||||||
this.server = server;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
package lu.circl.mispbump.models;
|
||||||
|
|
||||||
|
public class UploadInformation {
|
||||||
|
|
||||||
|
public enum SyncStatus {
|
||||||
|
COMPLETE,
|
||||||
|
FAILURE,
|
||||||
|
PENDING
|
||||||
|
}
|
||||||
|
|
||||||
|
public SyncStatus currentSyncStatus = SyncStatus.PENDING;
|
||||||
|
public SyncInformation local;
|
||||||
|
public SyncInformation remote;
|
||||||
|
|
||||||
|
public UploadInformation() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadInformation(SyncInformation local) {
|
||||||
|
this.local = local;
|
||||||
|
}
|
||||||
|
|
||||||
|
public UploadInformation(SyncInformation local, SyncInformation remote) {
|
||||||
|
this.local = local;
|
||||||
|
this.remote = remote;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2,9 +2,18 @@ package lu.circl.mispbump.restful_client;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.net.ssl.HostnameVerifier;
|
import javax.net.ssl.HostnameVerifier;
|
||||||
|
@ -18,6 +27,7 @@ import lu.circl.mispbump.auxiliary.PreferenceManager;
|
||||||
import okhttp3.Interceptor;
|
import okhttp3.Interceptor;
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
import okhttp3.Request;
|
import okhttp3.Request;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import okhttp3.logging.HttpLoggingInterceptor;
|
import okhttp3.logging.HttpLoggingInterceptor;
|
||||||
import retrofit2.Call;
|
import retrofit2.Call;
|
||||||
import retrofit2.Callback;
|
import retrofit2.Callback;
|
||||||
|
@ -31,6 +41,13 @@ import retrofit2.converter.gson.GsonConverterFactory;
|
||||||
*/
|
*/
|
||||||
public class MispRestClient {
|
public class MispRestClient {
|
||||||
|
|
||||||
|
private static final String TAG = "restClient";
|
||||||
|
|
||||||
|
public interface AvailableCallback {
|
||||||
|
void available();
|
||||||
|
void unavailable();
|
||||||
|
}
|
||||||
|
|
||||||
public interface UserCallback {
|
public interface UserCallback {
|
||||||
void success(User user);
|
void success(User user);
|
||||||
void failure(String error);
|
void failure(String error);
|
||||||
|
@ -44,6 +61,7 @@ public class MispRestClient {
|
||||||
public interface ServerCallback {
|
public interface ServerCallback {
|
||||||
void success(List<MispServer> servers);
|
void success(List<MispServer> servers);
|
||||||
void success(MispServer server);
|
void success(MispServer server);
|
||||||
|
void success(Server server);
|
||||||
void failure(String error);
|
void failure(String error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,9 +76,13 @@ public class MispRestClient {
|
||||||
public MispRestClient(Context context) {
|
public MispRestClient(Context context) {
|
||||||
preferenceManager = PreferenceManager.getInstance(context);
|
preferenceManager = PreferenceManager.getInstance(context);
|
||||||
|
|
||||||
|
String url = preferenceManager.getServerUrl();
|
||||||
|
|
||||||
|
Log.i(TAG, "URL: " + url);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Retrofit retrofit = new Retrofit.Builder()
|
Retrofit retrofit = new Retrofit.Builder()
|
||||||
.baseUrl(preferenceManager.getServerUrl())
|
.baseUrl(url)
|
||||||
.addConverterFactory(GsonConverterFactory.create())
|
.addConverterFactory(GsonConverterFactory.create())
|
||||||
.client(getUnsafeOkHttpClient())
|
.client(getUnsafeOkHttpClient())
|
||||||
.build();
|
.build();
|
||||||
|
@ -137,11 +159,41 @@ public class MispRestClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// status routes
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check via pyMispRoute if server is available
|
||||||
|
* @param callback {@link AvailableCallback}
|
||||||
|
*/
|
||||||
|
public void isAvailable(final AvailableCallback callback) {
|
||||||
|
Call<Version> call = mispRestService.pyMispVersion();
|
||||||
|
call.enqueue(new Callback<Version>() {
|
||||||
|
@Override
|
||||||
|
public void onResponse(Call<Version> call, Response<Version> response) {
|
||||||
|
if (!response.isSuccessful()) {
|
||||||
|
if (response.code() == 403) {
|
||||||
|
callback.available();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
callback.unavailable();
|
||||||
|
} else {
|
||||||
|
callback.available();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onFailure(Call<Version> call, Throwable t) {
|
||||||
|
callback.unavailable();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// user routes
|
// user routes
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetches information about the user that is associated with saved auth key.
|
* Fetches information about the user that is associated with saved auth key.
|
||||||
* @param callback wrapper to return a user directly
|
* @param callback {@link UserCallback} wrapper to return user directly
|
||||||
*/
|
*/
|
||||||
public void getMyUser(final UserCallback callback) {
|
public void getMyUser(final UserCallback callback) {
|
||||||
Call<MispUser> call = mispRestService.getMyUserInformation();
|
Call<MispUser> call = mispRestService.getMyUserInformation();
|
||||||
|
@ -150,7 +202,7 @@ public class MispRestClient {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if(!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
callback.success(response.body().user);
|
callback.success(response.body().user);
|
||||||
|
@ -171,7 +223,7 @@ public class MispRestClient {
|
||||||
/**
|
/**
|
||||||
* Get an user with specific ID.
|
* Get an user with specific ID.
|
||||||
* @param userId user identifier
|
* @param userId user identifier
|
||||||
* @param callback wrapper to return user directly
|
* @param callback {@link UserCallback} wrapper to return user directly
|
||||||
*/
|
*/
|
||||||
public void getUser(int userId, final UserCallback callback) {
|
public void getUser(int userId, final UserCallback callback) {
|
||||||
Call<MispUser> call = mispRestService.getUser(userId);
|
Call<MispUser> call = mispRestService.getUser(userId);
|
||||||
|
@ -180,7 +232,7 @@ public class MispRestClient {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if(!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
callback.success(response.body().user);
|
callback.success(response.body().user);
|
||||||
|
@ -201,7 +253,7 @@ public class MispRestClient {
|
||||||
/**
|
/**
|
||||||
* Add a given user to the MISP instance referenced by url in preferences.
|
* Add a given user to the MISP instance referenced by url in preferences.
|
||||||
* @param user user to add
|
* @param user user to add
|
||||||
* @param callback wrapper to return the created user directly
|
* @param callback {@link UserCallback} wrapper to return the created user directly
|
||||||
*/
|
*/
|
||||||
public void addUser(User user, final UserCallback callback) {
|
public void addUser(User user, final UserCallback callback) {
|
||||||
Call<MispUser> call = mispRestService.addUser(user);
|
Call<MispUser> call = mispRestService.addUser(user);
|
||||||
|
@ -209,13 +261,12 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispUser>() {
|
call.enqueue(new Callback<MispUser>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
public void onResponse(Call<MispUser> call, Response<MispUser> response) {
|
||||||
if (!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
callback.success(response.body().user);
|
callback.success(response.body().user);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<MispUser> call, Throwable t) {
|
public void onFailure(Call<MispUser> call, Throwable t) {
|
||||||
|
@ -230,7 +281,7 @@ public class MispRestClient {
|
||||||
/**
|
/**
|
||||||
* Get an organisation by a given organisation id.
|
* Get an organisation by a given organisation id.
|
||||||
* @param orgId organisation identifier
|
* @param orgId organisation identifier
|
||||||
* @param callback wrapper to return a organisation directly
|
* @param callback {@link OrganisationCallback} wrapper to return a organisation directly
|
||||||
*/
|
*/
|
||||||
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
public void getOrganisation(int orgId, final OrganisationCallback callback) {
|
||||||
Call<MispOrganisation> call = mispRestService.getOrganisation(orgId);
|
Call<MispOrganisation> call = mispRestService.getOrganisation(orgId);
|
||||||
|
@ -239,7 +290,7 @@ public class MispRestClient {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
||||||
if(!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
} else {
|
} else {
|
||||||
if (response.body() != null) {
|
if (response.body() != null) {
|
||||||
callback.success(response.body().organisation);
|
callback.success(response.body().organisation);
|
||||||
|
@ -259,7 +310,7 @@ public class MispRestClient {
|
||||||
/**
|
/**
|
||||||
* Add a given organisation to the MISP instance referenced by url in preferences.
|
* Add a given organisation to the MISP instance referenced by url in preferences.
|
||||||
* @param organisation organisation to add
|
* @param organisation organisation to add
|
||||||
* @param callback wrapper to return the created organisation directly
|
* @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
|
||||||
*/
|
*/
|
||||||
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
|
||||||
Call<MispOrganisation> call = mispRestService.addOrganisation(organisation);
|
Call<MispOrganisation> call = mispRestService.addOrganisation(organisation);
|
||||||
|
@ -267,13 +318,12 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<MispOrganisation>() {
|
call.enqueue(new Callback<MispOrganisation>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
public void onResponse(Call<MispOrganisation> call, Response<MispOrganisation> response) {
|
||||||
if (!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
callback.success(response.body().organisation);
|
callback.success(response.body().organisation);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<MispOrganisation> call, Throwable t) {
|
public void onFailure(Call<MispOrganisation> call, Throwable t) {
|
||||||
|
@ -286,7 +336,7 @@ public class MispRestClient {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all servers on MISP instance.
|
* Get all servers on MISP instance.
|
||||||
* @param callback wrapper to return a list of servers directly
|
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
|
||||||
*/
|
*/
|
||||||
public void getServers(final ServerCallback callback) {
|
public void getServers(final ServerCallback callback) {
|
||||||
Call<List<MispServer>> call = mispRestService.getServers();
|
Call<List<MispServer>> call = mispRestService.getServers();
|
||||||
|
@ -294,13 +344,12 @@ public class MispRestClient {
|
||||||
call.enqueue(new Callback<List<MispServer>>() {
|
call.enqueue(new Callback<List<MispServer>>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
|
public void onResponse(Call<List<MispServer>> call, Response<List<MispServer>> response) {
|
||||||
if (!response.isSuccessful()) {
|
if(!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
callback.success(response.body());
|
callback.success(response.body());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<List<MispServer>> call, Throwable t) {
|
public void onFailure(Call<List<MispServer>> call, Throwable t) {
|
||||||
|
@ -312,26 +361,87 @@ public class MispRestClient {
|
||||||
/**
|
/**
|
||||||
* Add a server to the MISP instance
|
* Add a server to the MISP instance
|
||||||
* @param server the server to create
|
* @param server the server to create
|
||||||
* @param callback wrapper to return the created server directly
|
* @param callback {@link ServerCallback} wrapper to return the created server directly
|
||||||
*/
|
*/
|
||||||
public void addServer(MispServer server, final ServerCallback callback) {
|
// public void addServer(MispServer server, final ServerCallback callback) {
|
||||||
Call<MispServer> call = mispRestService.addServer(server);
|
// Call<MispServer> call = mispRestService.addServer(server);
|
||||||
|
//
|
||||||
|
// call.enqueue(new Callback<MispServer>() {
|
||||||
|
// @Override
|
||||||
|
// public void onResponse(Call<MispServer> call, Response<MispServer> response) {
|
||||||
|
// if(!response.isSuccessful()) {
|
||||||
|
// callback.failure(extractError(response));
|
||||||
|
// } else {
|
||||||
|
// callback.success(response.body());
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// @Override
|
||||||
|
// public void onFailure(Call<MispServer> call, Throwable t) {
|
||||||
|
// callback.failure(t.getMessage());
|
||||||
|
// }
|
||||||
|
// });
|
||||||
|
// }
|
||||||
|
|
||||||
call.enqueue(new Callback<MispServer>() {
|
public void addServer(Server server, final ServerCallback callback) {
|
||||||
|
Call<Server> call = mispRestService.addServer(server);
|
||||||
|
|
||||||
|
call.enqueue(new Callback<Server>() {
|
||||||
@Override
|
@Override
|
||||||
public void onResponse(Call<MispServer> call, Response<MispServer> response) {
|
public void onResponse(Call<Server> call, Response<Server> response) {
|
||||||
if (!response.isSuccessful()) {
|
if (!response.isSuccessful()) {
|
||||||
callback.failure("" + response.code());
|
callback.failure(extractError(response));
|
||||||
return;
|
} else {
|
||||||
}
|
|
||||||
|
|
||||||
callback.success(response.body());
|
callback.success(response.body());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onFailure(Call<MispServer> call, Throwable t) {
|
public void onFailure(Call<Server> call, Throwable t) {
|
||||||
callback.failure(t.getMessage());
|
callback.failure(t.getMessage());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T> String extractError(Response<T> response) {
|
||||||
|
switch (response.code()) {
|
||||||
|
// bad request (malformed)
|
||||||
|
case 400:
|
||||||
|
return "Bad request";
|
||||||
|
|
||||||
|
// unauthorized
|
||||||
|
case 401:
|
||||||
|
return "Unauthorized";
|
||||||
|
|
||||||
|
// forbidden
|
||||||
|
case 403:
|
||||||
|
try {
|
||||||
|
JSONObject jsonError = new JSONObject(response.errorBody().string());
|
||||||
|
|
||||||
|
String name = jsonError.getString("name") + "\n";
|
||||||
|
String reasons = "";
|
||||||
|
JSONObject errorReasons = jsonError.getJSONObject("errors");
|
||||||
|
|
||||||
|
Iterator<String> errorKeys = errorReasons.keys();
|
||||||
|
|
||||||
|
while (errorKeys.hasNext()) {
|
||||||
|
reasons = reasons.concat(errorReasons.getString(errorKeys.next()) + "\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return name + reasons;
|
||||||
|
} catch (JSONException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Could not parse (403) error";
|
||||||
|
|
||||||
|
// not found
|
||||||
|
case 404:
|
||||||
|
return "Not found";
|
||||||
|
}
|
||||||
|
|
||||||
|
return "Unknown error";
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -13,6 +13,11 @@ import retrofit2.http.Path;
|
||||||
*/
|
*/
|
||||||
public interface MispRestService {
|
public interface MispRestService {
|
||||||
|
|
||||||
|
// settings routes
|
||||||
|
|
||||||
|
@GET("servers/getPyMISPVersion")
|
||||||
|
Call<Version> pyMispVersion();
|
||||||
|
|
||||||
// user routes
|
// user routes
|
||||||
|
|
||||||
@GET("users/view/me")
|
@GET("users/view/me")
|
||||||
|
@ -37,6 +42,9 @@ public interface MispRestService {
|
||||||
@GET("servers/index")
|
@GET("servers/index")
|
||||||
Call<List<MispServer>> getServers();
|
Call<List<MispServer>> getServers();
|
||||||
|
|
||||||
|
// @POST("servers/add")
|
||||||
|
// Call<MispServer> addServer(@Body MispServer server);
|
||||||
|
|
||||||
@POST("servers/add")
|
@POST("servers/add")
|
||||||
Call<MispServer> addServer(@Body MispServer server);
|
Call<Server> addServer(@Body Server server);
|
||||||
}
|
}
|
|
@ -6,6 +6,8 @@ import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
public class MispServer {
|
public class MispServer {
|
||||||
|
|
||||||
|
public MispServer() {}
|
||||||
|
|
||||||
public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
|
public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
|
||||||
this.server = server;
|
this.server = server;
|
||||||
this.organisation = organisation;
|
this.organisation = organisation;
|
||||||
|
|
|
@ -1,13 +1,13 @@
|
||||||
package lu.circl.mispbump.restful_client;
|
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.
|
* Information gathered from Misp API about a organisation.
|
||||||
*/
|
*/
|
||||||
public class Organisation {
|
public class Organisation {
|
||||||
|
|
||||||
|
public Organisation() {
|
||||||
|
}
|
||||||
|
|
||||||
public Organisation(String name) {
|
public Organisation(String name) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
}
|
}
|
||||||
|
@ -17,49 +17,35 @@ public class Organisation {
|
||||||
this.description = description;
|
this.description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
@SerializedName("id")
|
|
||||||
@Expose
|
|
||||||
public Integer id;
|
public Integer id;
|
||||||
@SerializedName("name")
|
|
||||||
@Expose
|
|
||||||
public String name;
|
public String name;
|
||||||
@SerializedName("date_created")
|
|
||||||
@Expose
|
|
||||||
public String date_created;
|
public String date_created;
|
||||||
@SerializedName("date_modified")
|
|
||||||
@Expose
|
|
||||||
public String date_modified;
|
public String date_modified;
|
||||||
@SerializedName("type")
|
|
||||||
@Expose
|
|
||||||
public String type;
|
public String type;
|
||||||
@SerializedName("nationality")
|
|
||||||
@Expose
|
|
||||||
public String nationality;
|
public String nationality;
|
||||||
@SerializedName("sector")
|
|
||||||
@Expose
|
|
||||||
public String sector;
|
public String sector;
|
||||||
@SerializedName("contacts")
|
|
||||||
@Expose
|
|
||||||
public String contacts;
|
public String contacts;
|
||||||
@SerializedName("description")
|
|
||||||
@Expose
|
|
||||||
public String description;
|
public String description;
|
||||||
@SerializedName("local")
|
|
||||||
@Expose
|
|
||||||
public Boolean local;
|
public Boolean local;
|
||||||
@SerializedName("uuid")
|
|
||||||
@Expose
|
|
||||||
public String uuid;
|
public String uuid;
|
||||||
@SerializedName("restricted_to_domain")
|
|
||||||
@Expose
|
|
||||||
public String restricted_to_domain;
|
public String restricted_to_domain;
|
||||||
@SerializedName("created_by")
|
|
||||||
@Expose
|
|
||||||
public String created_by;
|
public String created_by;
|
||||||
@SerializedName("user_count")
|
|
||||||
@Expose
|
|
||||||
public Integer user_count;
|
public Integer user_count;
|
||||||
|
|
||||||
|
public Organisation syncOrganisation() {
|
||||||
|
Organisation organisation = new Organisation();
|
||||||
|
organisation.local = true;
|
||||||
|
organisation.name = name;
|
||||||
|
organisation.uuid = uuid;
|
||||||
|
organisation.description = description;
|
||||||
|
organisation.nationality = nationality;
|
||||||
|
organisation.sector = sector;
|
||||||
|
organisation.type = "Sync organisation";
|
||||||
|
organisation.contacts = contacts;
|
||||||
|
|
||||||
|
return organisation;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Organisation{" +
|
return "Organisation{" +
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package lu.circl.mispbump.restful_client;
|
package lu.circl.mispbump.restful_client;
|
||||||
|
|
||||||
import com.google.gson.annotations.Expose;
|
|
||||||
import com.google.gson.annotations.SerializedName;
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
public class Server {
|
public class Server {
|
||||||
|
|
||||||
|
public Server() {}
|
||||||
|
|
||||||
public Server(String name, String url, String authkey, Integer remote_org_id) {
|
public Server(String name, String url, String authkey, Integer remote_org_id) {
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.url = url;
|
this.url = url;
|
||||||
|
@ -13,91 +14,69 @@ public class Server {
|
||||||
}
|
}
|
||||||
|
|
||||||
@SerializedName("id")
|
@SerializedName("id")
|
||||||
@Expose
|
|
||||||
public Integer id;
|
public Integer id;
|
||||||
|
|
||||||
@SerializedName("name")
|
@SerializedName("name")
|
||||||
@Expose
|
|
||||||
public String name;
|
public String name;
|
||||||
|
|
||||||
@SerializedName("url")
|
@SerializedName("url")
|
||||||
@Expose
|
|
||||||
public String url;
|
public String url;
|
||||||
|
|
||||||
@SerializedName("authkey")
|
@SerializedName("authkey")
|
||||||
@Expose
|
|
||||||
public String authkey;
|
public String authkey;
|
||||||
|
|
||||||
@SerializedName("org_id")
|
@SerializedName("org_id")
|
||||||
@Expose
|
|
||||||
public Integer org_id;
|
public Integer org_id;
|
||||||
|
|
||||||
@SerializedName("push")
|
@SerializedName("push")
|
||||||
@Expose
|
|
||||||
public Boolean push;
|
public Boolean push;
|
||||||
|
|
||||||
@SerializedName("pull")
|
@SerializedName("pull")
|
||||||
@Expose
|
|
||||||
public Boolean pull;
|
public Boolean pull;
|
||||||
|
|
||||||
@SerializedName("lastpulledid")
|
@SerializedName("lastpulledid")
|
||||||
@Expose
|
|
||||||
public Object lastpulledid;
|
public Object lastpulledid;
|
||||||
|
|
||||||
@SerializedName("lastpushedid")
|
@SerializedName("lastpushedid")
|
||||||
@Expose
|
|
||||||
public Object lastpushedid;
|
public Object lastpushedid;
|
||||||
|
|
||||||
@SerializedName("organization")
|
@SerializedName("organization")
|
||||||
@Expose
|
|
||||||
public Object organization;
|
public Object organization;
|
||||||
|
|
||||||
@SerializedName("remote_org_id")
|
@SerializedName("remote_org_id")
|
||||||
@Expose
|
|
||||||
public Integer remote_org_id;
|
public Integer remote_org_id;
|
||||||
|
|
||||||
@SerializedName("publish_without_email")
|
@SerializedName("publish_without_email")
|
||||||
@Expose
|
public Boolean publish_without_email = false;
|
||||||
public Boolean publish_without_email;
|
|
||||||
|
|
||||||
@SerializedName("unpublish_event")
|
@SerializedName("unpublish_event")
|
||||||
@Expose
|
|
||||||
public Boolean unpublish_event;
|
public Boolean unpublish_event;
|
||||||
|
|
||||||
@SerializedName("self_signed")
|
@SerializedName("self_signed")
|
||||||
@Expose
|
public Boolean self_signed = false;
|
||||||
public Boolean self_signed;
|
|
||||||
|
|
||||||
@SerializedName("pull_rules")
|
@SerializedName("pull_rules")
|
||||||
@Expose
|
|
||||||
public String pull_rules;
|
public String pull_rules;
|
||||||
|
|
||||||
@SerializedName("push_rules")
|
@SerializedName("push_rules")
|
||||||
@Expose
|
|
||||||
public String push_rules;
|
public String push_rules;
|
||||||
|
|
||||||
@SerializedName("cert_file")
|
@SerializedName("cert_file")
|
||||||
@Expose
|
|
||||||
public Object cert_file;
|
public Object cert_file;
|
||||||
|
|
||||||
@SerializedName("client_cert_file")
|
@SerializedName("client_cert_file")
|
||||||
@Expose
|
|
||||||
public Object client_cert_file;
|
public Object client_cert_file;
|
||||||
|
|
||||||
@SerializedName("internal")
|
@SerializedName("internal")
|
||||||
@Expose
|
|
||||||
public Boolean internal;
|
public Boolean internal;
|
||||||
|
|
||||||
@SerializedName("skip_proxy")
|
@SerializedName("skip_proxy")
|
||||||
@Expose
|
public Boolean skip_proxy = false;
|
||||||
public Boolean skip_proxy;
|
|
||||||
|
|
||||||
@SerializedName("caching_enabled")
|
@SerializedName("caching_enabled")
|
||||||
@Expose
|
|
||||||
public Boolean caching_enabled;
|
public Boolean caching_enabled;
|
||||||
|
|
||||||
@SerializedName("cache_timestamp")
|
@SerializedName("cache_timestamp")
|
||||||
@Expose
|
|
||||||
public Boolean cache_timestamp;
|
public Boolean cache_timestamp;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -12,6 +12,9 @@ public class User {
|
||||||
public static final int ROLE_SYNC_USER = 5;
|
public static final int ROLE_SYNC_USER = 5;
|
||||||
public static final int ROLE_READ_ONLY = 6;
|
public static final int ROLE_READ_ONLY = 6;
|
||||||
|
|
||||||
|
public User() {
|
||||||
|
}
|
||||||
|
|
||||||
public User(Integer org_id, String email, Integer role_id) {
|
public User(Integer org_id, String email, Integer role_id) {
|
||||||
this.org_id = org_id;
|
this.org_id = org_id;
|
||||||
this.email = email;
|
this.email = email;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
package lu.circl.mispbump.restful_client;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
|
||||||
|
public class Version {
|
||||||
|
|
||||||
|
@SerializedName("version")
|
||||||
|
public String version;
|
||||||
|
|
||||||
|
}
|
|
@ -12,9 +12,11 @@ import java.security.spec.InvalidKeySpecException;
|
||||||
import java.security.spec.X509EncodedKeySpec;
|
import java.security.spec.X509EncodedKeySpec;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class AESSecurity {
|
/**
|
||||||
|
* This class provides the functionality generate a shared secret key.
|
||||||
private static final String TAG = "MISP_LOGGING";
|
* Furthermore it contains the encryption/decryption methods.
|
||||||
|
*/
|
||||||
|
public class DiffieHellman {
|
||||||
|
|
||||||
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
|
private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
|
||||||
private static final String KEY_PAIR_ALGORITHM = "EC";
|
private static final String KEY_PAIR_ALGORITHM = "EC";
|
||||||
|
@ -22,7 +24,7 @@ public class AESSecurity {
|
||||||
private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
|
private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
|
||||||
private static final String KEY_FACTORY_ALGORITHM = "EC";
|
private static final String KEY_FACTORY_ALGORITHM = "EC";
|
||||||
|
|
||||||
private static AESSecurity instance;
|
private static DiffieHellman instance;
|
||||||
|
|
||||||
private PublicKey publickey;
|
private PublicKey publickey;
|
||||||
private KeyAgreement keyAgreement;
|
private KeyAgreement keyAgreement;
|
||||||
|
@ -30,14 +32,19 @@ public class AESSecurity {
|
||||||
private byte[] sharedSecret;
|
private byte[] sharedSecret;
|
||||||
private IvParameterSpec ivParameterSpec;
|
private IvParameterSpec ivParameterSpec;
|
||||||
|
|
||||||
private AESSecurity() {
|
private DiffieHellman() {
|
||||||
initialize();
|
initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AESSecurity getInstance() {
|
/**
|
||||||
|
* Singleton pattern
|
||||||
|
* @return {@link DiffieHellman}
|
||||||
|
*/
|
||||||
|
public static DiffieHellman getInstance() {
|
||||||
if(instance == null) {
|
if(instance == null) {
|
||||||
instance = new AESSecurity();
|
instance = new DiffieHellman();
|
||||||
}
|
}
|
||||||
|
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,7 +109,7 @@ public class AESSecurity {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decrypts data.
|
* Decrypts data with the current shared secret.
|
||||||
* @param data data to decrypt
|
* @param data data to decrypt
|
||||||
* @return To String converted and decrypted data
|
* @return To String converted and decrypted data
|
||||||
*/
|
*/
|
|
@ -16,6 +16,7 @@ import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.NoSuchProviderException;
|
import java.security.NoSuchProviderException;
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
import java.security.cert.CertificateException;
|
import java.security.cert.CertificateException;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
import javax.crypto.BadPaddingException;
|
import javax.crypto.BadPaddingException;
|
||||||
|
@ -172,11 +173,10 @@ public class KeyStoreWrapper {
|
||||||
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||||
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
cipher.init(Cipher.ENCRYPT_MODE, secretKey);
|
||||||
|
|
||||||
byte[] encryptedData = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));
|
byte[] byteData = data.getBytes(StandardCharsets.UTF_8);
|
||||||
String encryptedDataString = Base64.encodeToString(encryptedData, Base64.DEFAULT);
|
// byte[] byteData = Base64.decode(data, Base64.DEFAULT);
|
||||||
String ivString = Base64.encodeToString(cipher.getIV(), Base64.DEFAULT);
|
byte[] combined = getCombinedArray(cipher.getIV(), cipher.doFinal(byteData));
|
||||||
|
return Base64.encodeToString(combined, Base64.NO_WRAP);
|
||||||
return ivString + ":::" + encryptedDataString;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,17 +193,19 @@ public class KeyStoreWrapper {
|
||||||
public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
|
||||||
|
|
||||||
// extract iv from save data
|
// extract iv from save data
|
||||||
String[] parts = input.split(":::");
|
// String[] parts = input.split(":::");
|
||||||
|
// byte[] iv = Base64.decode(parts[0], Base64.DEFAULT);
|
||||||
|
// byte[] data = Base64.decode(parts[1], Base64.DEFAULT);
|
||||||
|
|
||||||
byte[] iv = Base64.decode(parts[0], Base64.DEFAULT);
|
byte[] in = Base64.decode(input, Base64.NO_WRAP);
|
||||||
byte[] data = Base64.decode(parts[1], Base64.DEFAULT);
|
IvAndData ivAndData = splitCombinedArray(in, 12);
|
||||||
|
|
||||||
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
|
||||||
final GCMParameterSpec gcmSpec = new GCMParameterSpec(128, iv);
|
final GCMParameterSpec gcmSpec = new GCMParameterSpec(128, ivAndData.iv);
|
||||||
|
|
||||||
cipher.init(Cipher.DECRYPT_MODE, getStoredKey(), gcmSpec);
|
cipher.init(Cipher.DECRYPT_MODE, getStoredKey(), gcmSpec);
|
||||||
|
|
||||||
return new String(cipher.doFinal(data), StandardCharsets.UTF_8);
|
return new String(cipher.doFinal(ivAndData.data), StandardCharsets.UTF_8);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -242,11 +244,33 @@ public class KeyStoreWrapper {
|
||||||
* @param encryptedData encrypted data
|
* @param encryptedData encrypted data
|
||||||
* @return combination of iv and encrypted data
|
* @return combination of iv and encrypted data
|
||||||
*/
|
*/
|
||||||
private static byte[] getCombinedArray(byte[] iv, byte[] encryptedData) {
|
private byte[] getCombinedArray(byte[] iv, byte[] encryptedData) {
|
||||||
|
|
||||||
|
Log.i(TAG, "iv length = " + iv.length);
|
||||||
|
|
||||||
byte[] combined = new byte[iv.length + encryptedData.length];
|
byte[] combined = new byte[iv.length + encryptedData.length];
|
||||||
for (int i = 0; i < combined.length; ++i) {
|
for (int i = 0; i < combined.length; ++i) {
|
||||||
combined[i] = i < iv.length ? iv[i] : encryptedData[i - iv.length];
|
combined[i] = i < iv.length ? iv[i] : encryptedData[i - iv.length];
|
||||||
}
|
}
|
||||||
return combined;
|
return combined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private IvAndData splitCombinedArray(byte[] input, int ivLength) {
|
||||||
|
byte[] iv = Arrays.copyOfRange(input, 0, ivLength);
|
||||||
|
byte[] data = Arrays.copyOfRange(input, ivLength, input.length);
|
||||||
|
return new IvAndData(iv, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
public class IvAndData {
|
||||||
|
|
||||||
|
public IvAndData() {}
|
||||||
|
|
||||||
|
public IvAndData(byte[] iv, byte[] data) {
|
||||||
|
this.iv = iv;
|
||||||
|
this.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] iv;
|
||||||
|
public byte[] data;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#B4B4B4"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M12,7L12,3L2,3v18h20L22,7L12,7zM6,19L4,19v-2h2v2zM6,15L4,15v-2h2v2zM6,11L4,11L4,9h2v2zM6,7L4,7L4,5h2v2zM10,19L8,19v-2h2v2zM10,15L8,15v-2h2v2zM10,11L8,11L8,9h2v2zM10,7L8,7L8,5h2v2zM20,19h-8v-2h2v-2h-2v-2h2v-2h-2L12,9h8v10zM18,11h-2v2h2v-2zM18,15h-2v2h2v-2z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M15,11L15,5l-3,-3 -3,3v2L3,7v14h18L21,11h-6zM7,19L5,19v-2h2v2zM7,15L5,15v-2h2v2zM7,11L5,11L5,9h2v2zM13,19h-2v-2h2v2zM13,15h-2v-2h2v2zM13,11h-2L11,9h2v2zM13,7h-2L11,5h2v2zM19,19h-2v-2h2v2zM19,15h-2v-2h2v2z"/>
|
||||||
|
</vector>
|
|
@ -1,4 +1,4 @@
|
||||||
<vector android:height="24dp" android:tint="#B4B4B4"
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
<path android:fillColor="#FF000000" android:pathData="M12,12c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4 -4,1.79 -4,4 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"/>
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
<vector android:height="24dp" android:tint="#FFFFFF"
|
||||||
|
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||||
|
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<path android:fillColor="#FF000000" android:pathData="M21.41,11.58l-9,-9C12.05,2.22 11.55,2 11,2H4c-1.1,0 -2,0.9 -2,2v7c0,0.55 0.22,1.05 0.59,1.42l9,9c0.36,0.36 0.86,0.58 1.41,0.58 0.55,0 1.05,-0.22 1.41,-0.59l7,-7c0.37,-0.36 0.59,-0.86 0.59,-1.41 0,-0.55 -0.23,-1.06 -0.59,-1.42zM5.5,7C4.67,7 4,6.33 4,5.5S4.67,4 5.5,4 7,4.67 7,5.5 6.33,7 5.5,7z"/>
|
||||||
|
</vector>
|
|
@ -0,0 +1,21 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="horizontal" >
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/actionbar_title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="center"
|
||||||
|
android:maxLines="1"
|
||||||
|
android:clickable="false"
|
||||||
|
android:focusable="false"
|
||||||
|
android:longClickable="false"
|
||||||
|
android:textStyle="bold"
|
||||||
|
android:textSize="18sp"
|
||||||
|
android:textColor="#FFFFFF" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
|
@ -1,119 +1,118 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.design.widget.CoordinatorLayout
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:id="@+id/layout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent">
|
||||||
tools:context=".activities.HomeActivity">
|
|
||||||
|
<android.support.design.widget.AppBarLayout
|
||||||
|
android:id="@+id/appbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<android.support.v7.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/toolbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
android:elevation="4dp"
|
android:elevation="0dp"
|
||||||
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
|
||||||
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
|
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
|
||||||
app:layout_constraintRight_toRightOf="parent"
|
|
||||||
app:layout_constraintLeft_toLeftOf="parent"/>
|
|
||||||
|
|
||||||
<android.support.v7.widget.CardView
|
|
||||||
android:id="@+id/cardView"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginStart="16dp"
|
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:contentPadding="8dp"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar">
|
|
||||||
|
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.constraint.ConstraintLayout
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingBottom="16dp">
|
||||||
|
|
||||||
<Button
|
<TextView
|
||||||
android:id="@+id/button"
|
android:id="@+id/user_count"
|
||||||
style="@style/Widget.MaterialComponents.Button"
|
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:fontFamily="sans-serif-medium"
|
android:gravity="center_vertical"
|
||||||
android:text="Remove"
|
android:textColor="#FFFFFF"
|
||||||
android:textAllCaps="true"
|
android:drawableStart="@drawable/ic_person"
|
||||||
android:textSize="14sp"
|
android:drawablePadding="4dp"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
|
app:layout_constraintEnd_toStartOf="@+id/sector"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
<Button
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
android:id="@+id/button2"
|
|
||||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="Update"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/button3"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/button3"
|
|
||||||
style="@style/Widget.AppCompat.Button.Borderless.Colored"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginEnd="8dp"
|
|
||||||
android:text="Details"
|
|
||||||
app:layout_constraintEnd_toStartOf="@+id/button"
|
|
||||||
app:layout_constraintTop_toBottomOf="@+id/home_org_image" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/home_org_image"
|
|
||||||
android:layout_width="40dp"
|
|
||||||
android:layout_height="40dp"
|
|
||||||
android:src="@drawable/ic_account_circle"
|
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="11" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="#55FFFFFF"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/sector"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/user_count"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/home_org_name"
|
android:id="@+id/sector"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="16dp"
|
||||||
android:textStyle="bold"
|
android:gravity="center_vertical"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
android:textColor="#FFFFFF"
|
||||||
app:layout_constraintStart_toEndOf="@id/home_org_image"
|
android:drawableStart="@drawable/ic_sector"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/nationality"
|
||||||
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/user_count"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Title" />
|
tools:text="Financial" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:layout_width="1dp"
|
||||||
|
android:layout_height="0dp"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="#55FFFFFF"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/nationality"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/sector"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/home_org_desc"
|
android:id="@+id/nationality"
|
||||||
android:layout_width="0dp"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="8dp"
|
android:layout_marginStart="16dp"
|
||||||
|
android:gravity="center_vertical"
|
||||||
|
android:textColor="#FFFFFF"
|
||||||
|
android:drawableStart="@drawable/ic_location"
|
||||||
|
android:drawablePadding="4dp"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintHorizontal_bias="1.0"
|
app:layout_constraintHorizontal_bias="0.5"
|
||||||
app:layout_constraintStart_toEndOf="@id/home_org_image"
|
app:layout_constraintStart_toEndOf="@+id/sector"
|
||||||
app:layout_constraintTop_toBottomOf="@id/home_org_name"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
tools:text="Description" />
|
tools:text="Germany" />
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
</android.support.design.widget.AppBarLayout>
|
||||||
|
|
||||||
</android.support.v7.widget.CardView>
|
<android.support.v7.widget.RecyclerView
|
||||||
|
android:id="@+id/recyclerView"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||||
|
|
||||||
|
</android.support.v7.widget.RecyclerView>
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/home_fab"
|
android:id="@+id/home_fab"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_gravity="bottom|end"
|
||||||
android:layout_marginBottom="16dp"
|
android:layout_margin="16dp"
|
||||||
android:clickable="true"
|
android:src="@drawable/ic_add" />
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_sync_black_24dp"
|
|
||||||
android:focusable="true" />
|
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
<android.support.constraint.ConstraintLayout
|
||||||
android:id="@+id/login_root"
|
android:id="@+id/layout"
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
@ -9,7 +9,7 @@
|
||||||
tools:context=".activities.LoginActivity">
|
tools:context=".activities.LoginActivity">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<android.support.v7.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
|
@ -89,7 +89,7 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
app:layout_constraintTop_toBottomOf="@+id/appbar" />
|
||||||
|
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.design.widget.CoordinatorLayout
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
<!--<android.support.design.widget.BottomNavigationView-->
|
||||||
|
<!--android:id="@+id/bottom_navigation"-->
|
||||||
|
<!--android:layout_width="match_parent"-->
|
||||||
|
<!--android:layout_height="56dp"-->
|
||||||
|
<!--android:layout_gravity="bottom"-->
|
||||||
|
<!--android:background="@color/colorPrimary"-->
|
||||||
|
<!--app:itemIconTint="#FFF"-->
|
||||||
|
<!--app:itemTextColor="#FFF"-->
|
||||||
|
<!--app:menu="@menu/menu_bottom_navigation" />-->
|
||||||
|
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -1,14 +1,16 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<android.support.constraint.ConstraintLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
<android.support.design.widget.CoordinatorLayout
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/layout"
|
||||||
|
tools:context=".activities.SyncActivity"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context=".activities.SyncActivity">
|
android:layout_width="match_parent">
|
||||||
|
|
||||||
<android.support.v7.widget.Toolbar
|
<android.support.v7.widget.Toolbar
|
||||||
android:id="@+id/toolbar"
|
android:id="@+id/appbar"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="?attr/actionBarSize"
|
android:layout_height="?attr/actionBarSize"
|
||||||
android:background="?attr/colorPrimary"
|
android:background="?attr/colorPrimary"
|
||||||
|
@ -21,16 +23,19 @@
|
||||||
|
|
||||||
<android.support.design.widget.FloatingActionButton
|
<android.support.design.widget.FloatingActionButton
|
||||||
android:id="@+id/continue_fab"
|
android:id="@+id/continue_fab"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="16dp"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:layout_marginBottom="16dp"
|
|
||||||
android:clickable="true"
|
android:clickable="true"
|
||||||
android:focusable="true"
|
android:focusable="true"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:srcCompat="@drawable/ic_check" />
|
app:srcCompat="@drawable/ic_check" />
|
||||||
|
|
||||||
|
<android.support.constraint.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
android:layout_marginTop="?attr/actionBarSize">
|
||||||
|
|
||||||
<FrameLayout
|
<FrameLayout
|
||||||
android:id="@+id/sync_fragment_container"
|
android:id="@+id/sync_fragment_container"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
|
@ -38,15 +43,16 @@
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toBottomOf="@+id/toolbar" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<ImageView
|
<ImageView
|
||||||
android:id="@+id/qrcode"
|
android:id="@+id/qrcode"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:contentDescription="QrCode"
|
android:contentDescription="@string/qr_code"
|
||||||
app:layout_constraintBottom_toBottomOf="parent"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
||||||
|
</android.support.design.widget.CoordinatorLayout>
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/title"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/label_name"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
tools:text="Organisation B" />
|
||||||
|
|
||||||
|
<View
|
||||||
|
android:id="@+id/divider"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="1dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:background="?android:attr/listDivider"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintHorizontal_bias="1.0"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/label_status" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/syncStatus"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="8dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintStart_toEndOf="@+id/label_status"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/label_name"
|
||||||
|
tools:text="successful" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_status"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:text="Status"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/label_name" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/label_name"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="16dp"
|
||||||
|
android:layout_marginTop="16dp"
|
||||||
|
android:text="Name"
|
||||||
|
android:textStyle="bold"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/delete_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:src="@drawable/ic_delete_forever"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/label_status"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/label_name" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/retry_button"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
android:padding="8dp"
|
||||||
|
android:src="@drawable/ic_autorenew"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@+id/label_status"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/delete_button"
|
||||||
|
app:layout_constraintTop_toTopOf="@+id/label_name" />
|
||||||
|
|
||||||
|
</android.support.constraint.ConstraintLayout>
|
|
@ -2,15 +2,10 @@
|
||||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
|
||||||
<!--<item-->
|
|
||||||
<!--android:value="@+value/action_download"-->
|
|
||||||
<!--android:icon="@drawable/ic_cloud_download_light_24dp"-->
|
|
||||||
<!--android:title="@string/login"-->
|
|
||||||
<!--app:showAsAction="ifRoom"/>-->
|
|
||||||
|
|
||||||
<item
|
<item
|
||||||
android:id="@+id/aes"
|
android:icon="@drawable/ic_cloud_download_light_24dp"
|
||||||
android:title="AES"
|
android:id="@+id/update"
|
||||||
|
android:title="Update Organisation"
|
||||||
app:showAsAction="never"/>
|
app:showAsAction="never"/>
|
||||||
|
|
||||||
<item android:id="@+id/main_menu_clear_and_logout"
|
<item android:id="@+id/main_menu_clear_and_logout"
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<menu xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_syncs"
|
||||||
|
android:icon="@drawable/ic_sync_black_24dp"
|
||||||
|
android:title="Syncs" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_add"
|
||||||
|
android:icon="@drawable/ic_add"
|
||||||
|
android:title="Add" />
|
||||||
|
|
||||||
|
<item
|
||||||
|
android:id="@+id/menu_profile"
|
||||||
|
android:icon="@drawable/ic_person"
|
||||||
|
android:title="Profile" />
|
||||||
|
|
||||||
|
</menu>
|
|
@ -9,4 +9,6 @@
|
||||||
<string name="no_information">Keine Informationen</string>
|
<string name="no_information">Keine Informationen</string>
|
||||||
<string name="save_automation_key_hint">Automatisierungs-Schlüssel speichern</string>
|
<string name="save_automation_key_hint">Automatisierungs-Schlüssel speichern</string>
|
||||||
<string name="login_help_text">Das ist der Anmelde Informations Text.</string>
|
<string name="login_help_text">Das ist der Anmelde Informations Text.</string>
|
||||||
|
<string name="qr_code">QR code</string>
|
||||||
|
<string name="sync">Synchronisation</string>
|
||||||
</resources>
|
</resources>
|
|
@ -11,4 +11,6 @@
|
||||||
<string name="menu_login_help_label">Help</string>
|
<string name="menu_login_help_label">Help</string>
|
||||||
<string name="login_help_text">This is the login info text.</string>
|
<string name="login_help_text">This is the login info text.</string>
|
||||||
<string name="ok" translatable="false">Okay</string>
|
<string name="ok" translatable="false">Okay</string>
|
||||||
|
<string name="qr_code">QR code</string>
|
||||||
|
<string name="sync">Synchronization</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<resources>
|
<resources>
|
||||||
<style name="AppTheme" parent="Theme.AppCompat.Light.NoActionBar">
|
<style name="AppTheme" parent="Theme.MaterialComponents.Light.NoActionBar">
|
||||||
<item name="colorPrimary">@color/colorPrimary</item>
|
<item name="colorPrimary">@color/colorPrimary</item>
|
||||||
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
|
||||||
<item name="colorAccent">@color/colorAccent</item>
|
<item name="colorAccent">@color/colorAccent</item>
|
||||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
||||||
|
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:3.4.0'
|
classpath 'com.android.tools.build:gradle:3.4.1'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
# Information in encrypted QR code (on MISP A)
|
||||||
|
## Organisation
|
||||||
|
+ Identifier (Organisation B on MISP A)
|
||||||
|
+ UUID (of organisation B)
|
||||||
|
+ description
|
||||||
|
+ Nationality
|
||||||
|
+ Sector
|
||||||
|
+ type (freetext)
|
||||||
|
+ (contacts?)
|
||||||
|
|
||||||
|
## SyncUser
|
||||||
|
+ email (orgb.syncuser@mispa.test)
|
||||||
|
+ password (abcdefghijklmnop) (16 chars but depends on settings)
|
||||||
|
|
||||||
|
## SyncServer
|
||||||
|
+ base url
|
||||||
|
+ instance name
|
||||||
|
+ authkey from syncUser
|
||||||
|
|
||||||
|
|
||||||
|
## Steps
|
||||||
|
|
||||||
|
1. each instance generates a foreign organisation
|
||||||
|
2. each instance generates a syncuser
|
||||||
|
3. each instance generates a sync server
|
Loading…
Reference in New Issue