Merge pull request #12 from cybertier/illegal-state-during-connection

Illegal state during connection
pull/5/head
Felix PK 2019-07-23 15:01:18 +02:00 committed by GitHub
commit fa20e74a67
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 633 additions and 239 deletions

View File

@ -118,7 +118,7 @@ public class ExchangeActivity extends AppCompatActivity {
SyncInformation syncInformation = new SyncInformation(); SyncInformation syncInformation = new SyncInformation();
syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation(); syncInformation.organisation = preferenceManager.getUserOrganisation().toSyncOrganisation();
syncInformation.syncUserAuthkey = new RandomString(40).nextString(); syncInformation.syncUserAuthkey = new RandomString(40).nextString();
syncInformation.baseUrl = preferenceManager.getServerUrl(); syncInformation.baseUrl = preferenceManager.getUserCredentials().first;
syncInformation.syncUserPassword = new RandomString(16).nextString(); syncInformation.syncUserPassword = new RandomString(16).nextString();
syncInformation.syncUserEmail = preferenceManager.getUserInfo().email; syncInformation.syncUserEmail = preferenceManager.getUserInfo().email;
return syncInformation; return syncInformation;
@ -289,7 +289,7 @@ public class ExchangeActivity extends AppCompatActivity {
final List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList(); final List<UploadInformation> uploadInformationList = preferenceManager.getUploadInformationList();
for (final UploadInformation ui : uploadInformationList) { for (final UploadInformation ui : uploadInformationList) {
if (ui.getRemote().organisation.uuid.equals(remoteSyncInfo.organisation.uuid)) { if (ui.getRemote().organisation.getUuid().equals(remoteSyncInfo.organisation.getUuid())) {
DialogManager.syncAlreadyExistsDialog(ui.getRemote(), remoteSyncInfo, ExchangeActivity.this, new DialogManager.IDialogFeedback() { DialogManager.syncAlreadyExistsDialog(ui.getRemote(), remoteSyncInfo, ExchangeActivity.this, new DialogManager.IDialogFeedback() {
@Override @Override
public void positive() { public void positive() {

View File

@ -3,13 +3,6 @@ package lu.circl.mispbump.activities;
import android.content.Intent; import android.content.Intent;
import android.net.Uri; import android.net.Uri;
import android.os.Bundle; import android.os.Bundle;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.text.TextUtils; import android.text.TextUtils;
import android.view.Menu; import android.view.Menu;
import android.view.MenuItem; import android.view.MenuItem;
@ -17,25 +10,30 @@ import android.view.View;
import android.widget.Button; import android.widget.Button;
import android.widget.ProgressBar; import android.widget.ProgressBar;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.google.android.material.snackbar.Snackbar;
import com.google.android.material.textfield.TextInputLayout;
import java.util.Objects; import java.util.Objects;
import lu.circl.mispbump.R; import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.DialogManager; import lu.circl.mispbump.auxiliary.DialogManager;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.auxiliary.MispRestClient; import lu.circl.mispbump.auxiliary.MispRestClient;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.models.restModels.Organisation; import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User; import lu.circl.mispbump.models.restModels.User;
/**
* This activity is shown when the current device has no misp user and organisation associated with it.
* 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 PreferenceManager preferenceManager;
private ConstraintLayout constraintLayout; private ConstraintLayout constraintLayout;
private TextInputLayout serverAutomationKey; private TextInputLayout serverAuthkey;
private TextInputLayout serverUrl; private TextInputLayout serverUrl;
private ProgressBar progressBar; private ProgressBar progressBar;
@ -64,7 +62,6 @@ public class LoginActivity extends AppCompatActivity {
return true; return true;
} }
// invoke superclass to handle unrecognized item (eg. homeAsUp)
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@ -72,7 +69,6 @@ public class LoginActivity extends AppCompatActivity {
private void initializeViews() { private void initializeViews() {
constraintLayout = findViewById(R.id.rootLayout); constraintLayout = findViewById(R.id.rootLayout);
// populate Toolbar (Actionbar)
Toolbar myToolbar = findViewById(R.id.appbar); Toolbar myToolbar = findViewById(R.id.appbar);
setSupportActionBar(myToolbar); setSupportActionBar(myToolbar);
ActionBar ab = getSupportActionBar(); ActionBar ab = getSupportActionBar();
@ -82,26 +78,26 @@ public class LoginActivity extends AppCompatActivity {
} }
Button downloadInfoButton = findViewById(R.id.login_download_button); Button downloadInfoButton = findViewById(R.id.login_download_button);
downloadInfoButton.setOnClickListener(onClickDownload); downloadInfoButton.setOnClickListener(onLogin);
serverUrl = findViewById(R.id.login_server_url); serverUrl = findViewById(R.id.login_server_url);
serverAutomationKey = findViewById(R.id.login_automation_key); serverAuthkey = findViewById(R.id.login_automation_key);
progressBar = findViewById(R.id.login_progressbar); progressBar = findViewById(R.id.login_progressbar);
} }
/** /**
* Is called when the user clicks on the login button. * Called when the user clicks on the login button.
*/ */
private View.OnClickListener onClickDownload = new View.OnClickListener() { private View.OnClickListener onLogin = new View.OnClickListener() {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
final String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString(); final String url = Objects.requireNonNull(serverUrl.getEditText()).getText().toString();
final String authkey = Objects.requireNonNull(serverAutomationKey.getEditText()).getText().toString(); final String authkey = Objects.requireNonNull(serverAuthkey.getEditText()).getText().toString();
boolean error = false; boolean error = false;
serverUrl.setError(null); serverUrl.setError(null);
serverAutomationKey.setError(null); serverAuthkey.setError(null);
if (!isValidUrl(url)) { if (!isValidUrl(url)) {
error = true; error = true;
@ -110,7 +106,7 @@ public class LoginActivity extends AppCompatActivity {
if (!isValidAutomationKey(authkey)) { if (!isValidAutomationKey(authkey)) {
error = true; error = true;
serverAutomationKey.setError("Invalid automation key"); serverAuthkey.setError("Invalid automation key");
} }
if (error) { if (error) {
@ -126,25 +122,44 @@ public class LoginActivity extends AppCompatActivity {
mispRestClient.isAvailable(new MispRestClient.AvailableCallback() { mispRestClient.isAvailable(new MispRestClient.AvailableCallback() {
@Override @Override
public void available() { public void available() {
mispRestClient.getMyUser(new MispRestClient.UserCallback() { mispRestClient.getRoles(new MispRestClient.AllRolesCallback() {
@Override @Override
public void success(final User user) { public void success(final Role[] roles) {
preferenceManager.setUserInfo(user); preferenceManager.setRoles(roles);
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
mispRestClient.getMyUser(new MispRestClient.UserCallback() {
@Override @Override
public void success(Organisation organisation) { public void success(final User user) {
preferenceManager.setUserOrgInfo(organisation); preferenceManager.setUserInfo(user);
for (Role role : roles) {
if (role.getId().equals(user.role_id)) {
if (!role.getPermAdmin()) {
progressBar.setVisibility(View.GONE);
Snackbar.make(constraintLayout, "No admin is associated with this authkey.", Snackbar.LENGTH_LONG).show();
return;
}
}
}
// save authkey mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
preferenceManager.setAutomationKey(authkey); @Override
public void success(Organisation organisation) {
preferenceManager.setUserOrgInfo(organisation);
preferenceManager.setUserCredentials(url, authkey);
// save url progressBar.setVisibility(View.GONE);
preferenceManager.setServerUrl(url);
progressBar.setVisibility(View.GONE); Intent home = new Intent(getApplicationContext(), HomeActivity.class);
Intent home = new Intent(getApplicationContext(), HomeActivity.class); startActivity(home);
startActivity(home); finish();
finish(); }
@Override
public void failure(String error) {
progressBar.setVisibility(View.GONE);
Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show();
}
});
} }
@Override @Override
@ -166,8 +181,7 @@ public class LoginActivity extends AppCompatActivity {
@Override @Override
public void unavailable(String error) { public void unavailable(String error) {
progressBar.setVisibility(View.GONE); progressBar.setVisibility(View.GONE);
Snackbar sb = Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG); Snackbar.make(constraintLayout, error, Snackbar.LENGTH_LONG).show();
sb.show();
} }
}); });
} }

View File

@ -17,6 +17,7 @@ import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.coordinatorlayout.widget.CoordinatorLayout; import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar; import com.google.android.material.snackbar.Snackbar;
@ -29,6 +30,7 @@ import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.auxiliary.TileDrawable; import lu.circl.mispbump.auxiliary.TileDrawable;
import lu.circl.mispbump.customViews.MaterialPreferenceText; import lu.circl.mispbump.customViews.MaterialPreferenceText;
import lu.circl.mispbump.models.restModels.Organisation; import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User; import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.security.KeyStoreWrapper; import lu.circl.mispbump.security.KeyStoreWrapper;
@ -47,7 +49,8 @@ public class ProfileActivity extends AppCompatActivity {
setContentView(R.layout.activity_profile); setContentView(R.layout.activity_profile);
preferenceManager = PreferenceManager.getInstance(this); preferenceManager = PreferenceManager.getInstance(this);
mispRestClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey()); Pair<String, String> credentials = preferenceManager.getUserCredentials();
mispRestClient = MispRestClient.getInstance(credentials.first, credentials.second);
init(); init();
populateInformationViews(); populateInformationViews();
@ -79,23 +82,23 @@ public class ProfileActivity extends AppCompatActivity {
Organisation organisation = preferenceManager.getUserOrganisation(); Organisation organisation = preferenceManager.getUserOrganisation();
TextView name = findViewById(R.id.orgName); TextView name = findViewById(R.id.orgName);
name.setText(organisation.name); name.setText(organisation.getName());
final MaterialPreferenceText uuid = findViewById(R.id.uuid); final MaterialPreferenceText uuid = findViewById(R.id.uuid);
uuid.setSubtitle(organisation.uuid); uuid.setSubtitle(organisation.getUuid());
MaterialPreferenceText nationality = findViewById(R.id.nationality); MaterialPreferenceText nationality = findViewById(R.id.nationality);
nationality.setSubtitle(organisation.nationality); nationality.setSubtitle(organisation.getNationality());
MaterialPreferenceText sector = findViewById(R.id.sector); MaterialPreferenceText sector = findViewById(R.id.sector);
if (organisation.sector == null) { if (organisation.getSector() == null) {
sector.setVisibility(View.GONE); sector.setVisibility(View.GONE);
} else { } else {
sector.setSubtitle(organisation.sector); sector.setSubtitle(organisation.getSector());
} }
MaterialPreferenceText description = findViewById(R.id.description); MaterialPreferenceText description = findViewById(R.id.description);
description.setSubtitle(organisation.description); description.setSubtitle(organisation.getDescription());
} }
@Override @Override
@ -131,14 +134,22 @@ public class ProfileActivity extends AppCompatActivity {
} }
public void updateProfile() { public void updateProfile() {
// progressBar.setVisibility(View.VISIBLE); mispRestClient.getRoles(new MispRestClient.AllRolesCallback() {
@Override
public void success(Role[] roles) {
preferenceManager.setRoles(roles);
}
@Override
public void failure(String error) {
Snackbar.make(rootLayout, error, Snackbar.LENGTH_LONG).show();
}
});
mispRestClient.getMyUser(new MispRestClient.UserCallback() { mispRestClient.getMyUser(new MispRestClient.UserCallback() {
@Override @Override
public void success(final User user) { public void success(final User user) {
preferenceManager.setUserInfo(user); preferenceManager.setUserInfo(user);
mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() { mispRestClient.getOrganisation(user.org_id, new MispRestClient.OrganisationCallback() {
@Override @Override
public void success(Organisation organisation) { public void success(Organisation organisation) {
@ -178,8 +189,7 @@ public class ProfileActivity extends AppCompatActivity {
builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() { builder.setPositiveButton("Delete & Logout", new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) { public void onClick(DialogInterface dialog, int which) {
PreferenceManager prefs = PreferenceManager.getInstance(ProfileActivity.this); preferenceManager.clearAllData();
prefs.clearAllData();
KeyStoreWrapper.deleteAllStoredKeys(); KeyStoreWrapper.deleteAllStoredKeys();
Intent login = new Intent(getApplicationContext(), LoginActivity.class); Intent login = new Intent(getApplicationContext(), LoginActivity.class);

View File

@ -2,12 +2,10 @@ package lu.circl.mispbump.activities;
import android.content.Intent; import android.content.Intent;
import android.os.Bundle; import android.os.Bundle;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import lu.circl.mispbump.auxiliary.PreferenceManager; import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.models.restModels.User;
/** /**
* Starts either the login or home activity. * Starts either the login or home activity.
@ -32,7 +30,6 @@ public class StartUpActivity extends AppCompatActivity {
private boolean isUserLoggedIn() { private boolean isUserLoggedIn() {
PreferenceManager preferenceManager = PreferenceManager.getInstance(this); PreferenceManager preferenceManager = PreferenceManager.getInstance(this);
User user = preferenceManager.getUserInfo(); return preferenceManager.getUserCredentials() != null && preferenceManager.getUserInfo() != null;
return user != null;
} }
} }

View File

@ -9,6 +9,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import androidx.core.util.Pair;
import com.google.android.material.floatingactionbutton.FloatingActionButton; import com.google.android.material.floatingactionbutton.FloatingActionButton;
@ -99,7 +100,8 @@ public class UploadActivity extends AppCompatActivity {
setContentView(R.layout.activity_upload); setContentView(R.layout.activity_upload);
preferenceManager = PreferenceManager.getInstance(UploadActivity.this); preferenceManager = PreferenceManager.getInstance(UploadActivity.this);
restClient = MispRestClient.getInstance(preferenceManager.getServerUrl(), preferenceManager.getAuthKey()); Pair<String, String> credentials = preferenceManager.getUserCredentials();
restClient = MispRestClient.getInstance(credentials.first, credentials.second);
parseExtra(); parseExtra();
initViews(); initViews();
@ -212,7 +214,7 @@ public class UploadActivity extends AppCompatActivity {
private User generateSyncUser(Organisation organisation) { private User generateSyncUser(Organisation organisation) {
User syncUser = new User(); User syncUser = new User();
syncUser.org_id = organisation.id; syncUser.org_id = organisation.getId();
syncUser.role_id = User.ROLE_SYNC_USER; syncUser.role_id = User.ROLE_SYNC_USER;
syncUser.email = uploadInformation.getRemote().syncUserEmail; syncUser.email = uploadInformation.getRemote().syncUserEmail;
syncUser.password = uploadInformation.getRemote().syncUserPassword; syncUser.password = uploadInformation.getRemote().syncUserPassword;
@ -224,9 +226,9 @@ public class UploadActivity extends AppCompatActivity {
private Server generateSyncServer() { private Server generateSyncServer() {
Server server = new Server(); Server server = new Server();
server.name = uploadInformation.getRemote().organisation.name + "'s Sync Server"; server.name = uploadInformation.getRemote().organisation.getName() + "'s Sync Server";
server.url = uploadInformation.getRemote().baseUrl; server.url = uploadInformation.getRemote().baseUrl;
server.remote_org_id = uploadInformation.getRemote().organisation.id; server.remote_org_id = uploadInformation.getRemote().organisation.getId();
server.authkey = uploadInformation.getLocal().syncUserAuthkey; server.authkey = uploadInformation.getLocal().syncUserAuthkey;
server.pull = uploadInformation.isPull(); server.pull = uploadInformation.isPull();
server.push = uploadInformation.isPush(); server.push = uploadInformation.isPush();
@ -256,11 +258,11 @@ public class UploadActivity extends AppCompatActivity {
private void organisationAdded(Organisation organisation) { private void organisationAdded(Organisation organisation) {
if (organisation != null) { if (organisation != null) {
setUploadActionState(orgAction, UploadAction.UploadState.DONE, null); setUploadActionState(orgAction, UploadAction.UploadState.DONE, null);
uploadInformation.getRemote().organisation.id = organisation.id; uploadInformation.getRemote().organisation.setId(organisation.getId());
restClient.addUser(generateSyncUser(organisation), userCallback); restClient.addUser(generateSyncUser(organisation), userCallback);
} else { } else {
// search by UUID because the error does not give the actual ID // search by UUID because the error does not give the actual ID
restClient.getOrganisation(uploadInformation.getRemote().organisation.uuid, new MispRestClient.OrganisationCallback() { restClient.getOrganisation(uploadInformation.getRemote().organisation.getUuid(), new MispRestClient.OrganisationCallback() {
@Override @Override
public void success(Organisation organisation) { public void success(Organisation organisation) {
organisationAdded(organisation); organisationAdded(organisation);

View File

@ -127,7 +127,7 @@ public class UploadInfoActivity extends AppCompatActivity {
assert ab != null; assert ab != null;
TextView toolbarTitle = findViewById(R.id.toolbarTitle); TextView toolbarTitle = findViewById(R.id.toolbarTitle);
toolbarTitle.setText(uploadInformation.getRemote().organisation.name); toolbarTitle.setText(uploadInformation.getRemote().organisation.getName());
ab.setHomeAsUpIndicator(R.drawable.ic_close); ab.setHomeAsUpIndicator(R.drawable.ic_close);

View File

@ -45,7 +45,7 @@ public class UploadInfoAdapter extends RecyclerView.Adapter<UploadInfoAdapter.Vi
final UploadInformation item = items.get(position); final UploadInformation item = items.get(position);
holder.date.setText(item.getDateString()); holder.date.setText(item.getDateString());
holder.orgName.setText(item.getRemote().organisation.name); holder.orgName.setText(item.getRemote().organisation.getName());
switch (item.getCurrentSyncStatus()) { switch (item.getCurrentSyncStatus()) {
case COMPLETE: case COMPLETE:

View File

@ -26,10 +26,10 @@ public class DialogManager {
// this dialog needs definite user feedback // this dialog needs definite user feedback
adb.setCancelable(false); adb.setCancelable(false);
if (oldSync.organisation.name.equals(newSync.organisation.name)) { if (oldSync.organisation.getName().equals(newSync.organisation.getName())) {
adb.setTitle("Already Synced with " + oldSync.organisation.name); adb.setTitle("Already Synced with " + oldSync.organisation.getName());
} else { } else {
adb.setTitle("Already Synced with " + oldSync.organisation.name + "(Now:" + newSync.organisation.name + ")"); adb.setTitle("Already Synced with " + oldSync.organisation.getName() + "(Now:" + newSync.organisation.getName() + ")");
} }
adb.setMessage(""); adb.setMessage("");
@ -142,7 +142,7 @@ public class DialogManager {
final AlertDialog.Builder adb = new AlertDialog.Builder(context); final AlertDialog.Builder adb = new AlertDialog.Builder(context);
adb.setTitle("Sync information received"); adb.setTitle("Sync information received");
adb.setMessage(syncInformation.organisation.name); adb.setMessage(syncInformation.organisation.getName());
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) {

View File

@ -23,9 +23,11 @@ import javax.net.ssl.X509TrustManager;
import lu.circl.mispbump.interfaces.MispRestInterface; import lu.circl.mispbump.interfaces.MispRestInterface;
import lu.circl.mispbump.models.restModels.MispOrganisation; import lu.circl.mispbump.models.restModels.MispOrganisation;
import lu.circl.mispbump.models.restModels.MispRole;
import lu.circl.mispbump.models.restModels.MispServer; import lu.circl.mispbump.models.restModels.MispServer;
import lu.circl.mispbump.models.restModels.MispUser; import lu.circl.mispbump.models.restModels.MispUser;
import lu.circl.mispbump.models.restModels.Organisation; import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.Server; import lu.circl.mispbump.models.restModels.Server;
import lu.circl.mispbump.models.restModels.User; import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.models.restModels.Version; import lu.circl.mispbump.models.restModels.Version;
@ -59,12 +61,12 @@ public class MispRestClient {
return instance; return instance;
} }
public void initMispRestInterface(String url, String authkey) { private void initMispRestInterface(String url, String authkey) {
try { try {
Retrofit retrofit = new Retrofit.Builder() Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url) .baseUrl(url)
.addConverterFactory(GsonConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create())
.client(getCustomClient(true, false, authkey)) .client(getCustomClient(true, true, authkey))
.build(); .build();
mispRestInterface = retrofit.create(MispRestInterface.class); mispRestInterface = retrofit.create(MispRestInterface.class);
@ -176,6 +178,36 @@ public class MispRestClient {
}); });
} }
public void getRoles(final AllRolesCallback callback) {
Call<List<MispRole>> call = mispRestInterface.getRoles();
call.enqueue(new Callback<List<MispRole>>() {
@Override
public void onResponse(Call<List<MispRole>> call, Response<List<MispRole>> response) {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
return;
}
List<MispRole> mispRoles = response.body();
assert mispRoles != null;
Role[] roles = new Role[mispRoles.size()];
for (int i = 0; i < roles.length; i++) {
roles[i] = mispRoles.get(i).role;
}
callback.success(roles);
}
@Override
public void onFailure(Call<List<MispRole>> call, Throwable t) {
callback.failure(extractError(t));
}
});
}
/** /**
* Fetches information about the user that is associated with saved auth key. * Fetches information about the user that is associated with saved auth key.
@ -338,7 +370,7 @@ public class MispRestClient {
if (response.body() != null) { if (response.body() != null) {
callback.success(response.body().organisation); callback.success(response.body().organisation);
} else { } else {
callback.failure("Response body was nul"); callback.failure("Response was empty");
} }
} }
} }
@ -355,7 +387,7 @@ public class MispRestClient {
@Override @Override
public void success(Organisation[] organisations) { public void success(Organisation[] organisations) {
for (Organisation organisation : organisations) { for (Organisation organisation : organisations) {
if (organisation.uuid.equals(uuid)) { if (organisation.getUuid().equals(uuid)) {
callback.success(organisation); callback.success(organisation);
return; return;
} }
@ -378,7 +410,6 @@ public class MispRestClient {
@Override @Override
public void onResponse(@NonNull Call<List<MispOrganisation>> call, @NonNull Response<List<MispOrganisation>> response) { public void onResponse(@NonNull Call<List<MispOrganisation>> call, @NonNull Response<List<MispOrganisation>> response) {
if (!response.isSuccessful()) { if (!response.isSuccessful()) {
// TODO handle
return; return;
} }
@ -574,6 +605,12 @@ public class MispRestClient {
return "Server is not available (no route to host)"; return "Server is not available (no route to host)";
} }
try {
throw new Exception(t);
} catch (Exception e) {
e.printStackTrace();
}
return t.getMessage(); return t.getMessage();
} }
@ -620,4 +657,10 @@ public class MispRestClient {
void failure(String error); void failure(String error);
} }
public interface AllRolesCallback {
void success(Role[] roles);
void failure(String error);
}
} }

View File

@ -2,7 +2,8 @@ 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 androidx.core.util.Pair;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken; import com.google.gson.reflect.TypeToken;
@ -21,24 +22,22 @@ import javax.crypto.NoSuchPaddingException;
import lu.circl.mispbump.models.UploadInformation; import lu.circl.mispbump.models.UploadInformation;
import lu.circl.mispbump.models.restModels.Organisation; import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Role;
import lu.circl.mispbump.models.restModels.User; import lu.circl.mispbump.models.restModels.User;
import lu.circl.mispbump.security.KeyStoreWrapper; import lu.circl.mispbump.security.KeyStoreWrapper;
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";
private static final String SAVE_CREDENTIALS = "save_credentials"; private static final String USER_CREDENTIALS = "user_credentials";
private static final String SERVER_URL = "server_url";
private static final String AUTOMATION_KEY = "user_automation";
private static final String USER_INFOS = "user_infos"; private static final String USER_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 static final String UPLOAD_INFO = "upload_info";
private static final String MISP_ROLES = "misp_roles";
private SharedPreferences preferences; private SharedPreferences preferences;
private static PreferenceManager instance; private static PreferenceManager instance;
@ -61,6 +60,38 @@ public class PreferenceManager {
} }
/**
* Save downloaded MISP roles on device.
*
* @param roles {@link Role}
*/
public void setRoles(Role[] roles) {
SharedPreferences.Editor editor = preferences.edit();
editor.putString(MISP_ROLES, new Gson().toJson(roles));
editor.apply();
}
/**
* Gets downloaded and saved MISP roles if available.
* <p/>
* Roles are downloaded on login and updated with each profile update.
*
* @return {@link Role}[] or null
*/
public Role[] getRoles() {
Type type = new TypeToken<Role[]>() {
}.getType();
String rolesString = preferences.getString(MISP_ROLES, "");
assert rolesString != null;
if (rolesString.isEmpty()) {
return null;
} else {
return new Gson().fromJson(rolesString, type);
}
}
/** /**
* Saves user infos from "users/view/me" (encrypted) * Saves user infos from "users/view/me" (encrypted)
* *
@ -180,147 +211,34 @@ public class PreferenceManager {
} }
/** public void setUserCredentials(String url, String authkey) {
* Encrypts the automation key and stores it in preferences.
*
* @param automationKey key entered in {@link lu.circl.mispbump.activities.LoginActivity}
*/
public void setAutomationKey(String automationKey) {
try { try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS); KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();
editor.putString(AUTOMATION_KEY, keyStoreWrapper.encrypt(automationKey)); editor.putString(USER_CREDENTIALS, keyStoreWrapper.encrypt(new Gson().toJson(new Pair<>(url, authkey))));
editor.apply(); editor.apply();
} catch (NoSuchPaddingException e) { } catch (NoSuchAlgorithmException | InvalidKeyException | BadPaddingException | IllegalBlockSizeException | NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace(); e.printStackTrace();
} }
} }
/** public Pair<String, String> getUserCredentials() {
* Decrypts the stored automation key and returns it. if (!preferences.contains(USER_CREDENTIALS)) {
*
* @return decrypted automation key associated with the current user. If no user exists an empty
* String is returned.
*/
public String getAuthKey() {
if (!preferences.contains(AUTOMATION_KEY)) {
return "";
}
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(AUTOMATION_KEY, ""));
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
return "";
}
/**
* Delete the key to decrypt this entry and the entry itself.
*/
public void clearAutomationKey() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.AUTOMATION_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(AUTOMATION_KEY);
editor.apply();
}
/**
* Encrypts the server url and stores it in preferences.
*
* @param serverUrl url of the corresponding misp instance
*/
public void setServerUrl(String serverUrl) {
try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
SharedPreferences.Editor editor = preferences.edit();
editor.putString(SERVER_URL, keyStoreWrapper.encrypt(serverUrl));
editor.apply();
} catch (NoSuchPaddingException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace();
}
}
/**
* Decrypts the stored server url and returns it
*
* @return decrypted misp instance url
*/
public String getServerUrl() {
if (!preferences.contains(SERVER_URL)) {
return null; return null;
} }
try { try {
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS); KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.USER_CREDENTIALS_ALIAS);
return keyStoreWrapper.decrypt(preferences.getString(SERVER_URL, null)); Type type = new TypeToken<Pair<String, String>>() {}.getType();
String serializedCreds = keyStoreWrapper.decrypt(preferences.getString(USER_CREDENTIALS, ""));
} catch (NoSuchPaddingException e) { return new Gson().fromJson(serializedCreds, type);
e.printStackTrace(); } catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | BadPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (InvalidAlgorithmParameterException e) {
e.printStackTrace();
} catch (InvalidKeyException e) {
e.printStackTrace();
} catch (BadPaddingException e) {
e.printStackTrace();
} catch (IllegalBlockSizeException e) {
e.printStackTrace(); e.printStackTrace();
} }
return null; return null;
} }
/**
* Delete the key to decrypt this entry and the entry itself.
*/
public void clearServerUrl() {
// remove the key from KeyStore
KeyStoreWrapper keyStoreWrapper = new KeyStoreWrapper(KeyStoreWrapper.SERVER_URL_ALIAS);
keyStoreWrapper.deleteStoredKey();
SharedPreferences.Editor editor = preferences.edit();
editor.remove(SERVER_URL);
editor.apply();
}
private List<UploadInformation> cachedUploadInformationList; private List<UploadInformation> cachedUploadInformationList;
@ -328,7 +246,8 @@ public class PreferenceManager {
KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS); KeyStoreWrapper ksw = new KeyStoreWrapper(KeyStoreWrapper.UPLOAD_INFORMATION_ALIAS);
String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null); String storedUploadInfoString = preferences.getString(UPLOAD_INFO, null);
Type type = new TypeToken<List<UploadInformation>>() {}.getType(); Type type = new TypeToken<List<UploadInformation>>() {
}.getType();
if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) { if (storedUploadInfoString == null || storedUploadInfoString.isEmpty()) {
cachedUploadInformationList = new ArrayList<>(); cachedUploadInformationList = new ArrayList<>();
@ -430,26 +349,13 @@ public class PreferenceManager {
} }
/**
* Set if credentials (authkey & server url) should be saved locally.
*
* @param save enable or disable
* @deprecated currently not used because automation key is needed to do requests to your misp instance.
* If this should be an option in future: misp automation key would be needed on each sync process.
*/
public void setSaveCredentials(boolean save) {
SharedPreferences.Editor editor = preferences.edit();
editor.putBoolean(SAVE_CREDENTIALS, save);
editor.apply();
}
public boolean getSaveCredentials() {
return preferences.getBoolean(SAVE_CREDENTIALS, false);
}
public void clearAllData() { public void clearAllData() {
SharedPreferences.Editor editor = preferences.edit(); SharedPreferences.Editor editor = preferences.edit();
// clearServerUrl();
// clearAutomationKey();
clearUploadInformation();
editor.clear(); editor.clear();
editor.apply(); editor.apply();
} }

View File

@ -3,6 +3,7 @@ package lu.circl.mispbump.interfaces;
import java.util.List; import java.util.List;
import lu.circl.mispbump.models.restModels.MispOrganisation; import lu.circl.mispbump.models.restModels.MispOrganisation;
import lu.circl.mispbump.models.restModels.MispRole;
import lu.circl.mispbump.models.restModels.MispServer; import lu.circl.mispbump.models.restModels.MispServer;
import lu.circl.mispbump.models.restModels.MispUser; import lu.circl.mispbump.models.restModels.MispUser;
import lu.circl.mispbump.models.restModels.Organisation; import lu.circl.mispbump.models.restModels.Organisation;
@ -25,6 +26,9 @@ public interface MispRestInterface {
@GET("servers/getPyMISPVersion") @GET("servers/getPyMISPVersion")
Call<Version> pyMispVersion(); Call<Version> pyMispVersion();
@GET("admin/roles")
Call<List<MispRole>> getRoles();
// user routes // user routes
@GET("users/view/me") @GET("users/view/me")

View File

@ -0,0 +1,10 @@
package lu.circl.mispbump.models.restModels;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
public class MispRole {
@SerializedName("Role")
@Expose
public Role role;
}

View File

@ -5,20 +5,20 @@ package lu.circl.mispbump.models.restModels;
*/ */
public class Organisation { public class Organisation {
public Integer id; private Integer id;
public String name; private String name;
public String date_created; private String date_created;
public String date_modified; private String date_modified;
public String type; private String type;
public String nationality; private String nationality;
public String sector; private String sector;
public String contacts; private String contacts;
public String description; private String description;
public Boolean local; private Boolean local;
public String uuid; private String uuid;
public String restricted_to_domain; private String[] restricted_to_domain;
public String created_by; private String created_by;
public Integer user_count; private Integer user_count;
public Organisation() { public Organisation() {
} }
@ -46,6 +46,119 @@ public class Organisation {
return organisation; return organisation;
} }
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDate_created() {
return date_created;
}
public void setDate_created(String date_created) {
this.date_created = date_created;
}
public String getDate_modified() {
return date_modified;
}
public void setDate_modified(String date_modified) {
this.date_modified = date_modified;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getNationality() {
return nationality;
}
public void setNationality(String nationality) {
this.nationality = nationality;
}
public String getSector() {
return sector;
}
public void setSector(String sector) {
this.sector = sector;
}
public String getContacts() {
return contacts;
}
public void setContacts(String contacts) {
this.contacts = contacts;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Boolean getLocal() {
return local;
}
public void setLocal(Boolean local) {
this.local = local;
}
public String getUuid() {
return uuid;
}
public void setUuid(String uuid) {
this.uuid = uuid;
}
public String[] getRestricted_to_domain() {
return restricted_to_domain;
}
public void setRestricted_to_domain(String[] restricted_to_domain) {
this.restricted_to_domain = restricted_to_domain;
}
public String getCreated_by() {
return created_by;
}
public void setCreated_by(String created_by) {
this.created_by = created_by;
}
public Integer getUser_count() {
return user_count;
}
public void setUser_count(Integer user_count) {
this.user_count = user_count;
}
@Override @Override
public String toString() { public String toString() {
return "Organisation{" + return "Organisation{" +

View File

@ -0,0 +1,296 @@
package lu.circl.mispbump.models.restModels;
import com.google.gson.annotations.SerializedName;
public class Role {
@SerializedName("id")
private Integer id;
@SerializedName("name")
private String name;
@SerializedName("created")
private String created;
@SerializedName("modified")
private String modified;
@SerializedName("perm_add")
private Boolean permAdd;
@SerializedName("perm_modify")
private Boolean permModify;
@SerializedName("perm_modify_org")
private Boolean permModifyOrg;
@SerializedName("perm_publish")
private Boolean permPublish;
@SerializedName("perm_delegate")
private Boolean permDelegate;
@SerializedName("perm_sync")
private Boolean permSync;
@SerializedName("perm_admin")
private Boolean permAdmin;
@SerializedName("perm_audit")
private Boolean permAudit;
@SerializedName("perm_auth")
private Boolean permAuth;
@SerializedName("perm_site_admin")
private Boolean permSiteAdmin;
@SerializedName("perm_regexp_access")
private Boolean permRegexpAccess;
@SerializedName("perm_tagger")
private Boolean permTagger;
@SerializedName("perm_template")
private Boolean permTemplate;
@SerializedName("perm_sharing_group")
private Boolean permSharingGroup;
@SerializedName("perm_tag_editor")
private Boolean permTagEditor;
@SerializedName("perm_sighting")
private Boolean permSighting;
@SerializedName("perm_object_template")
private Boolean permObjectTemplate;
@SerializedName("default_role")
private Boolean defaultRole;
@SerializedName("memory_limit")
private String memoryLimit;
@SerializedName("max_execution_time")
private String maxExecutionTime;
@SerializedName("restricted_to_site_admin")
private Boolean restrictedToSiteAdmin;
@SerializedName("perm_publish_zmq")
private Boolean permPublishZmq;
@SerializedName("perm_publish_kafka")
private Boolean permPublishKafka;
@SerializedName("permission")
private String permission;
@SerializedName("permission_description")
private String permissionDescription;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getModified() {
return modified;
}
public void setModified(String modified) {
this.modified = modified;
}
public Boolean getPermAdd() {
return permAdd;
}
public void setPermAdd(Boolean permAdd) {
this.permAdd = permAdd;
}
public Boolean getPermModify() {
return permModify;
}
public void setPermModify(Boolean permModify) {
this.permModify = permModify;
}
public Boolean getPermModifyOrg() {
return permModifyOrg;
}
public void setPermModifyOrg(Boolean permModifyOrg) {
this.permModifyOrg = permModifyOrg;
}
public Boolean getPermPublish() {
return permPublish;
}
public void setPermPublish(Boolean permPublish) {
this.permPublish = permPublish;
}
public Boolean getPermDelegate() {
return permDelegate;
}
public void setPermDelegate(Boolean permDelegate) {
this.permDelegate = permDelegate;
}
public Boolean getPermSync() {
return permSync;
}
public void setPermSync(Boolean permSync) {
this.permSync = permSync;
}
public Boolean getPermAdmin() {
return permAdmin;
}
public void setPermAdmin(Boolean permAdmin) {
this.permAdmin = permAdmin;
}
public Boolean getPermAudit() {
return permAudit;
}
public void setPermAudit(Boolean permAudit) {
this.permAudit = permAudit;
}
public Boolean getPermAuth() {
return permAuth;
}
public void setPermAuth(Boolean permAuth) {
this.permAuth = permAuth;
}
public Boolean getPermSiteAdmin() {
return permSiteAdmin;
}
public void setPermSiteAdmin(Boolean permSiteAdmin) {
this.permSiteAdmin = permSiteAdmin;
}
public Boolean getPermRegexpAccess() {
return permRegexpAccess;
}
public void setPermRegexpAccess(Boolean permRegexpAccess) {
this.permRegexpAccess = permRegexpAccess;
}
public Boolean getPermTagger() {
return permTagger;
}
public void setPermTagger(Boolean permTagger) {
this.permTagger = permTagger;
}
public Boolean getPermTemplate() {
return permTemplate;
}
public void setPermTemplate(Boolean permTemplate) {
this.permTemplate = permTemplate;
}
public Boolean getPermSharingGroup() {
return permSharingGroup;
}
public void setPermSharingGroup(Boolean permSharingGroup) {
this.permSharingGroup = permSharingGroup;
}
public Boolean getPermTagEditor() {
return permTagEditor;
}
public void setPermTagEditor(Boolean permTagEditor) {
this.permTagEditor = permTagEditor;
}
public Boolean getPermSighting() {
return permSighting;
}
public void setPermSighting(Boolean permSighting) {
this.permSighting = permSighting;
}
public Boolean getPermObjectTemplate() {
return permObjectTemplate;
}
public void setPermObjectTemplate(Boolean permObjectTemplate) {
this.permObjectTemplate = permObjectTemplate;
}
public Boolean getDefaultRole() {
return defaultRole;
}
public void setDefaultRole(Boolean defaultRole) {
this.defaultRole = defaultRole;
}
public String getMemoryLimit() {
return memoryLimit;
}
public void setMemoryLimit(String memoryLimit) {
this.memoryLimit = memoryLimit;
}
public String getMaxExecutionTime() {
return maxExecutionTime;
}
public void setMaxExecutionTime(String maxExecutionTime) {
this.maxExecutionTime = maxExecutionTime;
}
public Boolean getRestrictedToSiteAdmin() {
return restrictedToSiteAdmin;
}
public void setRestrictedToSiteAdmin(Boolean restrictedToSiteAdmin) {
this.restrictedToSiteAdmin = restrictedToSiteAdmin;
}
public Boolean getPermPublishZmq() {
return permPublishZmq;
}
public void setPermPublishZmq(Boolean permPublishZmq) {
this.permPublishZmq = permPublishZmq;
}
public Boolean getPermPublishKafka() {
return permPublishKafka;
}
public void setPermPublishKafka(Boolean permPublishKafka) {
this.permPublishKafka = permPublishKafka;
}
public String getPermission() {
return permission;
}
public void setPermission(String permission) {
this.permission = permission;
}
public String getPermissionDescription() {
return permissionDescription;
}
public void setPermissionDescription(String permissionDescription) {
this.permissionDescription = permissionDescription;
}
}

View File

@ -29,8 +29,7 @@ public class KeyStoreWrapper {
public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO"; public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO"; public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY"; public static final String USER_CREDENTIALS_ALIAS = "ALIAS_USER_CREDENTIALS";
public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION"; public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
private static final String KEYSTORE_PROVIDER = "AndroidKeyStore"; private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";