upload is now safe in every case

pull/5/head
Felix Prahl-Kamps 2019-07-03 23:13:25 +02:00
parent 9268a0939c
commit 4585dedc7a
11 changed files with 318 additions and 190 deletions

View File

@ -36,6 +36,7 @@
android:theme="@style/AppTheme.Translucent" />
<activity
android:name=".activities.UploadInfoActivity"
android:configChanges="orientation|screenSize"
android:parentActivityName=".activities.HomeActivity" />
<activity
android:name=".activities.UploadActivity"

View File

@ -12,16 +12,13 @@ import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.snackbar.Snackbar;
import java.io.IOException;
import java.util.List;
import java.util.UUID;
import lu.circl.mispbump.R;
import lu.circl.mispbump.auxiliary.MispRestClient;
import lu.circl.mispbump.auxiliary.PreferenceManager;
import lu.circl.mispbump.customViews.UploadAction;
import lu.circl.mispbump.models.UploadInformation;
import lu.circl.mispbump.auxiliary.MispRestClient;
import lu.circl.mispbump.models.restModels.MispServer;
import lu.circl.mispbump.models.restModels.Organisation;
import lu.circl.mispbump.models.restModels.Server;
import lu.circl.mispbump.models.restModels.User;
@ -37,6 +34,63 @@ public class UploadActivity extends AppCompatActivity {
private MispRestClient restClient;
private UploadAction availableAction, orgAction, userAction, serverAction;
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
@Override
public void available() {
mispAvailable(true, null);
}
@Override
public void unavailable(String error) {
mispAvailable(false, error);
}
};
private MispRestClient.OrganisationCallback organisationCallback = new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
organisationAdded(organisation);
}
@Override
public void failure(String error) {
organisationAdded(null);
}
};
private MispRestClient.UserCallback userCallback = new MispRestClient.UserCallback() {
@Override
public void success(User user) {
userAdded(user);
}
@Override
public void failure(String error) {
userAdded(null);
}
};
private MispRestClient.AllServersCallback allServersCallback = new MispRestClient.AllServersCallback() {
@Override
public void success(Server[] servers) {
allServersReceived(servers);
}
@Override
public void failure(String error) {
allServersReceived(null);
}
};
private MispRestClient.ServerCallback serverCallback = new MispRestClient.ServerCallback() {
@Override
public void success(Server server) {
serverAdded(server);
}
@Override
public void failure(String error) {
serverAdded(null);
}
};
private boolean errorWhileUpload;
@Override
@ -121,17 +175,12 @@ public class UploadActivity extends AppCompatActivity {
restClient.isAvailable(availableCallback);
}
private User generateSyncUser(Organisation organisation) {
User syncUser = new User();
syncUser.org_id = organisation.id;
syncUser.role_id = User.ROLE_SYNC_USER;
syncUser.email = uploadInformation.getRemote().syncUserEmail;
// String emailSaveOrgName = organisation.name.replace(" ", "").toLowerCase();
// String syncUserEmailFormat = uploadInformation.getRemote().syncUserEmail;
// syncUser.email = syncUserEmailFormat.replace("[ORG]", emailSaveOrgName);
// uploadInformation.getLocal().syncUserEmail = syncUser.email;
syncUser.password = uploadInformation.getRemote().syncUserPassword;
syncUser.authkey = uploadInformation.getRemote().syncUserAuthkey;
syncUser.termsaccepted = true;
@ -139,24 +188,35 @@ public class UploadActivity extends AppCompatActivity {
return syncUser;
}
private Server generateSyncServer() {
Server server = new Server();
server.name = uploadInformation.getRemote().organisation.name + "'s Sync Server";
server.url = uploadInformation.getRemote().baseUrl;
server.remote_org_id = uploadInformation.getRemote().organisation.id;
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
server.pull = uploadInformation.isPull();
server.push = uploadInformation.isPush();
server.caching_enabled = uploadInformation.isCached();
server.self_signed = uploadInformation.isAllowSelfSigned();
return server;
}
private MispRestClient.AvailableCallback availableCallback = new MispRestClient.AvailableCallback() {
@Override
public void available() {
private void mispAvailable(boolean available, String error) {
if (available) {
availableAction.setCurrentUploadState(UploadAction.UploadState.DONE);
orgAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
}
availableAction.setError(null);
@Override
public void unavailable(String error) {
restClient.addOrganisation(uploadInformation.getRemote().organisation, organisationCallback);
} else {
availableAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
availableAction.setError(error);
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
errorWhileUpload = true;
Snackbar sb = Snackbar.make(rootLayout, error, Snackbar.LENGTH_INDEFINITE);
sb.setAction("Retry", new View.OnClickListener() {
@Override
public void onClick(View v) {
@ -166,103 +226,83 @@ public class UploadActivity extends AppCompatActivity {
startUpload();
}
});
sb.show();
}
};
}
private MispRestClient.OrganisationCallback organisationCallback = new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
private void organisationAdded(Organisation organisation) {
if (organisation != null) {
orgAction.setCurrentUploadState(UploadAction.UploadState.DONE);
userAction.setCurrentUploadState(UploadAction.UploadState.LOADING);
// for later reference in add user callback
uploadInformation.getRemote().organisation.id = organisation.id;
restClient.addUser(generateSyncUser(organisation), userCallback);
}
@Override
public void failure(String error) {
orgAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
orgAction.setError(error);
errorWhileUpload = true;
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
}
};
private MispRestClient.UserCallback userCallback = new MispRestClient.UserCallback() {
@Override
public void success(User user) {
userAction.setCurrentUploadState(UploadAction.UploadState.DONE);
Server server = new Server();
server.name = uploadInformation.getRemote().organisation.name + "'s Sync Server";
server.url = uploadInformation.getRemote().baseUrl;
server.remote_org_id = uploadInformation.getRemote().organisation.id;
server.authkey = uploadInformation.getLocal().syncUserAuthkey;
server.pull = uploadInformation.isPull();
server.push = uploadInformation.isPush();
server.caching_enabled = uploadInformation.isCached();
server.self_signed = uploadInformation.isAllowSelfSigned();
restClient.addServer(server, serverCallback);
}
@Override
public void failure(String error) {
userAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
userAction.setError(error);
errorWhileUpload = true;
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
}
};
private MispRestClient.ServerCallback serverCallback = new MispRestClient.ServerCallback() {
@Override
public void success(List<MispServer> servers) {
}
@Override
public void success(Server server) {
serverAction.setCurrentUploadState(UploadAction.UploadState.DONE);
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
saveCurrentState();
}
@Override
public void failure(String error) {
serverAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
serverAction.setError(error);
errorWhileUpload = true;
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
}
};
private int organisationExists() throws IOException {
final UUID uuidToCheck = UUID.fromString(uploadInformation.getRemote().organisation.uuid);
Organisation[] organisations = restClient.getAllOrganisations();
if (organisations != null) {
for (Organisation organisation : organisations) {
if (uuidToCheck.compareTo(UUID.fromString(organisation.uuid)) == 0) {
return organisation.id;
} else {
restClient.getOrganisation(uploadInformation.getRemote().organisation.uuid, new MispRestClient.OrganisationCallback() {
@Override
public void success(Organisation organisation) {
organisationAdded(organisation);
}
@Override
public void failure(String error) {
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
orgAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
orgAction.setError(error);
errorWhileUpload = true;
}
});
}
}
private void userAdded(User user) {
if (user != null) {
userAction.setCurrentUploadState(UploadAction.UploadState.DONE);
restClient.getAllServers(allServersCallback);
} else {
restClient.getUser(uploadInformation.getRemote().syncUserEmail, new MispRestClient.UserCallback() {
@Override
public void success(User user) {
userAdded(user);
}
@Override
public void failure(String error) {
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
userAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
userAction.setError(error);
errorWhileUpload = true;
}
});
}
}
private void allServersReceived(Server[] servers) {
Server serverToUpload = generateSyncServer();
for (Server server : servers) {
if (server.remote_org_id.equals(serverToUpload.remote_org_id)) {
// server already exists
serverToUpload.id = server.id;
break;
}
}
return -1;
restClient.addServer(serverToUpload, serverCallback);
}
private int userExists() {
return -1;
private void serverAdded(Server server) {
if (server != null) {
serverAction.setCurrentUploadState(UploadAction.UploadState.DONE);
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.COMPLETE);
saveCurrentState();
} else {
uploadInformation.setCurrentSyncStatus(UploadInformation.SyncStatus.FAILURE);
serverAction.setCurrentUploadState(UploadAction.UploadState.ERROR);
serverAction.setError("Could not add server");
errorWhileUpload = true;
}
}
}

View File

@ -5,6 +5,7 @@ import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@ -46,8 +47,8 @@ public class UploadInfoActivity extends AppCompatActivity {
preferenceManager = PreferenceManager.getInstance(UploadInfoActivity.this);
// tint statusBar
getWindow().setStatusBarColor(getColor(R.color.white));
getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
getWindow().setStatusBarColor(getColor(R.color.colorPrimary));
// getWindow().getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);
parseExtra();
initToolbar();
@ -114,9 +115,12 @@ public class UploadInfoActivity extends AppCompatActivity {
ActionBar ab = getSupportActionBar();
assert ab != null;
ab.setTitle(uploadInformation.getRemote().organisation.name);
TextView toolbarTitle = findViewById(R.id.toolbarTitle);
toolbarTitle.setText(uploadInformation.getRemote().organisation.name);
ab.setHomeAsUpIndicator(R.drawable.ic_close);
ab.setDisplayShowTitleEnabled(true);
ab.setDisplayShowTitleEnabled(false);
ab.setDisplayHomeAsUpEnabled(true);
}

View File

@ -57,17 +57,28 @@ public class MispRestClient {
void failure(String error);
}
public interface AllUsersCallback {
void success(User[] users);
void failure(String error);
}
public interface OrganisationCallback {
void success(Organisation organisation);
void failure(String error);
}
public interface AllOrganisationsCallback {
void success(Organisation[] organisations);
void failure(String error);
}
public interface ServerCallback {
void success(List<MispServer> servers);
void success(Server server);
void failure(String error);
}
public interface AllServersCallback {
void success(Server[] servers);
void failure(String error);
}
@ -100,7 +111,7 @@ public class MispRestClient {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(url)
.addConverterFactory(GsonConverterFactory.create())
.client(getCustomClient(true, false))
.client(getCustomClient(true, true))
.build();
mispRestInterface = retrofit.create(MispRestInterface.class);
@ -250,6 +261,7 @@ public class MispRestClient {
* @param userId user identifier
* @param callback {@link UserCallback} wrapper to return user directly
*/
public void getUser(int userId, final UserCallback callback) {
Call<MispUser> call = mispRestInterface.getUser(userId);
@ -275,6 +287,57 @@ public class MispRestClient {
});
}
public void getUser(final String emailAddress, final UserCallback callback) {
getAllUsers(new AllUsersCallback() {
@Override
public void success(User[] users) {
for (User user : users) {
if (user.email.equals(emailAddress)) {
callback.success(user);
return;
}
}
callback.failure("Could not find user with email address {" + emailAddress + "}");
}
@Override
public void failure(String error) {
callback.failure(error);
}
});
}
public void getAllUsers(final AllUsersCallback callback) {
Call<List<MispUser>> call = mispRestInterface.getAllUsers();
call.enqueue(new Callback<List<MispUser>>() {
@Override
public void onResponse(Call<List<MispUser>> call, Response<List<MispUser>> response) {
if (!response.isSuccessful()) {
callback.failure("Failed onResponse");
return;
}
List<MispUser> mispUsers = response.body();
assert mispUsers != null;
User[] users = new User[mispUsers.size()];
for (int i = 0; i < users.length; i++) {
users[i] = mispUsers.get(i).user;
}
callback.success(users);
}
@Override
public void onFailure(Call<List<MispUser>> call, Throwable t) {
callback.failure(extractError(t));
}
});
}
/**
* Add a given user to the MISP instance referenced by url in preferences.
*
@ -335,45 +398,56 @@ public class MispRestClient {
});
}
public Organisation[] getAllOrganisations() throws IOException {
public void getOrganisation(final String uuid, final OrganisationCallback callback) {
getAllOrganisations(new AllOrganisationsCallback() {
@Override
public void success(Organisation[] organisations) {
for (Organisation organisation : organisations) {
if (organisation.uuid.equals(uuid)) {
callback.success(organisation);
return;
}
}
callback.failure("Could not find organisation with UUID {" + uuid + "}");
}
@Override
public void failure(String error) {
callback.failure(error);
}
});
}
public void getAllOrganisations(final AllOrganisationsCallback callback) {
Call<List<MispOrganisation>> call = mispRestInterface.getAllOrganisations();
Response<List<MispOrganisation>> response = call.execute();
List<MispOrganisation> mispOrganisations = response.body();
Organisation[] organisations = new Organisation[mispOrganisations.size()];
call.enqueue(new Callback<List<MispOrganisation>>() {
@Override
public void onResponse(Call<List<MispOrganisation>> call, Response<List<MispOrganisation>> response) {
if (!response.isSuccessful()) {
// TODO handle
return;
}
for (int i = 0; i < mispOrganisations.size(); i++) {
organisations[i] = mispOrganisations.get(i).organisation;
}
List<MispOrganisation> mispOrganisations = response.body();
return organisations;
assert mispOrganisations != null;
// call.enqueue(new Callback<List<MispOrganisation>>() {
// @Override
// public void onResponse(Call<List<MispOrganisation>> call, Response<List<MispOrganisation>> response) {
// if (!response.isSuccessful()) {
// // TODO handle
// return;
// }
//
// List<MispOrganisation> mispOrganisations = response.body();
//
// assert mispOrganisations != null;
//
// Organisation[] organisations = new Organisation[mispOrganisations.size()];
//
// for (int i = 0; i < mispOrganisations.size(); i++) {
// organisations[i] = mispOrganisations.get(i).organisation;
// }
//
// callback.success(organisations);
// }
//
// @Override
// public void onFailure(Call<List<MispOrganisation>> call, Throwable t) {
// callback.failure(extractError(t));
// }
// });
Organisation[] organisations = new Organisation[mispOrganisations.size()];
for (int i = 0; i < mispOrganisations.size(); i++) {
organisations[i] = mispOrganisations.get(i).organisation;
}
callback.success(organisations);
}
@Override
public void onFailure(Call<List<MispOrganisation>> call, Throwable t) {
callback.failure(extractError(t));
}
});
}
/**
@ -405,13 +479,17 @@ public class MispRestClient {
// --- server routes ---
public void getServer() {
}
/**
* Get all servers on MISP instance.
*
* @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
*/
public void getServers(final ServerCallback callback) {
Call<List<MispServer>> call = mispRestInterface.getServers();
public void getAllServers(final AllServersCallback callback) {
Call<List<MispServer>> call = mispRestInterface.getAllServers();
call.enqueue(new Callback<List<MispServer>>() {
@Override
@ -419,7 +497,17 @@ public class MispRestClient {
if (!response.isSuccessful()) {
callback.failure(extractError(response));
} else {
callback.success(response.body());
List<MispServer> mispServers = response.body();
assert mispServers != null;
Server[] servers = new Server[mispServers.size()];
for (int i = 0; i < servers.length; i++) {
servers[i] = mispServers.get(i).server;
}
callback.success(servers);
}
}
@ -452,6 +540,7 @@ public class MispRestClient {
@Override
public void onFailure(Call<Server> call, Throwable t) {
callback.failure(t.getMessage());
throw new RuntimeException(t);
}
});
}

View File

@ -53,6 +53,8 @@ public class UploadAction extends ConstraintLayout {
errorView = baseView.findViewById(R.id.error);
stateView = baseView.findViewById(R.id.stateView);
progressBar = baseView.findViewById(R.id.progressBar);
setCurrentUploadState(UploadState.PENDING);
}
@ -85,7 +87,7 @@ public class UploadAction extends ConstraintLayout {
case DONE:
stateView.setVisibility(VISIBLE);
stateView.setImageResource(R.drawable.ic_check);
stateView.setImageResource(R.drawable.ic_check_outline);
ImageViewCompat.setImageTintList(stateView, ColorStateList.valueOf(context.getColor(R.color.status_green)));
break;

View File

@ -1,24 +0,0 @@
package lu.circl.mispbump.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import lu.circl.mispbump.R;
public class UploadInfoFragment extends Fragment {
public UploadInfoFragment () {}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_upload_info, container, false);
return v;
}
}

View File

@ -33,6 +33,9 @@ public interface MispRestInterface {
@GET("users/view/{value}")
Call<MispUser> getUser(@Path("value") int userId);
@GET("admin/users")
Call<List<MispUser>> getAllUsers();
@POST("admin/users/add")
Call<MispUser> addUser(@Body User user);
@ -50,7 +53,7 @@ public interface MispRestInterface {
// server routes
@GET("servers/index")
Call<List<MispServer>> getServers();
Call<List<MispServer>> getAllServers();
@POST("servers/add")
Call<Server> addServer(@Body Server server);

View File

@ -34,6 +34,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -44,6 +45,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/white"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
@ -54,6 +56,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
@ -64,21 +67,10 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:background="@color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:description="Add sync server" />
</androidx.appcompat.widget.LinearLayoutCompat>
<!--<com.google.android.material.floatingactionbutton.FloatingActionButton-->
<!--android:id="@+id/fab"-->
<!--android:layout_width="wrap_content"-->
<!--android:layout_height="wrap_content"-->
<!--android:layout_gravity="bottom|end"-->
<!--android:layout_margin="16dp"-->
<!--app:backgroundTint="@color/colorAccent"-->
<!--android:tint="@color/white"-->
<!--android:src="@drawable/ic_cloud_upload"/>-->
</androidx.coordinatorlayout.widget.CoordinatorLayout>

View File

@ -2,6 +2,7 @@
<androidx.coordinatorlayout.widget.CoordinatorLayout
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:id="@+id/rootLayout"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -9,19 +10,34 @@
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white">
android:background="@color/colorPrimary">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/PopupTheme"
app:theme="@style/ToolbarTheme.Light"/>
app:theme="@style/ToolbarTheme">
<TextView
android:id="@+id/toolbarTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title"
tools:text="Organisation A"
android:layout_gravity="center"/>
</androidx.appcompat.widget.Toolbar>
<com.google.android.material.tabs.TabLayout
android:id="@+id/tabLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
app:tabBackground="@color/colorPrimary"
app:tabSelectedTextColor="@color/white"
app:tabTextColor="@color/white_50"
app:tabIndicatorFullWidth="true"
app:tabGravity="fill"
app:tabMode="fixed"/>
</com.google.android.material.appbar.AppBarLayout>

View File

@ -9,13 +9,15 @@
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="wrap_content"
android:paddingBottom="32dp">
<lu.circl.mispbump.customViews.MaterialPreferenceText
android:id="@+id/baseUrl"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@color/white"
app:subtitle="www.google.de"
app:title="Base URL"/>
@ -24,6 +26,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@color/white"
app:title="Authkey"
app:password="abc"/>
@ -32,6 +35,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@color/white"
android:elevation="4dp"
app:title="Password"
app:password="abc"/>
</LinearLayout>

View File

@ -6,7 +6,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:foreground="?attr/selectableItemBackground">
android:foreground="?attr/selectableItemBackgroundBorderless">
<ImageView
android:id="@+id/stateView"