improve readme add string/content descriptionpull/10/head
| @@ -4,13 +4,12 @@ Simple and secure synchronisation of MISP instances | |||
| # What is MISPbump? | |||
| With MISPbump admins can easily synchronize MISP instances by exchanging relevant information via encrypted QR codes. | |||
| Note: only **use case 1** from the [documentation](https://www.circl.lu/doc/misp/sharing/) is supported. | |||
| > Note that only **use case 1** from the [documentation](https://www.circl.lu/doc/misp/sharing/) is supported. | |||
| # How does MISPbump work? | |||
| First of all: MISP admins login by providing the base URL of their instance and their authkey (automationkey). | |||
| MISP admins log in by providing the **base URL** of their instance and their **authkey**. | |||
| On a successfull login the admins profile and the linked organisation information will be downloaded automatically. | |||
| This information can be updated at any time in the profile screen. | |||
| After a successfull login the admin's profile and the linked organisation information will be downloaded. | |||
| In the main screen you can start a synchronisation process by pressing the dedicated button. | |||
| @@ -26,11 +25,11 @@ The synchronisation process consists of 3 steps: | |||
| + Own User: Email | |||
| + Own MISP instance: base URL | |||
| + Generated: sync user authkey, sync user password | |||
| (your partner will create a sync user with these credentials) | |||
| (your partner will create a sync user with these credentials for you) | |||
| The synchronisation information is encrypted with AES using the shared secret (from step 1). | |||
| The sync process information will be saved securely on the device, that means the upload can be started any time in the future. | |||
| The synchronisation process information will be saved securely on the device. | |||
| 1. **Upload information to own MISP instance** | |||
| @@ -41,7 +40,7 @@ The synchronisation process consists of 3 steps: | |||
| 1. Create sync user & add to organisation | |||
| 1. Create sync server & populate with information above | |||
| After that the two MISP instances are connected. | |||
| After that the two MISP instances are able to share Events based on their permissions. | |||
| # Dependencies | |||
| + [Retrofit](https://github.com/square/retrofit) | |||
| @@ -57,7 +57,8 @@ | |||
| android:layout_margin="16dp" | |||
| app:layout_constraintEnd_toEndOf="parent" | |||
| app:layout_constraintBottom_toBottomOf="parent" | |||
| app:layout_constraintTop_toTopOf="parent" /> | |||
| app:layout_constraintTop_toTopOf="parent" | |||
| android:contentDescription="@string/content_description_sync_status_icon" /> | |||
| <View | |||
| android:background="@color/black_10" | |||
| @@ -58,4 +58,5 @@ | |||
| <string name="upload_changes">Upload Changes</string> | |||
| <string name="download_changes">Download Changes</string> | |||
| <string name="label_delete_sync">Delete Synchronisation</string> | |||
| <string name="content_description_sync_status_icon">Shows if local changes are already uploaded to MISP instance</string> | |||
| </resources> | |||
| @@ -1 +0,0 @@ | |||
| /build | |||
| @@ -1,34 +0,0 @@ | |||
| apply plugin: 'com.android.library' | |||
| android { | |||
| compileSdkVersion 29 | |||
| buildToolsVersion "29.0.1" | |||
| defaultConfig { | |||
| minSdkVersion 21 | |||
| targetSdkVersion 29 | |||
| versionCode 1 | |||
| versionName "1.0" | |||
| testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" | |||
| } | |||
| buildTypes { | |||
| release { | |||
| minifyEnabled false | |||
| proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' | |||
| } | |||
| } | |||
| } | |||
| dependencies { | |||
| implementation fileTree(dir: 'libs', include: ['*.jar']) | |||
| implementation 'androidx.appcompat:appcompat:1.0.2' | |||
| testImplementation 'junit:junit:4.12' | |||
| androidTestImplementation 'androidx.test:runner:1.2.0' | |||
| androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' | |||
| } | |||
| @@ -1,21 +0,0 @@ | |||
| # Add project specific ProGuard rules here. | |||
| # You can control the set of applied configuration files using the | |||
| # proguardFiles setting in build.gradle. | |||
| # | |||
| # For more details, see | |||
| # http://developer.android.com/guide/developing/tools/proguard.html | |||
| # If your project uses WebView with JS, uncomment the following | |||
| # and specify the fully qualified class name to the JavaScript interface | |||
| # class: | |||
| #-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |||
| # public *; | |||
| #} | |||
| # Uncomment this to preserve the line number information for | |||
| # debugging stack traces. | |||
| #-keepattributes SourceFile,LineNumberTable | |||
| # If you keep the line number information, uncomment this to | |||
| # hide the original source file name. | |||
| #-renamesourcefileattribute SourceFile | |||
| @@ -1,29 +0,0 @@ | |||
| package lu.circl.expandablecardview; | |||
| import android.content.Context; | |||
| import androidx.test.InstrumentationRegistry; | |||
| import androidx.test.runner.AndroidJUnit4; | |||
| import org.junit.Test; | |||
| import org.junit.runner.RunWith; | |||
| import static org.junit.Assert.assertEquals; | |||
| /** | |||
| * Instrumented test, which will execute on an Android device. | |||
| * | |||
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |||
| */ | |||
| @RunWith(AndroidJUnit4.class) | |||
| public class ExampleInstrumentedTest { | |||
| @Test | |||
| public void useAppContext() { | |||
| // Context of the app under test. | |||
| Context appContext = InstrumentationRegistry.getTargetContext(); | |||
| assertEquals("lu.circl.expandablecardview.test", appContext.getPackageName()); | |||
| } | |||
| } | |||
| @@ -1 +0,0 @@ | |||
| <manifest package="lu.circl.expandablecardview" /> | |||
| @@ -1,177 +0,0 @@ | |||
| package lu.circl.expandablecardview; | |||
| import android.content.Context; | |||
| import android.content.res.TypedArray; | |||
| import android.graphics.drawable.GradientDrawable; | |||
| import android.util.AttributeSet; | |||
| import android.view.LayoutInflater; | |||
| import android.view.View; | |||
| import android.view.ViewGroup; | |||
| import android.view.animation.Animation; | |||
| import android.view.animation.Transformation; | |||
| import android.widget.FrameLayout; | |||
| import android.widget.ImageButton; | |||
| import android.widget.ImageView; | |||
| import android.widget.LinearLayout; | |||
| import android.widget.TextView; | |||
| public class ExpandableCardView extends LinearLayout { | |||
| private Context context; | |||
| private FrameLayout contentLayout; | |||
| private int cardContentPadding; | |||
| private boolean isExpanded = true; | |||
| private int animationSpeed = 200; | |||
| public ExpandableCardView(Context context) { | |||
| this(context, null); | |||
| } | |||
| public ExpandableCardView(Context context, AttributeSet attrs) { | |||
| this(context, attrs, 0); | |||
| } | |||
| public ExpandableCardView(Context context, AttributeSet attrs, int defStyleAttr) { | |||
| super(context, attrs, defStyleAttr); | |||
| this.context = context; | |||
| setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); | |||
| setOrientation(VERTICAL); | |||
| setClipToOutline(true); | |||
| TypedArray customAttributes = context.getTheme().obtainStyledAttributes(attrs, R.styleable.ExpandableCardView, defStyleAttr, 0); | |||
| // general | |||
| int cornerRadius = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_corner_radius, 12); | |||
| // header | |||
| String cardTitle = customAttributes.getString(R.styleable.ExpandableCardView_card_title); | |||
| int iconRes = customAttributes.getResourceId(R.styleable.ExpandableCardView_card_icon, 0x0); | |||
| int headerForegroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_foreground_color, 0xFF000000); | |||
| int headerBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_header_background_color, 0xFFFFFFFF); | |||
| // content | |||
| cardContentPadding = customAttributes.getDimensionPixelSize(R.styleable.ExpandableCardView_card_content_padding, 0); | |||
| int cardContentBackgroundColor = customAttributes.getColor(R.styleable.ExpandableCardView_card_content_background_color, 0xFFFFFFFF); | |||
| customAttributes.recycle(); | |||
| GradientDrawable cardBackground = new GradientDrawable(); | |||
| cardBackground.setCornerRadius(cornerRadius); | |||
| cardBackground.setColor(cardContentBackgroundColor); | |||
| setBackground(cardBackground); | |||
| setElevation(10); | |||
| initHeader(cardTitle, iconRes, headerBackgroundColor, headerForegroundColor); | |||
| } | |||
| @Override | |||
| public void addView(View child, int index, ViewGroup.LayoutParams params) { | |||
| if (getChildCount() == 0) { | |||
| super.addView(child, index, params); // add header | |||
| } else { | |||
| if (contentLayout == null) { | |||
| contentLayout = new FrameLayout(context); | |||
| contentLayout.setLayoutParams(new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); | |||
| contentLayout.setPadding(cardContentPadding, cardContentPadding, cardContentPadding, cardContentPadding); | |||
| super.addView(contentLayout, index, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); | |||
| } | |||
| contentLayout.addView(child); | |||
| } | |||
| } | |||
| private void initHeader(String title, int iconRes, int backgroundColor, int foregroundColor) { | |||
| View header = LayoutInflater.from(context).inflate(R.layout.expandable_card_view_header, this, true); | |||
| LinearLayout ll = header.findViewById(R.id.llRoot); | |||
| ll.setBackgroundColor(backgroundColor); | |||
| TextView titleTextView = header.findViewById(R.id.expandable_card_view_header_title); | |||
| titleTextView.setText(title); | |||
| titleTextView.setTextColor(foregroundColor); | |||
| ImageView iconView = header.findViewById(R.id.expandable_card_view_header_icon); | |||
| if (iconRes == 0x0) { | |||
| iconView.setVisibility(GONE); | |||
| } else { | |||
| iconView.setImageResource(iconRes); | |||
| iconView.setColorFilter(foregroundColor); | |||
| } | |||
| final ImageButton expandToggle = header.findViewById(R.id.expandable_card_view_header_toggle); | |||
| expandToggle.setColorFilter(foregroundColor); | |||
| expandToggle.setOnClickListener(new OnClickListener() { | |||
| @Override | |||
| public void onClick(View view) { | |||
| if (isExpanded) { | |||
| collapse(contentLayout); | |||
| expandToggle.animate().rotation(0).setDuration(animationSpeed); | |||
| } else { | |||
| expand(contentLayout); | |||
| expandToggle.animate().rotation(180).setDuration(animationSpeed); | |||
| } | |||
| isExpanded = !isExpanded; | |||
| } | |||
| }); | |||
| } | |||
| private void expand(final View v) { | |||
| int matchParentMeasureSpec = View.MeasureSpec.makeMeasureSpec(((View) v.getParent()).getWidth(), View.MeasureSpec.EXACTLY); | |||
| int wrapContentMeasureSpec = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED); | |||
| v.measure(matchParentMeasureSpec, wrapContentMeasureSpec); | |||
| final int targetHeight = v.getMeasuredHeight(); | |||
| v.getLayoutParams().height = 1; | |||
| v.setVisibility(View.VISIBLE); | |||
| Animation a = new Animation() { | |||
| @Override | |||
| protected void applyTransformation(float interpolatedTime, Transformation t) { | |||
| v.getLayoutParams().height = interpolatedTime == 1 | |||
| ? LayoutParams.WRAP_CONTENT | |||
| : (int) (targetHeight * interpolatedTime); | |||
| v.requestLayout(); | |||
| } | |||
| @Override | |||
| public boolean willChangeBounds() { | |||
| return true; | |||
| } | |||
| }; | |||
| a.setDuration(animationSpeed); | |||
| v.startAnimation(a); | |||
| } | |||
| private void collapse(final View v) { | |||
| final int initialHeight = v.getMeasuredHeight(); | |||
| Animation a = new Animation() { | |||
| @Override | |||
| protected void applyTransformation(float interpolatedTime, Transformation t) { | |||
| if (interpolatedTime == 1) { | |||
| v.setVisibility(View.GONE); | |||
| } else { | |||
| v.getLayoutParams().height = initialHeight - (int) (initialHeight * interpolatedTime); | |||
| v.requestLayout(); | |||
| } | |||
| } | |||
| @Override | |||
| public boolean willChangeBounds() { | |||
| return true; | |||
| } | |||
| }; | |||
| a.setDuration(animationSpeed); | |||
| v.startAnimation(a); | |||
| } | |||
| } | |||
| @@ -1,9 +0,0 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||
| android:width="24dp" | |||
| android:height="24dp" | |||
| android:viewportWidth="24.0" | |||
| android:viewportHeight="24.0"> | |||
| <path | |||
| android:fillColor="#FF000000" | |||
| android:pathData="M11,17h2v-6h-2v6zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM11,9h2L13,7h-2v2z"/> | |||
| </vector> | |||
| @@ -1,9 +0,0 @@ | |||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | |||
| android:width="24dp" | |||
| android:height="24dp" | |||
| android:viewportWidth="24.0" | |||
| android:viewportHeight="24.0"> | |||
| <path | |||
| android:fillColor="#FF000000" | |||
| android:pathData="M7.41,7.84L12,12.42l4.59,-4.58L18,9.25l-6,6 -6,-6z"/> | |||
| </vector> | |||
| @@ -1,37 +0,0 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <LinearLayout | |||
| xmlns:android="http://schemas.android.com/apk/res/android" | |||
| xmlns:tools="http://schemas.android.com/tools" | |||
| android:id="@+id/llRoot" | |||
| android:orientation="horizontal" | |||
| android:layout_width="match_parent" | |||
| android:layout_height="wrap_content"> | |||
| <ImageView | |||
| android:id="@+id/expandable_card_view_header_icon" | |||
| android:layout_width="wrap_content" | |||
| android:layout_height="wrap_content" | |||
| android:layout_marginStart="16dp" | |||
| android:layout_marginTop="16dp" | |||
| android:layout_marginBottom="16dp" | |||
| tools:src="@drawable/ic_info_outline"/> | |||
| <TextView | |||
| android:id="@+id/expandable_card_view_header_title" | |||
| android:layout_width="0dp" | |||
| android:layout_height="wrap_content" | |||
| android:layout_weight="1" | |||
| android:layout_marginStart="16dp" | |||
| android:layout_gravity="center_vertical" | |||
| tools:text="Card Title"/> | |||
| <ImageButton | |||
| android:id="@+id/expandable_card_view_header_toggle" | |||
| android:layout_width="wrap_content" | |||
| android:layout_height="wrap_content" | |||
| android:layout_margin="8dp" | |||
| android:padding="8dp" | |||
| android:src="@drawable/ic_keyboard_arrow_down" | |||
| android:background="?attr/selectableItemBackgroundBorderless"/> | |||
| </LinearLayout> | |||
| @@ -1,17 +0,0 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | |||
| <resources> | |||
| <declare-styleable name="ExpandableCardView"> | |||
| // general | |||
| <attr name="card_corner_radius" format="dimension"/> | |||
| // header | |||
| <attr name="card_title" format="string"/> | |||
| <attr name="card_icon" format="reference"/> | |||
| <attr name="card_header_background_color" format="color"/> | |||
| <attr name="card_header_foreground_color" format="color"/> | |||
| // content | |||
| <attr name="card_content_padding" format="dimension"/> | |||
| <attr name="card_content_background_color" format="color"/> | |||
| </declare-styleable> | |||
| </resources> | |||
| @@ -1,3 +0,0 @@ | |||
| <resources> | |||
| <string name="app_name">ExpandableCardView</string> | |||
| </resources> | |||
| @@ -1,19 +0,0 @@ | |||
| package lu.circl.expandablecardview; | |||
| import org.junit.Test; | |||
| import static org.junit.Assert.assertEquals; | |||
| /** | |||
| * Example local unit test, which will execute on the development machine (host). | |||
| * | |||
| * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |||
| */ | |||
| public class ExampleUnitTest { | |||
| @Test | |||
| public void addition_isCorrect() { | |||
| assertEquals(4, 2 + 2); | |||
| } | |||
| } | |||