servers);
+
+ void success(MispServer server);
+
+ void success(Server server);
+
+ void failure(String error);
+ }
+
+
+ private PreferenceManager preferenceManager;
+ private MispRestService mispRestService;
+
+ /**
+ * Initializes the rest client to communicate with a MISP instance.
+ *
+ * @param context needed to access the preferences for loading credentials
+ */
+ public MispRestClient(Context context) {
+ preferenceManager = PreferenceManager.getInstance(context);
+
+ String url = preferenceManager.getServerUrl();
+
+ Log.i(TAG, "URL: " + url);
+
+ try {
+ Retrofit retrofit = new Retrofit.Builder()
+ .baseUrl(url)
+ .addConverterFactory(GsonConverterFactory.create())
+ .client(getUnsafeOkHttpClient())
+ .build();
+
+ mispRestService = retrofit.create(MispRestService.class);
+ } catch (IllegalArgumentException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ /**
+ * NOTE: for development only!
+ *
+ * Accepts all certificates including self signed.
+ *
+ * @return {@link OkHttpClient} which accepts all certificates
+ */
+ private OkHttpClient getUnsafeOkHttpClient() {
+ try {
+ // Create a trust manager that does not validate certificate chains
+ final TrustManager[] trustAllCerts = new TrustManager[]{
+ new X509TrustManager() {
+ @SuppressLint("TrustAllX509TrustManager")
+ @Override
+ public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @SuppressLint("TrustAllX509TrustManager")
+ @Override
+ public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public java.security.cert.X509Certificate[] getAcceptedIssuers() {
+ return new java.security.cert.X509Certificate[]{};
+ }
+ }
+ };
+
+ // Install the all-trusting trust manager
+ final SSLContext sslContext = SSLContext.getInstance("SSL");
+ sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
+
+ // Create an ssl socket factory with our all-trusting manager
+ final SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory();
+
+ OkHttpClient.Builder builder = new OkHttpClient.Builder();
+ builder.sslSocketFactory(sslSocketFactory, (X509TrustManager)trustAllCerts[0]);
+ builder.hostnameVerifier(new HostnameVerifier() {
+ @Override
+ public boolean verify(String hostname, SSLSession session) {
+ return true;
+ }
+ });
+
+ // create logging interceptor
+ HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
+ interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
+ builder.addInterceptor(interceptor);
+
+ // create authorization interceptor
+ builder.addInterceptor(new Interceptor() {
+ @Override
+ public okhttp3.Response intercept(Chain chain) throws IOException {
+ Request.Builder ongoing = chain.request().newBuilder();
+ ongoing.addHeader("Accept", "application/json");
+ ongoing.addHeader("Content-Type", "application/json");
+ ongoing.addHeader("Authorization", preferenceManager.getAutomationKey());
+ return chain.proceed(ongoing.build());
+ }
+ });
+
+ return builder.build();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ // status routes
+
+ /**
+ * Check via pyMispRoute if server is available
+ *
+ * @param callback {@link AvailableCallback}
+ */
+ public void isAvailable(final AvailableCallback callback) {
+ Call call = mispRestService.pyMispVersion();
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ if (response.code() == 403) {
+ callback.available();
+ return;
+ }
+
+ callback.unavailable(extractError(response));
+ } else {
+ callback.available();
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ callback.unavailable(extractError(t));
+ }
+ });
+ }
+
+ // user routes
+
+ /**
+ * Fetches information about the user that is associated with saved auth key.
+ *
+ * @param callback {@link UserCallback} wrapper to return user directly
+ */
+ public void getMyUser(final UserCallback callback) {
+ Call call = mispRestService.getMyUserInformation();
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ if (response.body() != null) {
+ callback.success(response.body().user);
+ } else {
+ callback.failure("response body was null");
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ t.printStackTrace();
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ /**
+ * Get an user with specific ID.
+ *
+ * @param userId user identifier
+ * @param callback {@link UserCallback} wrapper to return user directly
+ */
+ public void getUser(int userId, final UserCallback callback) {
+ Call call = mispRestService.getUser(userId);
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ if (response.body() != null) {
+ callback.success(response.body().user);
+ } else {
+ callback.failure("response body was null");
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ t.printStackTrace();
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ /**
+ * Add a given user to the MISP instance referenced by url in preferences.
+ *
+ * @param user user to add
+ * @param callback {@link UserCallback} wrapper to return the created user directly
+ */
+ public void addUser(User user, final UserCallback callback) {
+ Call call = mispRestService.addUser(user);
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ assert response.body() != null;
+ callback.success(response.body().user);
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+
+ // organisation routes
+
+ /**
+ * Get an organisation by a given organisation id.
+ *
+ * @param orgId organisation identifier
+ * @param callback {@link OrganisationCallback} wrapper to return a organisation directly
+ */
+ public void getOrganisation(int orgId, final OrganisationCallback callback) {
+ Call call = mispRestService.getOrganisation(orgId);
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ if (response.body() != null) {
+ callback.success(response.body().organisation);
+ } else {
+ callback.failure("Response body was nul");
+ }
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ public Organisation[] getAllOrganisations() throws IOException {
+ Call> call = mispRestService.getAllOrganisations();
+ Response> response = call.execute();
+
+ List mispOrganisations = response.body();
+ Organisation[] organisations = new Organisation[mispOrganisations.size()];
+
+ for (int i = 0; i < mispOrganisations.size(); i++) {
+ organisations[i] = mispOrganisations.get(i).organisation;
+ }
+
+ return organisations;
+
+// call.enqueue(new Callback>() {
+// @Override
+// public void onResponse(Call> call, Response> response) {
+// if (!response.isSuccessful()) {
+// // TODO handle
+// return;
+// }
+//
+// List 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> call, Throwable t) {
+// callback.failure(extractError(t));
+// }
+// });
+ }
+
+ /**
+ * Add a given organisation to the MISP instance referenced by url in preferences.
+ *
+ * @param organisation organisation to add
+ * @param callback {@link OrganisationCallback} wrapper to return the created organisation directly
+ */
+ public void addOrganisation(Organisation organisation, final OrganisationCallback callback) {
+ Call call = mispRestService.addOrganisation(organisation);
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ assert response.body() != null;
+ callback.success(response.body().organisation);
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ // server routes
+
+ /**
+ * Get all servers on MISP instance.
+ *
+ * @param callback {@link OrganisationCallback} wrapper to return a list of servers directly
+ */
+ public void getServers(final ServerCallback callback) {
+ Call> call = mispRestService.getServers();
+
+ call.enqueue(new Callback>() {
+ @Override
+ public void onResponse(Call> call, Response> response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ callback.success(response.body());
+ }
+ }
+
+ @Override
+ public void onFailure(Call> call, Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ /**
+ * Add a server to the MISP instance
+ *
+ * @param server the server to create
+ * @param callback {@link ServerCallback} wrapper to return the created server directly
+ */
+ public void addServer(Server server, final ServerCallback callback) {
+ Call call = mispRestService.addServer(server);
+
+ call.enqueue(new Callback() {
+ @Override
+ public void onResponse(Call call, Response response) {
+ if (!response.isSuccessful()) {
+ callback.failure(extractError(response));
+ } else {
+ callback.success(response.body());
+ }
+ }
+
+ @Override
+ public void onFailure(Call call, Throwable t) {
+ callback.failure(t.getMessage());
+ }
+ });
+ }
+
+ // error parsing
+
+ /**
+ * Converts error {@link Response}s to human readable info.
+ * @param response erroneous response
+ * @param type of response
+ * @return human readable String that describes the error
+ */
+ private String extractError(Response response) {
+ switch (response.code()) {
+ // bad request (malformed)
+ case 400:
+ return "Bad request";
+
+ // unauthorized
+ case 401:
+ return "Unauthorized";
+
+ // forbidden
+ case 403:
+ try {
+ assert response.errorBody() != null;
+ JSONObject jsonError = new JSONObject(response.errorBody().string());
+
+ String name = jsonError.getString("name") + "\n";
+
+ if (name.startsWith("Authentication failed")) {
+ return "Authentication failed";
+ }
+
+ String reasons = "";
+ JSONObject errorReasons = jsonError.getJSONObject("errors");
+
+ Iterator 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";
+ }
+
+ /**
+ * Converts a {@link Throwable} to a human readable error message.
+ * @param t throwable
+ * @return human readable String that describes the error.
+ */
+ private String extractError(Throwable t) {
+
+ if (t.getCause() instanceof CertificateException) {
+ return "Trust anchor for certification path not found.\nSelf signed certificates are not supported.";
+ }
+
+ if (t instanceof SSLHandshakeException) {
+ return "SSL Handshake Error";
+ }
+
+ if (t instanceof NoRouteToHostException) {
+ return "Server is not available (no route to host)";
+ }
+
+ return t.getMessage();
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java
new file mode 100644
index 0000000..4eb6430
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispRestService.java
@@ -0,0 +1,53 @@
+package lu.circl.mispbump.restful_client;
+
+import java.util.List;
+
+import retrofit2.Call;
+import retrofit2.http.Body;
+import retrofit2.http.GET;
+import retrofit2.http.POST;
+import retrofit2.http.Path;
+
+/**
+ * RetroFit2 interface for communication with misp instances
+ */
+public interface MispRestService {
+
+ // settings routes
+
+ @GET("servers/getPyMISPVersion")
+ Call pyMispVersion();
+
+ // user routes
+
+ @GET("users/view/me")
+ Call getMyUserInformation();
+
+ @GET("users/view/{value}")
+ Call getUser(@Path("value") int userId);
+
+ @POST("admin/users/add")
+ Call addUser(@Body User user);
+
+ // organisation routes
+
+ @GET("organisations/view/{value}")
+ Call getOrganisation(@Path("value") int orgId);
+
+ @GET("organisations")
+ Call> getAllOrganisations();
+
+ @POST("admin/organisations/add")
+ Call addOrganisation(@Body Organisation organisation);
+
+ // server routes
+
+ @GET("servers/index")
+ Call> getServers();
+
+// @POST("servers/add")
+// Call addServer(@Body MispServer server);
+
+ @POST("servers/add")
+ Call addServer(@Body Server server);
+}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java
new file mode 100644
index 0000000..1c7b9b3
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispServer.java
@@ -0,0 +1,30 @@
+package lu.circl.mispbump.restful_client;
+
+import java.util.List;
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+public class MispServer {
+
+ public MispServer() {}
+
+ public MispServer(Server server, Organisation organisation, Organisation remoteOrganisation) {
+ this.server = server;
+ this.organisation = organisation;
+ this.remoteOrg = remoteOrganisation;
+ }
+
+ @SerializedName("Server")
+ @Expose
+ public Server server;
+ @SerializedName("Organisation")
+ @Expose
+ public Organisation organisation;
+ @SerializedName("RemoteOrg")
+ @Expose
+ public Organisation remoteOrg;
+ @SerializedName("User")
+ @Expose
+ public List user;
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java b/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java
new file mode 100644
index 0000000..4bcb275
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/MispUser.java
@@ -0,0 +1,15 @@
+package lu.circl.mispbump.restful_client;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+public class MispUser {
+
+ @SerializedName("User")
+ @Expose
+ public User user;
+
+ public MispUser(User user) {
+ this.user = user;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java b/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java
new file mode 100644
index 0000000..f24bd59
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/Organisation.java
@@ -0,0 +1,68 @@
+package lu.circl.mispbump.restful_client;
+
+/**
+ * Information gathered from Misp API about a organisation.
+ */
+public class Organisation {
+
+ public Integer id;
+ public String name;
+ public String date_created;
+ public String date_modified;
+ public String type;
+ public String nationality;
+ public String sector;
+ public String contacts;
+ public String description;
+ public Boolean local;
+ public String uuid;
+ public String restricted_to_domain;
+ public String created_by;
+ public Integer user_count;
+
+ public Organisation() {
+ }
+
+ public Organisation(String name) {
+ this.name = name;
+ }
+
+ public Organisation(String name, String description) {
+ this.name = name;
+ this.description = description;
+ }
+
+ public Organisation toSyncOrganisation() {
+ 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
+ public String toString() {
+ return "Organisation{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", date_created='" + date_created + '\'' +
+ ", date_modified='" + date_modified + '\'' +
+ ", type='" + type + '\'' +
+ ", nationality='" + nationality + '\'' +
+ ", sector='" + sector + '\'' +
+ ", contacts='" + contacts + '\'' +
+ ", description='" + description + '\'' +
+ ", local=" + local +
+ ", uuid='" + uuid + '\'' +
+ ", restricted_to_domain='" + restricted_to_domain + '\'' +
+ ", created_by='" + created_by + '\'' +
+ ", user_count=" + user_count +
+ '}';
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/Server.java b/app/src/main/java/lu/circl/mispbump/restful_client/Server.java
new file mode 100644
index 0000000..99ba9ad
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/Server.java
@@ -0,0 +1,109 @@
+package lu.circl.mispbump.restful_client;
+
+import com.google.gson.annotations.SerializedName;
+
+public class Server {
+
+ public Server() {}
+
+ public Server(String name, String url, String authkey, Integer remote_org_id) {
+ this.name = name;
+ this.url = url;
+ this.authkey = authkey;
+ this.remote_org_id = remote_org_id;
+ }
+
+ @SerializedName("id")
+ public Integer id;
+
+ @SerializedName("name")
+ public String name;
+
+ @SerializedName("url")
+ public String url;
+
+ @SerializedName("authkey")
+ public String authkey;
+
+ @SerializedName("org_id")
+ public Integer org_id;
+
+ @SerializedName("push")
+ public Boolean push;
+
+ @SerializedName("pull")
+ public Boolean pull;
+
+ @SerializedName("lastpulledid")
+ public Object lastpulledid;
+
+ @SerializedName("lastpushedid")
+ public Object lastpushedid;
+
+ @SerializedName("organization")
+ public Object organization;
+
+ @SerializedName("remote_org_id")
+ public Integer remote_org_id;
+
+ @SerializedName("publish_without_email")
+ public Boolean publish_without_email = false;
+
+ @SerializedName("unpublish_event")
+ public Boolean unpublish_event;
+
+ @SerializedName("self_signed")
+ public Boolean self_signed = false;
+
+ @SerializedName("pull_rules")
+ public String pull_rules;
+
+ @SerializedName("push_rules")
+ public String push_rules;
+
+ @SerializedName("cert_file")
+ public Object cert_file;
+
+ @SerializedName("client_cert_file")
+ public Object client_cert_file;
+
+ @SerializedName("internal")
+ public Boolean internal;
+
+ @SerializedName("skip_proxy")
+ public Boolean skip_proxy = false;
+
+ @SerializedName("caching_enabled")
+ public Boolean caching_enabled;
+
+ @SerializedName("cache_timestamp")
+ public Boolean cache_timestamp;
+
+ @Override
+ public String toString() {
+ return "Server{" +
+ "id=" + id +
+ ", name='" + name + '\'' +
+ ", url='" + url + '\'' +
+ ", authkey='" + authkey + '\'' +
+ ", org_id=" + org_id +
+ ", push=" + push +
+ ", pull=" + pull +
+ ", lastpulledid=" + lastpulledid +
+ ", lastpushedid=" + lastpushedid +
+ ", organization=" + organization +
+ ", remote_org_id=" + remote_org_id +
+ ", publish_without_email=" + publish_without_email +
+ ", unpublish_event=" + unpublish_event +
+ ", self_signed=" + self_signed +
+ ", pull_rules='" + pull_rules + '\'' +
+ ", push_rules='" + push_rules + '\'' +
+ ", cert_file=" + cert_file +
+ ", client_cert_file=" + client_cert_file +
+ ", internal=" + internal +
+ ", skip_proxy=" + skip_proxy +
+ ", caching_enabled=" + caching_enabled +
+ ", cache_timestamp=" + cache_timestamp +
+ '}';
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/User.java b/app/src/main/java/lu/circl/mispbump/restful_client/User.java
new file mode 100644
index 0000000..4535419
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/User.java
@@ -0,0 +1,125 @@
+package lu.circl.mispbump.restful_client;
+
+import com.google.gson.annotations.Expose;
+import com.google.gson.annotations.SerializedName;
+
+public class User {
+
+ public static final int ROLE_ADMIN = 1;
+ public static final int ROLE_ORG_ADMIN = 2;
+ public static final int ROLE_USER = 3;
+ public static final int ROLE_PUBLISHER = 4;
+ public static final int ROLE_SYNC_USER = 5;
+ public static final int ROLE_READ_ONLY = 6;
+
+ public User() {
+ }
+
+ public User(Integer org_id, String email, Integer role_id) {
+ this.org_id = org_id;
+ this.email = email;
+ this.role_id = role_id;
+ }
+
+ public User(Integer org_id, String email, Integer role_id, String password) {
+ this.password = password;
+ this.org_id = org_id;
+ this.email = email;
+ this.role_id = role_id;
+ }
+
+ @SerializedName("id")
+ @Expose
+ public Integer id;
+ @SerializedName("password")
+ @Expose
+ public String password;
+ @SerializedName("org_id")
+ @Expose
+ public Integer org_id;
+ @SerializedName("email")
+ @Expose
+ public String email;
+ @SerializedName("autoalert")
+ @Expose
+ public Boolean autoalert;
+ @SerializedName("authkey")
+ @Expose
+ public String authkey;
+ @SerializedName("invited_by")
+ @Expose
+ public String invited_by;
+ @SerializedName("gpgkey")
+ @Expose
+ public Object gpgkey;
+ @SerializedName("certif_public")
+ @Expose
+ public String certif_public;
+ @SerializedName("nids_sid")
+ @Expose
+ public String nids_sid;
+ @SerializedName("termsaccepted")
+ @Expose
+ public Boolean termsaccepted;
+ @SerializedName("newsread")
+ @Expose
+ public String newsread;
+ @SerializedName("role_id")
+ @Expose
+ public Integer role_id;
+ @SerializedName("change_pw")
+ @Expose
+ public String change_pw;
+ @SerializedName("contactalert")
+ @Expose
+ public Boolean contactalert;
+ @SerializedName("disabled")
+ @Expose
+ public Boolean disabled;
+ @SerializedName("expiration")
+ @Expose
+ public Object expiration;
+ @SerializedName("current_login")
+ @Expose
+ public String current_login;
+ @SerializedName("last_login")
+ @Expose
+ public String last_login;
+ @SerializedName("force_logout")
+ @Expose
+ public Boolean force_logout;
+ @SerializedName("date_created")
+ @Expose
+ public Object date_created;
+ @SerializedName("date_modified")
+ @Expose
+ public String date_modified;
+
+ @Override
+ public String toString() {
+ return "User{" +
+ "id='" + id + '\'' +
+ ", password='" + password + '\'' +
+ ", org_id='" + org_id + '\'' +
+ ", email='" + email + '\'' +
+ ", autoalert=" + autoalert +
+ ", authkey='" + authkey + '\'' +
+ ", invited_by='" + invited_by + '\'' +
+ ", gpgkey=" + gpgkey +
+ ", certif_public='" + certif_public + '\'' +
+ ", nids_sid='" + nids_sid + '\'' +
+ ", termsaccepted=" + termsaccepted +
+ ", newsread='" + newsread + '\'' +
+ ", role_id='" + role_id + '\'' +
+ ", change_pw='" + change_pw + '\'' +
+ ", contactalert=" + contactalert +
+ ", disabled=" + disabled +
+ ", expiration=" + expiration +
+ ", current_login='" + current_login + '\'' +
+ ", last_login='" + last_login + '\'' +
+ ", force_logout=" + force_logout +
+ ", date_created=" + date_created +
+ ", date_modified='" + date_modified + '\'' +
+ '}';
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/lu/circl/mispbump/restful_client/Version.java b/app/src/main/java/lu/circl/mispbump/restful_client/Version.java
new file mode 100644
index 0000000..5ba921e
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/restful_client/Version.java
@@ -0,0 +1,10 @@
+package lu.circl.mispbump.restful_client;
+
+import com.google.gson.annotations.SerializedName;
+
+public class Version {
+
+ @SerializedName("version")
+ public String version;
+
+}
diff --git a/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java b/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java
new file mode 100644
index 0000000..407b057
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/security/DiffieHellman.java
@@ -0,0 +1,147 @@
+package lu.circl.mispbump.security;
+
+import android.util.Base64;
+
+import javax.crypto.*;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Arrays;
+
+/**
+ * This class provides the functionality generate a shared secret key.
+ * Furthermore it contains the encryption/decryption methods.
+ */
+public class DiffieHellman {
+
+ private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
+ private static final String KEY_PAIR_ALGORITHM = "EC";
+ private static final int KEY_SIZE = 521; // 224 | 256 | 384 | 521
+ private static final String KEY_AGREEMENT_ALGORITHM = "ECDH";
+ private static final String KEY_FACTORY_ALGORITHM = "EC";
+
+ private static DiffieHellman instance;
+
+ private PublicKey publickey;
+ private KeyAgreement keyAgreement;
+
+ private byte[] sharedSecret;
+ private IvParameterSpec ivParameterSpec;
+
+
+ private DiffieHellman() {
+ initialize();
+ }
+
+ /**
+ * Singleton pattern
+ * @return {@link DiffieHellman}
+ */
+ public static DiffieHellman getInstance() {
+ if(instance == null) {
+ instance = new DiffieHellman();
+ }
+
+ return instance;
+ }
+
+ /**
+ * Generates a public and a private key using an elliptic curve algorithm.
+ * The private key is fed into the key agreement instance.
+ */
+ private void initialize() {
+ try {
+ KeyPairGenerator kpg = KeyPairGenerator.getInstance(KEY_PAIR_ALGORITHM);
+ kpg.initialize(KEY_SIZE);
+
+ KeyPair kp = kpg.generateKeyPair();
+ publickey = kp.getPublic();
+
+ keyAgreement = KeyAgreement.getInstance(KEY_AGREEMENT_ALGORITHM);
+ keyAgreement.init(kp.getPrivate());
+
+ } catch (NoSuchAlgorithmException | InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Encrypts data.
+ * @param data data to encrypt
+ * @return To String converted and encrypted data
+ */
+ public String encrypt(String data) {
+ try {
+ Cipher c = Cipher.getInstance(CIPHER_ALGORITHM);
+ c.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(sharedSecret, CIPHER_ALGORITHM), ivParameterSpec);
+
+ byte[] cipherText = c.doFinal(data.getBytes(StandardCharsets.UTF_8));
+ return Base64.encodeToString(cipherText, Base64.NO_WRAP);
+
+ } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ /**
+ * Decrypts data with the current shared secret.
+ * @param data data to decrypt
+ * @return To String converted and decrypted data
+ */
+ public String decrypt(String data) {
+ try {
+ Cipher c = Cipher.getInstance(CIPHER_ALGORITHM);
+ c.init(Cipher.DECRYPT_MODE, new SecretKeySpec(sharedSecret, CIPHER_ALGORITHM), ivParameterSpec);
+
+ byte[] cipherText = Base64.decode(data, Base64.NO_WRAP);
+ return new String(c.doFinal(cipherText), StandardCharsets.UTF_8);
+
+ } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ }
+ return data;
+ }
+
+ /**
+ * Generates a shared secret and derives an initialisation vector from it.
+ * @param pk public key of the sync partner
+ */
+ public void setForeignPublicKey(PublicKey pk) {
+ try {
+ keyAgreement.doPhase(pk, true);
+
+ byte[] tmpSharedSecret = keyAgreement.generateSecret();
+ sharedSecret = Arrays.copyOfRange(tmpSharedSecret, 0, 32);
+
+ byte[] inputVector = Arrays.copyOfRange(sharedSecret, 32, 48);
+ ivParameterSpec = new IvParameterSpec(inputVector);
+ } catch (InvalidKeyException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * @return this devices public key
+ */
+ public PublicKey getPublicKey() {
+ return publickey;
+ }
+
+ public static String publicKeyToString(PublicKey key) {
+ return Base64.encodeToString(key.getEncoded(), Base64.DEFAULT);
+ }
+
+ public static PublicKey publicKeyFromString(String key) throws NoSuchAlgorithmException, InvalidKeySpecException {
+ byte[] input = Base64.decode(key, Base64.DEFAULT);
+ return KeyFactory.getInstance(KEY_FACTORY_ALGORITHM).generatePublic(new X509EncodedKeySpec(input));
+ }
+}
diff --git a/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
new file mode 100644
index 0000000..0576074
--- /dev/null
+++ b/app/src/main/java/lu/circl/mispbump/security/KeyStoreWrapper.java
@@ -0,0 +1,273 @@
+package lu.circl.mispbump.security;
+
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.util.Base64;
+import android.util.Log;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
+import java.security.InvalidKeyException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.Arrays;
+import java.util.Enumeration;
+
+import javax.crypto.BadPaddingException;
+import javax.crypto.Cipher;
+import javax.crypto.IllegalBlockSizeException;
+import javax.crypto.KeyGenerator;
+import javax.crypto.NoSuchPaddingException;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+public class KeyStoreWrapper {
+
+ private static final String TAG = "KeyStoreWrapper";
+
+ public static final String USER_INFO_ALIAS = "ALIAS_USER_INFO";
+ public static final String USER_ORGANISATION_INFO_ALIAS = "ALIAS_USER_ORGANISATION_INFO";
+ public static final String AUTOMATION_ALIAS = "ALIAS_AUTOMATION_KEY";
+ public static final String SERVER_URL_ALIAS = "ALIAS_SERVER_URL";
+ public static final String UPLOAD_INFORMATION_ALIAS = "ALIAS_UPLOAD_INFORMATION";
+
+ private static final String KEYSTORE_PROVIDER = "AndroidKeyStore";
+ private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding";
+
+ private String KEYSTORE_ALIAS;
+
+ /**
+ * Wraps the android key store to easily encrypt and decrypt sensitive data.
+ * @param alias identifies a key store entry (see public static ALIAS variables).
+ */
+ public KeyStoreWrapper(String alias) {
+ KEYSTORE_ALIAS = alias;
+ }
+
+ /**
+ * @return wheter an entry for this alias already exists.
+ */
+ private boolean isInitialized() {
+ try {
+ KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
+ ks.load(null);
+
+ if (ks.containsAlias(KEYSTORE_ALIAS)) {
+ return true;
+ }
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return false;
+ }
+
+ /**
+ *
+ * @return SecretKey associated with the given alias.
+ */
+ private SecretKey getStoredKey() {
+ try {
+
+ KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
+ ks.load(null);
+ return (SecretKey) ks.getKey(KEYSTORE_ALIAS, null);
+
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (UnrecoverableKeyException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * Generates a new key.
+ * @return the newly generated key.
+ */
+ private SecretKey generateKey() {
+ try {
+
+ // androids key generator
+ final KeyGenerator keyGenerator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES, KEYSTORE_PROVIDER);
+
+ // specs for the generated key
+ final KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(KEYSTORE_ALIAS,
+ KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setKeySize(256)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ .build();
+
+ // initialize KeyGenerator and generate a secret key
+ keyGenerator.init(keyGenParameterSpec);
+ return keyGenerator.generateKey();
+
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (NoSuchProviderException e) {
+ e.printStackTrace();
+ } catch (InvalidAlgorithmParameterException e) {
+ e.printStackTrace();
+ }
+
+ return null;
+ }
+
+ /**
+ * Deletes the key associated with the current alias.
+ */
+ public void deleteStoredKey() {
+ try {
+ KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
+ ks.load(null);
+ ks.deleteEntry(KEYSTORE_ALIAS);
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Encrypt data with given algorithm and key associated with alias.
+ * @param data data to encrypt.
+ * @return encrypted data as String.
+ * @throws NoSuchPaddingException padding not found
+ * @throws NoSuchAlgorithmException algorithm not found
+ * @throws InvalidKeyException invalid key
+ * @throws BadPaddingException bad padding
+ * @throws IllegalBlockSizeException illegal block size
+ */
+ public String encrypt(String data) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+ SecretKey secretKey;
+
+ if (isInitialized()) {
+ secretKey = getStoredKey();
+ } else {
+ secretKey = generateKey();
+ }
+
+ final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+
+ byte[] byteData = data.getBytes(StandardCharsets.UTF_8);
+ byte[] combined = getCombinedArray(cipher.getIV(), cipher.doFinal(byteData));
+ return Base64.encodeToString(combined, Base64.NO_WRAP);
+ }
+
+ /**
+ * Decrypts data with given algorithm and key associated with alias.
+ * @param input encrypted data.
+ * @return decrypted data as String.
+ * @throws NoSuchPaddingException padding not found
+ * @throws NoSuchAlgorithmException algorithm not found
+ * @throws InvalidAlgorithmParameterException invalid algorithm parameters
+ * @throws InvalidKeyException invalid key
+ * @throws BadPaddingException bad padding
+ * @throws IllegalBlockSizeException illegal block size
+ */
+ public String decrypt(String input) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidAlgorithmParameterException, InvalidKeyException, BadPaddingException, IllegalBlockSizeException {
+
+ // extract iv from save data
+// String[] parts = input.split(":::");
+// byte[] iv = Base64.decode(parts[0], Base64.DEFAULT);
+// byte[] data = Base64.decode(parts[1], Base64.DEFAULT);
+
+ byte[] in = Base64.decode(input, Base64.NO_WRAP);
+ IvAndData ivAndData = splitCombinedArray(in, 12);
+
+ final Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+ final GCMParameterSpec gcmSpec = new GCMParameterSpec(128, ivAndData.iv);
+
+ cipher.init(Cipher.DECRYPT_MODE, getStoredKey(), gcmSpec);
+
+ return new String(cipher.doFinal(ivAndData.data), StandardCharsets.UTF_8);
+ }
+
+ /**
+ * Removes all aliases and the associated keys.
+ * Note: all encrypted data cannot be decrypted anymore!
+ */
+ public static void deleteAllStoredKeys() {
+ try {
+
+ KeyStore ks = KeyStore.getInstance(KEYSTORE_PROVIDER);
+ ks.load(null);
+
+ Log.i(TAG, "Size: " + ks.size());
+
+ Enumeration aliases = ks.aliases();
+
+ while (aliases.hasMoreElements()) {
+ String alias = aliases.nextElement();
+ ks.deleteEntry(alias);
+ }
+
+ } catch (KeyStoreException e) {
+ e.printStackTrace();
+ } catch (CertificateException e) {
+ e.printStackTrace();
+ } catch (NoSuchAlgorithmException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Combine IV and encrypted data.
+ * @param iv initialisation vector
+ * @param encryptedData encrypted data
+ * @return combination of iv and encrypted data
+ */
+ private byte[] getCombinedArray(byte[] iv, byte[] encryptedData) {
+
+ Log.i(TAG, "iv length = " + iv.length);
+
+ byte[] combined = new byte[iv.length + encryptedData.length];
+ for (int i = 0; i < combined.length; ++i) {
+ combined[i] = i < iv.length ? iv[i] : encryptedData[i - iv.length];
+ }
+ 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 {
+ IvAndData(byte[] iv, byte[] data) {
+ this.iv = iv;
+ this.data = data;
+ }
+
+ byte[] iv;
+ byte[] data;
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/res/anim/fade_in.xml b/app/src/main/res/anim/fade_in.xml
new file mode 100644
index 0000000..271b405
--- /dev/null
+++ b/app/src/main/res/anim/fade_in.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/fade_out.xml b/app/src/main/res/anim/fade_out.xml
new file mode 100644
index 0000000..b0caf35
--- /dev/null
+++ b/app/src/main/res/anim/fade_out.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/slide_down.xml b/app/src/main/res/anim/slide_down.xml
deleted file mode 100644
index ad40deb..0000000
--- a/app/src/main/res/anim/slide_down.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/anim/slide_in_right.xml b/app/src/main/res/anim/slide_in_right.xml
new file mode 100644
index 0000000..6fb52a3
--- /dev/null
+++ b/app/src/main/res/anim/slide_in_right.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/slide_out_left.xml b/app/src/main/res/anim/slide_out_left.xml
new file mode 100644
index 0000000..020a1be
--- /dev/null
+++ b/app/src/main/res/anim/slide_out_left.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/anim/slide_up.xml b/app/src/main/res/anim/slide_up.xml
deleted file mode 100644
index a731689..0000000
--- a/app/src/main/res/anim/slide_up.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/animator/rotation_cw.xml b/app/src/main/res/animator/rotation_cw.xml
new file mode 100644
index 0000000..fdc9066
--- /dev/null
+++ b/app/src/main/res/animator/rotation_cw.xml
@@ -0,0 +1,10 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/animator/slide_in_left.xml b/app/src/main/res/animator/slide_in_left.xml
new file mode 100644
index 0000000..ddc7c45
--- /dev/null
+++ b/app/src/main/res/animator/slide_in_left.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/animator/slide_in_right.xml b/app/src/main/res/animator/slide_in_right.xml
new file mode 100644
index 0000000..206720e
--- /dev/null
+++ b/app/src/main/res/animator/slide_in_right.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/animator/slide_out_left.xml b/app/src/main/res/animator/slide_out_left.xml
new file mode 100644
index 0000000..e3e2d1d
--- /dev/null
+++ b/app/src/main/res/animator/slide_out_left.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/animator/slide_out_right.xml b/app/src/main/res/animator/slide_out_right.xml
new file mode 100644
index 0000000..10d8add
--- /dev/null
+++ b/app/src/main/res/animator/slide_out_right.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
index 789e157..c7bd21d 100644
--- a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
+++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -1,34 +1,34 @@
-
-
-
-
-
-
-
-
-
+ xmlns:aapt="http://schemas.android.com/aapt"
+ android:width="108dp"
+ android:height="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108">
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/animated_sync.xml b/app/src/main/res/drawable/animated_sync.xml
new file mode 100644
index 0000000..575c7bb
--- /dev/null
+++ b/app/src/main/res/drawable/animated_sync.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/bottom_navigation_color_states.xml b/app/src/main/res/drawable/bottom_navigation_color_states.xml
new file mode 100644
index 0000000..dde925c
--- /dev/null
+++ b/app/src/main/res/drawable/bottom_navigation_color_states.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_account_circle.xml b/app/src/main/res/drawable/ic_account_circle.xml
new file mode 100644
index 0000000..e14b3e0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_account_circle.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/icon_arrow_right.xml b/app/src/main/res/drawable/ic_add.xml
similarity index 63%
rename from app/src/main/res/drawable/icon_arrow_right.xml
rename to app/src/main/res/drawable/ic_add.xml
index 25fb386..e3979cd 100644
--- a/app/src/main/res/drawable/icon_arrow_right.xml
+++ b/app/src/main/res/drawable/ic_add.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/app/src/main/res/drawable/ic_arrow_back.xml b/app/src/main/res/drawable/ic_arrow_back.xml
new file mode 100644
index 0000000..f8ad49c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_back.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_arrow_forward.xml b/app/src/main/res/drawable/ic_arrow_forward.xml
new file mode 100644
index 0000000..42d364a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_arrow_forward.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_autorenew.xml b/app/src/main/res/drawable/ic_autorenew.xml
new file mode 100644
index 0000000..3bdee48
--- /dev/null
+++ b/app/src/main/res/drawable/ic_autorenew.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_bank_note.xml b/app/src/main/res/drawable/ic_bank_note.xml
new file mode 100644
index 0000000..61b826e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_bank_note.xml
@@ -0,0 +1,13 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_check.xml b/app/src/main/res/drawable/ic_check.xml
new file mode 100644
index 0000000..d04a04c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_check_outline.xml b/app/src/main/res/drawable/ic_check_outline.xml
new file mode 100644
index 0000000..9e25fdc
--- /dev/null
+++ b/app/src/main/res/drawable/ic_check_outline.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_circuit_board.xml b/app/src/main/res/drawable/ic_circuit_board.xml
new file mode 100644
index 0000000..fb1d101
--- /dev/null
+++ b/app/src/main/res/drawable/ic_circuit_board.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_close.xml b/app/src/main/res/drawable/ic_close.xml
new file mode 100644
index 0000000..cbf794b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_close.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/icon_cloud_download.xml b/app/src/main/res/drawable/ic_cloud_download_black_24dp.xml
similarity index 100%
rename from app/src/main/res/drawable/icon_cloud_download.xml
rename to app/src/main/res/drawable/ic_cloud_download_black_24dp.xml
diff --git a/app/src/main/res/drawable/icon_cloud.xml b/app/src/main/res/drawable/ic_cloud_download_light_24dp.xml
similarity index 87%
rename from app/src/main/res/drawable/icon_cloud.xml
rename to app/src/main/res/drawable/ic_cloud_download_light_24dp.xml
index 0f28023..0feb270 100644
--- a/app/src/main/res/drawable/icon_cloud.xml
+++ b/app/src/main/res/drawable/ic_cloud_download_light_24dp.xml
@@ -1,5 +1,5 @@
-
+
diff --git a/app/src/main/res/drawable/ic_cloud_upload.xml b/app/src/main/res/drawable/ic_cloud_upload.xml
new file mode 100644
index 0000000..55dbbae
--- /dev/null
+++ b/app/src/main/res/drawable/ic_cloud_upload.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_code_black_24dp.xml b/app/src/main/res/drawable/ic_code_black_24dp.xml
new file mode 100644
index 0000000..5817fac
--- /dev/null
+++ b/app/src/main/res/drawable/ic_code_black_24dp.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_delete_forever.xml b/app/src/main/res/drawable/ic_delete_forever.xml
new file mode 100644
index 0000000..4469a5e
--- /dev/null
+++ b/app/src/main/res/drawable/ic_delete_forever.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_description.xml b/app/src/main/res/drawable/ic_description.xml
new file mode 100644
index 0000000..302bb4a
--- /dev/null
+++ b/app/src/main/res/drawable/ic_description.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_domain.xml b/app/src/main/res/drawable/ic_domain.xml
new file mode 100644
index 0000000..b7e6b25
--- /dev/null
+++ b/app/src/main/res/drawable/ic_domain.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/icon_add.xml b/app/src/main/res/drawable/ic_email_black_24dp.xml
similarity index 61%
rename from app/src/main/res/drawable/icon_add.xml
rename to app/src/main/res/drawable/ic_email_black_24dp.xml
index 0258249..ce97ab8 100644
--- a/app/src/main/res/drawable/icon_add.xml
+++ b/app/src/main/res/drawable/ic_email_black_24dp.xml
@@ -5,5 +5,5 @@
android:viewportHeight="24.0">
+ android:pathData="M20,4L4,4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6c0,-1.1 -0.9,-2 -2,-2zM20,8l-8,5 -8,-5L4,6l8,5 8,-5v2z"/>
diff --git a/app/src/main/res/drawable/ic_error_outline.xml b/app/src/main/res/drawable/ic_error_outline.xml
new file mode 100644
index 0000000..93db179
--- /dev/null
+++ b/app/src/main/res/drawable/ic_error_outline.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_help_outline.xml b/app/src/main/res/drawable/ic_help_outline.xml
new file mode 100644
index 0000000..fc62825
--- /dev/null
+++ b/app/src/main/res/drawable/ic_help_outline.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_info_outline.xml b/app/src/main/res/drawable/ic_info_outline.xml
new file mode 100644
index 0000000..af0d4d0
--- /dev/null
+++ b/app/src/main/res/drawable/ic_info_outline.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_key.xml b/app/src/main/res/drawable/ic_key.xml
new file mode 100644
index 0000000..ae7aa7b
--- /dev/null
+++ b/app/src/main/res/drawable/ic_key.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_keyboard_arrow_up.xml b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml
new file mode 100644
index 0000000..bc01039
--- /dev/null
+++ b/app/src/main/res/drawable/ic_keyboard_arrow_up.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_language.xml b/app/src/main/res/drawable/ic_language.xml
new file mode 100644
index 0000000..74bc279
--- /dev/null
+++ b/app/src/main/res/drawable/ic_language.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml
index 1fa43f1..2408e30 100644
--- a/app/src/main/res/drawable/ic_launcher_background.xml
+++ b/app/src/main/res/drawable/ic_launcher_background.xml
@@ -1,74 +1,74 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:height="108dp"
+ android:width="108dp"
+ android:viewportHeight="108"
+ android:viewportWidth="108"
+ xmlns:android="http://schemas.android.com/apk/res/android">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_location.xml b/app/src/main/res/drawable/ic_location.xml
new file mode 100644
index 0000000..7ce2348
--- /dev/null
+++ b/app/src/main/res/drawable/ic_location.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_open_in_browser.xml b/app/src/main/res/drawable/ic_open_in_browser.xml
new file mode 100644
index 0000000..3fb9799
--- /dev/null
+++ b/app/src/main/res/drawable/ic_open_in_browser.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_person.xml b/app/src/main/res/drawable/ic_person.xml
new file mode 100644
index 0000000..f0aedfe
--- /dev/null
+++ b/app/src/main/res/drawable/ic_person.xml
@@ -0,0 +1,9 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_polka_dots.xml b/app/src/main/res/drawable/ic_polka_dots.xml
new file mode 100644
index 0000000..30d036f
--- /dev/null
+++ b/app/src/main/res/drawable/ic_polka_dots.xml
@@ -0,0 +1,13 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_qrcode.xml b/app/src/main/res/drawable/ic_qrcode.xml
new file mode 100644
index 0000000..b1092e9
--- /dev/null
+++ b/app/src/main/res/drawable/ic_qrcode.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_qrcode_scan.xml b/app/src/main/res/drawable/ic_qrcode_scan.xml
new file mode 100644
index 0000000..d740f75
--- /dev/null
+++ b/app/src/main/res/drawable/ic_qrcode_scan.xml
@@ -0,0 +1,8 @@
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_sector.xml b/app/src/main/res/drawable/ic_sector.xml
new file mode 100644
index 0000000..eb94181
--- /dev/null
+++ b/app/src/main/res/drawable/ic_sector.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_settings.xml b/app/src/main/res/drawable/ic_settings.xml
new file mode 100644
index 0000000..1397d37
--- /dev/null
+++ b/app/src/main/res/drawable/ic_settings.xml
@@ -0,0 +1,5 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_sync_black_24dp.xml b/app/src/main/res/drawable/ic_sync_black_24dp.xml
new file mode 100644
index 0000000..dd197a6
--- /dev/null
+++ b/app/src/main/res/drawable/ic_sync_black_24dp.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_wiggle.xml b/app/src/main/res/drawable/ic_wiggle.xml
new file mode 100644
index 0000000..0e3e6fa
--- /dev/null
+++ b/app/src/main/res/drawable/ic_wiggle.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/icon_check.xml b/app/src/main/res/drawable/icon_check.xml
deleted file mode 100644
index 459aef9..0000000
--- a/app/src/main/res/drawable/icon_check.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_close.xml b/app/src/main/res/drawable/icon_close.xml
deleted file mode 100644
index ede4b71..0000000
--- a/app/src/main/res/drawable/icon_close.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_cloud_upload.xml b/app/src/main/res/drawable/icon_cloud_upload.xml
deleted file mode 100644
index 7d0637d..0000000
--- a/app/src/main/res/drawable/icon_cloud_upload.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_contact.xml b/app/src/main/res/drawable/icon_contact.xml
deleted file mode 100644
index 0d6b3bb..0000000
--- a/app/src/main/res/drawable/icon_contact.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_forward.xml b/app/src/main/res/drawable/icon_forward.xml
deleted file mode 100644
index cf9e208..0000000
--- a/app/src/main/res/drawable/icon_forward.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_hour_glass.xml b/app/src/main/res/drawable/icon_hour_glass.xml
deleted file mode 100644
index fa7abc6..0000000
--- a/app/src/main/res/drawable/icon_hour_glass.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_key.xml b/app/src/main/res/drawable/icon_key.xml
deleted file mode 100644
index 2eddd16..0000000
--- a/app/src/main/res/drawable/icon_key.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_retry.xml b/app/src/main/res/drawable/icon_retry.xml
deleted file mode 100644
index 794ca6a..0000000
--- a/app/src/main/res/drawable/icon_retry.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_round_check.xml b/app/src/main/res/drawable/icon_round_check.xml
deleted file mode 100644
index 529c91e..0000000
--- a/app/src/main/res/drawable/icon_round_check.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
diff --git a/app/src/main/res/drawable/icon_round_error.xml b/app/src/main/res/drawable/icon_round_error.xml
deleted file mode 100644
index cb3b30a..0000000
--- a/app/src/main/res/drawable/icon_round_error.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/icon_settings.xml b/app/src/main/res/drawable/icon_settings.xml
deleted file mode 100644
index ce997a7..0000000
--- a/app/src/main/res/drawable/icon_settings.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-
-
-
diff --git a/app/src/main/res/drawable/rounded_rect.xml b/app/src/main/res/drawable/rounded_rect.xml
new file mode 100644
index 0000000..8daefbc
--- /dev/null
+++ b/app/src/main/res/drawable/rounded_rect.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/rounded_square.xml b/app/src/main/res/drawable/rounded_square.xml
deleted file mode 100644
index e042271..0000000
--- a/app/src/main/res/drawable/rounded_square.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_home.xml b/app/src/main/res/layout/activity_home.xml
new file mode 100644
index 0000000..cb08ed5
--- /dev/null
+++ b/app/src/main/res/layout/activity_home.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_login.xml b/app/src/main/res/layout/activity_login.xml
new file mode 100644
index 0000000..1cb59dc
--- /dev/null
+++ b/app/src/main/res/layout/activity_login.xml
@@ -0,0 +1,105 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
deleted file mode 100644
index 3dee13c..0000000
--- a/app/src/main/res/layout/activity_main.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/activity_my_organisation.xml b/app/src/main/res/layout/activity_my_organisation.xml
deleted file mode 100644
index b0b60b6..0000000
--- a/app/src/main/res/layout/activity_my_organisation.xml
+++ /dev/null
@@ -1,63 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_preference.xml b/app/src/main/res/layout/activity_preference.xml
new file mode 100644
index 0000000..b471d0f
--- /dev/null
+++ b/app/src/main/res/layout/activity_preference.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_profile.xml b/app/src/main/res/layout/activity_profile.xml
new file mode 100644
index 0000000..f39fdea
--- /dev/null
+++ b/app/src/main/res/layout/activity_profile.xml
@@ -0,0 +1,145 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_qr_sync.xml b/app/src/main/res/layout/activity_qr_sync.xml
deleted file mode 100644
index f2a5e48..0000000
--- a/app/src/main/res/layout/activity_qr_sync.xml
+++ /dev/null
@@ -1,69 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_sync.xml b/app/src/main/res/layout/activity_sync.xml
new file mode 100644
index 0000000..6c823e7
--- /dev/null
+++ b/app/src/main/res/layout/activity_sync.xml
@@ -0,0 +1,96 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_upload.xml b/app/src/main/res/layout/activity_upload.xml
index bba536e..6574145 100644
--- a/app/src/main/res/layout/activity_upload.xml
+++ b/app/src/main/res/layout/activity_upload.xml
@@ -1,74 +1,90 @@
+
-
+
-
+
+
-
+
-
+
-
+
-
-
+
-
+
-
+
-
+
-
-
-
-
-
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_sheet_public_key.xml b/app/src/main/res/layout/bottom_sheet_public_key.xml
new file mode 100644
index 0000000..66e4777
--- /dev/null
+++ b/app/src/main/res/layout/bottom_sheet_public_key.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/bottom_sheet_sync_information.xml b/app/src/main/res/layout/bottom_sheet_sync_information.xml
new file mode 100644
index 0000000..5d2c2d0
--- /dev/null
+++ b/app/src/main/res/layout/bottom_sheet_sync_information.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_enter_credentials.xml b/app/src/main/res/layout/dialog_enter_credentials.xml
deleted file mode 100644
index 20d7bf6..0000000
--- a/app/src/main/res/layout/dialog_enter_credentials.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_public_key.xml b/app/src/main/res/layout/dialog_public_key.xml
deleted file mode 100644
index 54122d8..0000000
--- a/app/src/main/res/layout/dialog_public_key.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_save_authkey.xml b/app/src/main/res/layout/dialog_save_authkey.xml
deleted file mode 100644
index fd9e56f..0000000
--- a/app/src/main/res/layout/dialog_save_authkey.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_select_delete_data.xml b/app/src/main/res/layout/dialog_select_delete_data.xml
deleted file mode 100644
index 82c7388..0000000
--- a/app/src/main/res/layout/dialog_select_delete_data.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/dialog_sync_info.xml b/app/src/main/res/layout/dialog_sync_info.xml
deleted file mode 100644
index 133dad2..0000000
--- a/app/src/main/res/layout/dialog_sync_info.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_camera.xml b/app/src/main/res/layout/fragment_camera.xml
index b1233a8..7bd5ce8 100644
--- a/app/src/main/res/layout/fragment_camera.xml
+++ b/app/src/main/res/layout/fragment_camera.xml
@@ -1,18 +1,28 @@
-
+
-
+
-
\ No newline at end of file
+
+
+
diff --git a/app/src/main/res/layout/fragment_sync_options.xml b/app/src/main/res/layout/fragment_sync_options.xml
new file mode 100644
index 0000000..7b32505
--- /dev/null
+++ b/app/src/main/res/layout/fragment_sync_options.xml
@@ -0,0 +1,147 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/material_preference_text.xml b/app/src/main/res/layout/material_preference_text.xml
new file mode 100644
index 0000000..cc188b5
--- /dev/null
+++ b/app/src/main/res/layout/material_preference_text.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/row_org_info_entry.xml b/app/src/main/res/layout/row_org_info_entry.xml
deleted file mode 100644
index 5a244f5..0000000
--- a/app/src/main/res/layout/row_org_info_entry.xml
+++ /dev/null
@@ -1,31 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/row_synced_organisation.xml b/app/src/main/res/layout/row_synced_organisation.xml
deleted file mode 100644
index daaa5bf..0000000
--- a/app/src/main/res/layout/row_synced_organisation.xml
+++ /dev/null
@@ -1,56 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/row_upload_state.xml b/app/src/main/res/layout/row_upload_state.xml
deleted file mode 100644
index f188423..0000000
--- a/app/src/main/res/layout/row_upload_state.xml
+++ /dev/null
@@ -1,59 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_organisation.xml b/app/src/main/res/layout/view_organisation.xml
deleted file mode 100644
index 2564feb..0000000
--- a/app/src/main/res/layout/view_organisation.xml
+++ /dev/null
@@ -1,84 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/app/src/main/res/layout/view_pk_info.xml b/app/src/main/res/layout/view_pk_info.xml
deleted file mode 100644
index 0bbdef9..0000000
--- a/app/src/main/res/layout/view_pk_info.xml
+++ /dev/null
@@ -1,36 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/res/layout/view_upload_action.xml b/app/src/main/res/layout/view_upload_action.xml
new file mode 100644
index 0000000..9d88e7c
--- /dev/null
+++ b/app/src/main/res/layout/view_upload_action.xml
@@ -0,0 +1,45 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/viewholder_sync.xml b/app/src/main/res/layout/viewholder_sync.xml
new file mode 100644
index 0000000..2d262e7
--- /dev/null
+++ b/app/src/main/res/layout/viewholder_sync.xml
@@ -0,0 +1,156 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/viewholder_user.xml b/app/src/main/res/layout/viewholder_user.xml
new file mode 100644
index 0000000..f3950c3
--- /dev/null
+++ b/app/src/main/res/layout/viewholder_user.xml
@@ -0,0 +1,43 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/main_menu.xml b/app/src/main/res/menu/main_menu.xml
new file mode 100644
index 0000000..3defc8b
--- /dev/null
+++ b/app/src/main/res/menu/main_menu.xml
@@ -0,0 +1,16 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_login.xml b/app/src/main/res/menu/menu_login.xml
new file mode 100644
index 0000000..83ee6ad
--- /dev/null
+++ b/app/src/main/res/menu/menu_login.xml
@@ -0,0 +1,11 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_main.xml b/app/src/main/res/menu/menu_main.xml
deleted file mode 100644
index e49f064..0000000
--- a/app/src/main/res/menu/menu_main.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_my_org.xml b/app/src/main/res/menu/menu_my_org.xml
deleted file mode 100644
index 97841d1..0000000
--- a/app/src/main/res/menu/menu_my_org.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-
-
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_profile.xml b/app/src/main/res/menu/menu_profile.xml
new file mode 100644
index 0000000..8388c42
--- /dev/null
+++ b/app/src/main/res/menu/menu_profile.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/menu_sync.xml b/app/src/main/res/menu/menu_sync.xml
new file mode 100644
index 0000000..7d4e56e
--- /dev/null
+++ b/app/src/main/res/menu/menu_sync.xml
@@ -0,0 +1,9 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
index db69e7e..bbd3e02 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
index db69e7e..bbd3e02 100644
--- a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
+++ b/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -1,5 +1,5 @@
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png
index a2f5908..898f3ed 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
index 1b52399..dffca36 100644
Binary files a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-hdpi/launcher_handshake_round.png b/app/src/main/res/mipmap-hdpi/launcher_handshake_round.png
deleted file mode 100644
index aa2f41a..0000000
Binary files a/app/src/main/res/mipmap-hdpi/launcher_handshake_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/launcher_handshake_square.png b/app/src/main/res/mipmap-hdpi/launcher_handshake_square.png
deleted file mode 100644
index 7d50fb2..0000000
Binary files a/app/src/main/res/mipmap-hdpi/launcher_handshake_square.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-hdpi/launcher_round_2.png b/app/src/main/res/mipmap-hdpi/launcher_round_2.png
deleted file mode 100644
index c41209a..0000000
Binary files a/app/src/main/res/mipmap-hdpi/launcher_round_2.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png
index ff10afd..64ba76f 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
index 115a4c7..dae5e08 100644
Binary files a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-mdpi/launcher_handshake_round.png b/app/src/main/res/mipmap-mdpi/launcher_handshake_round.png
deleted file mode 100644
index 8d1c20c..0000000
Binary files a/app/src/main/res/mipmap-mdpi/launcher_handshake_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/launcher_handshake_square.png b/app/src/main/res/mipmap-mdpi/launcher_handshake_square.png
deleted file mode 100644
index b667a85..0000000
Binary files a/app/src/main/res/mipmap-mdpi/launcher_handshake_square.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-mdpi/launcher_round_2.png b/app/src/main/res/mipmap-mdpi/launcher_round_2.png
deleted file mode 100644
index 6eea0a2..0000000
Binary files a/app/src/main/res/mipmap-mdpi/launcher_round_2.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png
index dcd3cd8..e5ed465 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
index 459ca60..14ed0af 100644
Binary files a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xhdpi/launcher_handshake_round.png b/app/src/main/res/mipmap-xhdpi/launcher_handshake_round.png
deleted file mode 100644
index 8fbf9bb..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/launcher_handshake_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/launcher_handshake_square.png b/app/src/main/res/mipmap-xhdpi/launcher_handshake_square.png
deleted file mode 100644
index fa562a7..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/launcher_handshake_square.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xhdpi/launcher_round_2.png b/app/src/main/res/mipmap-xhdpi/launcher_round_2.png
deleted file mode 100644
index e318340..0000000
Binary files a/app/src/main/res/mipmap-xhdpi/launcher_round_2.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
index 8ca12fe..b0907ca 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
index 8e19b41..d8ae031 100644
Binary files a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxhdpi/launcher_handshake_round.png b/app/src/main/res/mipmap-xxhdpi/launcher_handshake_round.png
deleted file mode 100644
index 54659ec..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/launcher_handshake_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/launcher_handshake_square.png b/app/src/main/res/mipmap-xxhdpi/launcher_handshake_square.png
deleted file mode 100644
index 1ba2b77..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/launcher_handshake_square.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxhdpi/launcher_round_2.png b/app/src/main/res/mipmap-xxhdpi/launcher_round_2.png
deleted file mode 100644
index d440e89..0000000
Binary files a/app/src/main/res/mipmap-xxhdpi/launcher_round_2.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
index b824ebd..2c18de9 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
index 4c19a13..beed3cd 100644
Binary files a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_round.png b/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_round.png
deleted file mode 100644
index 92de8dc..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_round.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_square.png b/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_square.png
deleted file mode 100644
index 83ba86f..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/launcher_handshake_square.png and /dev/null differ
diff --git a/app/src/main/res/mipmap-xxxhdpi/launcher_round_2.png b/app/src/main/res/mipmap-xxxhdpi/launcher_round_2.png
deleted file mode 100644
index e0f8838..0000000
Binary files a/app/src/main/res/mipmap-xxxhdpi/launcher_round_2.png and /dev/null differ
diff --git a/app/src/main/res/raw/misp.crt b/app/src/main/res/raw/misp.crt
new file mode 100644
index 0000000..00f458a
--- /dev/null
+++ b/app/src/main/res/raw/misp.crt
@@ -0,0 +1,23 @@
+-----BEGIN CERTIFICATE-----
+MIIDwzCCAqugAwIBAgIUEHRo5YZyVzJRWcqG4zHzG68DoTgwDQYJKoZIhvcNAQEL
+BQAwcTELMAkGA1UEBhMCREUxDDAKBgNVBAgMA05SVzENMAsGA1UEBwwEQm9ubjEO
+MAwGA1UECgwFRmVsaXgxEjAQBgNVBAMMCWxvY2FsaG9zdDEhMB8GCSqGSIb3DQEJ
+ARYSZmVsaXhwa0BvdXRsb29rLmRlMB4XDTE5MDUxMzA4NTEwOVoXDTIwMDUxMjA4
+NTEwOVowcTELMAkGA1UEBhMCREUxDDAKBgNVBAgMA05SVzENMAsGA1UEBwwEQm9u
+bjEOMAwGA1UECgwFRmVsaXgxEjAQBgNVBAMMCWxvY2FsaG9zdDEhMB8GCSqGSIb3
+DQEJARYSZmVsaXhwa0BvdXRsb29rLmRlMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
+MIIBCgKCAQEA0ut7qAzPuNPoZmQNCyOkDL8szBT6+pspGNQHQpL7GG5UotlniXcp
+q+FtF4X4PEow5P0aRMBG72QIxUzAtFiqK2/RCbK3ECrKezedM26BT0xkEB/eUU7E
+RQIO+XYa4JUi+g+YwnDCnPWexGIsztq+vvHXdny+uMeRCBFQxiPuPwdB4uPQyy8d
+kv9XNScRCOu4Hp4IaFBIw5V7uP71WdyoHjD7NBbzubrVjcr+I0DC+MbpJOKpM/YB
+lbp+I9NeA/rWZ4r6rrMAVOv6tV2dgnQ+6cWOFBiM3ZkxuocPWg/iI4UzdSsy2K/W
+qONJfAjAqkmgkBBr2cyW5wwWEN8J994DIwIDAQABo1MwUTAdBgNVHQ4EFgQUWsMY
+gtEo2b2WtuROWMfRDKzwTT0wHwYDVR0jBBgwFoAUWsMYgtEo2b2WtuROWMfRDKzw
+TT0wDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAmGU2K9isN1Wm
+2PksR92pKrs7SJom2L3o7V3ui8oZ2FZrLx/IUeUA4aSmSeyqbxuziPqYUkO0ku1t
+9ASaf9yaNS7CULDftgoebLzlIEwktvEI3XixpRIfJJywHSG5eLsG51D65hyuOZ2z
+s0Y94HzvKX4fIaXv7NxGCW+xHhc6anxYKrXFldFwv3z/NHq0pzvd/aebbfuEeggH
+xpmA3dgi0y0meTLKzYzDypEhkUPiq6u8R+cEuFgSun89/fW80VktEo+32tkaczEm
+qjcZGfUFGNGG08p6MfRSl9PSakpdymV+aKK+TxB5nACe/RmISkqLz9REDlzUyNDm
+yArY8SEbhg==
+-----END CERTIFICATE-----
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index b0f7753..11144ba 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -1,52 +1,14 @@
- MISPBump
-
- Verlassen
- Zurück
- Sie haben bisher keine Instanzen verknüpft
- Keine lokalen Informationen vorhanden
- Autorisierungschlüssel speichern (potentielles Sicherheitsrisiko)
- Ungesicherte Änderungen
- Wollen Sie die Änderungen sichern?
- Speichern
- Verwerfen
- Lokale Informationen fehlen
- Bitte laden Sie erst die fehlenden Informationen von Ihrer Instanz
- Informationen Laden
- Hochladen
- Akzeptieren
- Ablehnen
- Öffentlicher Schlüssel
- QR Code
- weiter
- Löschen
- Lokale Daten löschen
- Die URL, der Autorisierungsschlüssel und ihre lokalen Daten werden gelöscht. \n\nHinweis: diese Informationen sind für eine Synchronissierung notwendig
-
- Überschreiben
- Lokale Daten überschreiben
- Wollen Sie wirklich die lokalen Daten auf diesem Gerät überschreiben?
-
- Synchronisierungs Profil
-
- Server URL
- Autorisierungsschlüssel
-
- Autentifizierungseinstellungen
-
- Sync Informationen
-
- MISP Url benötigt
- MISP Automatisierungsschlüssel benötigt
- In Zwischenablage kopiert
- %1$s im Browser öffnen?
- Im Browser öffnen
- öffnen
- Einstellungen
- Wurde Ihr Öffentlicher Schlüssel bereits von Ihrem Partner gescannt?
- Wurden Ihre Synchronisations Informationen bereits von Ihrem Partner gescannt?
- Ja
- Nein
- Fortfahren
+ MispBump
+ Anmelden
+ Abmelden
+ Hilfe
+ MISP Automatisierungs-Schlüssel
+ Keine Informationen
+ Automatisierungs-Schlüssel speichern
+ MISP Server URL\nDie URL unter der Ihre MISP Instanz erreichbar ist.\n\nMISP Automatisierungs Schlüssel\nZu finden unter ...
+ QR code
+ Synchronisation
+ Sie haben noch keine MISP Instanzen verknüpft.
\ No newline at end of file
diff --git a/app/src/main/res/values/attrs.xml b/app/src/main/res/values/attrs.xml
new file mode 100644
index 0000000..1fa0848
--- /dev/null
+++ b/app/src/main/res/values/attrs.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml
index 5e41eb5..cc2e9fc 100644
--- a/app/src/main/res/values/colors.xml
+++ b/app/src/main/res/values/colors.xml
@@ -1,11 +1,17 @@
- #ffffff
- #424242
- #212121
- #42a5f5
- #AA42a5f5
- #FFF
- #00c853
- #BB00c853
+ #047EB4
+ #023850
+
+ #12B3FA
+ #8012B3FA
+
+ #33000000
+
+
+ #FFFFFF
+ #80FFFFFF
+ #4CAF50
+ #FB8C00
+ #E53935
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 741b754..d881361 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -1,56 +1,16 @@
- MISPBump
-
- Exit
- Next
- Back
-
- You have not synced any instances yet
- No local information available
- Save auth-key (potential security risk)
- Unsaved changes
- Do you want to save the changes?
- Save
- Discard
- Missing local information
- Please fetch the missing information from your instance first
- Fetch information
- Upload
- Accept
- Reject
- Public Key
- QR code
- continue
- delete
- Delete local data
-
- This action will delete the URL, automation key and your downloaded organisation information.
- \n\nKeep in mind that the latter is required for synchronisation.
-
- override
- Override local data
- Do you really want to override the local information stored on this device?
- Sync Profile
- Server URL
- Authkey
- Credential Settings
- Sync Information
-
- Enter MISP base url
- Enter MISP automation key
- Copied to clipboard
- Open %1$s in browser?
- Open in browser
- open
- Settings
- Has your sync partner scanned your Public Key?
- Has your sync partner scanned your Sync Information?
- Yes
- No
- Proceed
-
-
- Hello blank fragment
-
-
+ MispBump
+ Log in
+ Log out
+ MISP Server URL
+ MISP Automation Key
+ No Information
+ Save Automation Key
+ Home
+ Help
+ MISP Server URL\nPublic MISP URL\n\nMISP Automation key\nZu finden unter ...
+ Okay
+ QR code
+ Synchronization
+ You have not synced any MISP instances yet.
diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml
index 15ac006..3116eeb 100644
--- a/app/src/main/res/values/styles.xml
+++ b/app/src/main/res/values/styles.xml
@@ -1,24 +1,26 @@
+
-
+
-
+
-
+
-
-
+
+
diff --git a/app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
similarity index 90%
rename from app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java
rename to app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
index 2ff2654..ef7a9dd 100644
--- a/app/src/test/java/de/overview/wg/its/mispbump/ExampleUnitTest.java
+++ b/app/src/test/java/lu/circl/mispbump/ExampleUnitTest.java
@@ -1,4 +1,4 @@
-package de.overview.wg.its.mispbump;
+package lu.circl.mispbump;
import org.junit.Test;
diff --git a/build.gradle b/build.gradle
index 909e1a2..e0e9fa2 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,14 +1,15 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
-
+ ext.kotlin_version = '1.3.31'
repositories {
google()
jcenter()
+
}
-
dependencies {
- classpath 'com.android.tools.build:gradle:3.1.3'
+ classpath 'com.android.tools.build:gradle:3.4.1'
+ classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@@ -19,8 +20,6 @@ allprojects {
repositories {
google()
jcenter()
-
- maven { url "https://jitpack.io" }
}
}
diff --git a/gradle.properties b/gradle.properties
index 743d692..34470d8 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -6,8 +6,12 @@
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
+android.useAndroidX=true
+android.enableJetifier=true
org.gradle.jvmargs=-Xmx1536m
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
+
+
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
index 01b8bf6..f6b961f 100644
Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 933b647..4e2d414 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Wed May 08 12:00:08 CEST 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-5.1.1-all.zip
diff --git a/gradlew b/gradlew
new file mode 100755
index 0000000..cccdd3d
--- /dev/null
+++ b/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/gradlew.bat b/gradlew.bat
new file mode 100644
index 0000000..e95643d
--- /dev/null
+++ b/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega