Skip to content

Commit

Permalink
Merge branch 'security_audit' into import_mnemonic_ui
Browse files Browse the repository at this point in the history
  • Loading branch information
phuocbitmark committed Apr 24, 2024
2 parents b7cc74c + 83931f6 commit 69010d6
Show file tree
Hide file tree
Showing 42 changed files with 1,049 additions and 499 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/android-release-appcenter.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ jobs:
echo "FLUTTER_VERSION_CODE=${{ github.event.inputs.build-number }}" >> $GITHUB_ENV
echo "BRANCH_KEY=${{ secrets.BRANCH_KEY }}" >> $GITHUB_ENV
echo "BRANCH_KEY_TEST=${{ secrets.BRANCH_KEY_TEST }}" >> $GITHUB_ENV
echo "SIGNATURE_HASH=${{ secrets.SIGNATURE_HASH }}" >> $GITHUB_ENV
echo "SIGNATURE_HASH_INHOUSE=${{ secrets.SIGNATURE_HASH_INHOUSE }}" >> $GITHUB_ENV
${{ github.event.inputs.testnet == 'true' }} && echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-Test >> $GITHUB_ENV || echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-1 >> $GITHUB_ENV
${{ github.event.inputs.testnet == 'true' }} && echo NAME_SUFFIX=test-${{ github.event.inputs.build-number }} >> $GITHUB_ENV || echo NAME_SUFFIX=main-${{ github.event.inputs.build-number }} >> $GITHUB_ENV
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/bmvn_build_appcenter_android.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ jobs:
# echo "FLUTTER_VERSION_CODE=${{ inputs.build-number }}" >> $GITHUB_ENV
echo "BRANCH_KEY=${{ secrets.BRANCH_KEY }}" >> $GITHUB_ENV
echo "BRANCH_KEY_TEST=${{ secrets.BRANCH_KEY_TEST }}" >> $GITHUB_ENV
echo "SIGNATURE_HASH=${{ secrets.SIGNATURE_HASH }}" >> $GITHUB_ENV
echo "SIGNATURE_HASH_INHOUSE=${{ secrets.SIGNATURE_HASH_INHOUSE }}" >> $GITHUB_ENV
${{ inputs.testnet == true }} && echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-Test >> $GITHUB_ENV || echo APPCENTER_APP_ID=support-zzd0-28/Autonomy-Android-1 >> $GITHUB_ENV
${{ inputs.testnet == true }} && echo NAME_SUFFIX=test-${{env.FLUTTER_VERSION_CODE}} >> $GITHUB_ENV || echo NAME_SUFFIX=main-${{env.FLUTTER_VERSION_CODE}} >> $GITHUB_ENV
Expand Down
70 changes: 57 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,18 +1,62 @@
# Autonomy: Digital Art Wallet
_Collect, View & Discovery_
# Feral File: the way to collect art


## About

Autonomy is the world’s first and only digital art wallet. It gives you one easy-to-use app to securely collect, view and discover digital art you love. Autonomy works with Ethereum and Tezos and is built to support all new chains as they emerge.

- _Collect_: Buy digital art on Tezos or Ethereum and let Autonomy secure, organize and showcase your collection—all in one beautiful, simple experience. Autonomy takes care of the hard stuff so you can focus on growing the good stuff.

- _View_: Enjoy your digital art anywhere—on any screen, TV or projector. Autonomy is the only app that does this. It’s like having an infinite personal gallery you can share and experience anywhere you go.

- _Discover_: Autonomy automatically helps you discover new art by knowing the artists you collect, what they’ve minted and what they’ve bought for themselves. We don’t use likes, trends or algorithms. We go straight to the source to give you the stuff we know you’ll love.
### [Feral File](https://feralfile.com/) is the place to experience digital art today.

Visit curated exhibitions of world-class, software-based art, interact with dynamic digital works, and organize your personal digital art collection directly in the app. You can share and enjoy all artwork found in the app with friends and family by Streaming to any compatible screen.

Co-create a [MoMA Postcard](https://www.moma.org/calendar/exhibitions/5618) and experiment with borderless collaboration and creativity.


</br>
</br>


The **Feral File** app enhances the digital experience, increasing the ways people can share, organize, explore, and live with software-based artwork.


#### Explore Feral File Exhibitions

- Each exhibition on **Feral File** begins with the curator. World-class artists collaborate with visionary curators to create and exhibit artworks around a single, ambitious theme.

- Exhibitions never close on **[feralfile.com](https://feralfile.com/)**. Soon, all exhibitions will be viewable and streamable on the **Feral File** app. For now, the current exhibition is on view.


#### Live with digital art

- Stream digital artwork to any compatible screen. Share and enjoy your favorite pieces with family, friends, and colleagues at home and in the office.

- For interactive works, your mobile device becomes the remote control. Use the keyboard, experiment with the artist’s commands, and dive into the immersive world of software-based art.


#### Organize

- Consolidate collected digital art across blockchains (Ethereum and Tezos)

- Create collections within your collection.

- The app classifies artwork into 3 categories: Still, Video, Interactive.


#### Share

- Co-create a digital chain letter with [MoMA Postcard](https://www.moma.org/calendar/exhibitions/5618). This experiment in borderless collaboration and creativity explores ways individuals, groups, and institutions can make and own digital goods.

- The “View existing address” feature allows you to see other collections and share yours with friends.


</br>
</br>


Bitmark started with the idea of building tools to help individuals and institutions secure digital property rights. Feral File, an online gallery co-founded by Casey Reas, applies this vision to art made with software, helping artists and collectors secure the property rights to their artwork. Visit feralfile.com and experience world-class digital art in-situ. The **Feral File** app goes beyond ownership and provides dynamic ways to engage with digital art on your personal devices, in your home, and across the world.

</br>

![all in one](https://github.com/bitmark-inc/feralfile-app/assets/61187455/a63402ea-3949-4188-b9dd-c26c7457952b)

<img src="https://user-images.githubusercontent.com/422993/177656126-c3e02532-8ee6-4772-b495-84565231371b.jpg" width=220/> <img src="https://user-images.githubusercontent.com/422993/177656144-c3ccf692-5882-4bd2-8920-daaef399b055.jpg" width=220/> <img src="https://user-images.githubusercontent.com/422993/177656150-bce1a823-3944-4649-a502-049be2a57017.jpg" width=220/>


## Getting Started
Expand All @@ -29,7 +73,7 @@ Autonomy is the world’s first and only digital art wallet. It gives you one ea
6. Run ./script/encrypt_secrets.sh <-entropy-> to generate the encrypted secrets file.
- <-entropy-> is a random string. You can type a random string like akhrdsgl4893tynk3iu4y8hf
- You only need to run this script again when you want to update .env.secret.
7. Run `flutter run --flavor inhouse` to run Feral File app development on the connected device.
7. Run `flutter run --flavor inhouse` to run **Feral File** app development on the connected device.

A few resources to get you started if this is your first Flutter project:

Expand All @@ -41,8 +85,8 @@ For help getting started with Flutter, view our
samples, guidance on mobile development, and a full API reference.

## Status - Released
- [App Store](https://apps.apple.com/us/app/autonomy-app/id1544022728)
- [Google Play](https://play.google.com/store/apps/details?id=com.bitmark.autonomy_client)
- [App Store](https://apps.apple.com/us/app/feral-file/id1544022728)
- [Google Play](https://play.google.com/store/apps/details?id=com.bitmark.autonomy_client&pli=)

[Release Notes](https://github.com/bitmark-inc/autonomy-apps/tree/main/release_notes/production)

Expand Down
2 changes: 1 addition & 1 deletion android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ dependencies {
implementation 'com.google.android.gms:play-services-auth-blockstore:16.1.0'
implementation 'io.reactivex.rxjava2:rxjava:2.2.10'
implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
implementation('com.github.bitmark-inc:libauk-kotlin:aaf6d60725') {
implementation('com.github.bitmark-inc:libauk-kotlin:0.6.3') {
exclude group: 'com.google.protobuf'
exclude module: 'jetified-protobuf-java'
}
Expand Down
20 changes: 15 additions & 5 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,8 @@
android:icon="${appIcon}"
android:label="@string/app_name"
android:roundIcon="${appIconRound}"
android:usesCleartextTraffic="true"
android:networkSecurityConfig="@xml/network_security_config"
tools:replace="android:label">
<!--
- Enable usesCleartextTraffic only to allow make connection to localhost
- It will be used to rendering model viewer for 3d artworks.
-->

<meta-data
android:name="com.onesignal.NotificationServiceExtension"
Expand Down Expand Up @@ -199,6 +195,20 @@
android:scheme="https" />
</intent-filter>
</activity>
<activity
android:name=".EmergencyLog"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data
android:host="emergency-logs"
android:pathPattern="/.*"
android:scheme="feralfile" />
</intent-filter>
</activity>
<!--
Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package com.bitmark.autonomy_flutter

import android.app.Activity
import android.net.Uri
import android.os.Bundle
import com.google.gson.Gson
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.*
import okhttp3.OkHttpClient
import okhttp3.RequestBody.Companion.toRequestBody
import java.io.File
import java.io.IOException
import java.util.Base64

class EmergencyLog : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

val logger = FileLogger.init(applicationContext)
val data: Uri? = intent.data
val token: String? = data?.lastPathSegment

if (token != null) {
uploadLogFile(logger.getFile(), token)
}
}

private fun uploadLogFile(file: File, token: String) {
val client = OkHttpClient()

val requestBody = buildRequestBody(file)

// Build the request
val url = if (BuildConfig.FLAVOR.contains("inhouse")) {
"https://support.test.autonomy.io/v1/issues/"
} else {
"https://support.autonomy.io/v1/issues/"
}

val request = Request.Builder()
.url(url)
.post(requestBody)
.header("Authorization", "Emergency $token")
.build()

client.newCall(request).enqueue(object : Callback {
override fun onFailure(call: Call, e: IOException) {
e.printStackTrace()
// Handle failure
}

override fun onResponse(call: Call, response: Response) {
if (response.isSuccessful) {
// Handle successful upload
println("Log file uploaded successfully")
} else {
// Handle unsuccessful upload
println("Failed to upload log file")
}
}
})
}

private fun buildRequestBody(file: File): RequestBody {
// Read the log file content as base64
val base64Content = Base64.getEncoder().encodeToString(file.readBytes())

// Construct the attachments array with base64 data and file name
val attachments = listOf(
mapOf("data" to base64Content, "title" to file.name, "path" to "", "contentType" to "")
)

// Construct the request body as JSON
val requestBodyMap = mapOf(
"attachments" to attachments,
"title" to "Emergency log",
"message" to "message",
"tags" to listOf("emergency", "android"),
"announcement_context_id" to ""
)

val gson = Gson()
val json = gson.toJson(requestBodyMap)

return json.toRequestBody("application/json".toMediaTypeOrNull())
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,25 @@ class FileLogger(context: Context) {

fun init(context: Context) = INSTANCE ?: FileLogger(context).also { INSTANCE = it }

fun log(tag: String , message: String) {
fun log(tag: String, message: String) {
INSTANCE?.log(tag, message)
}
}

private val _fileLogger: File

fun getFile(): File {
return _fileLogger
}

init {
_fileLogger = File(context.cacheDir, "app.log")
if (!_fileLogger.exists()) {
_fileLogger.createNewFile()
}
}

private fun log(tag: String , message: String) {
private fun log(tag: String, message: String) {
if (_fileLogger.canWrite()) {
Log.d(tag, message)
FileOutputStream(_fileLogger, true).apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ import android.content.SharedPreferences
import android.content.pm.PackageManager
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import io.sentry.Sentry
import android.util.Base64
import android.util.Log
import android.view.View.ACCESSIBILITY_DATA_SENSITIVE_YES
Expand Down Expand Up @@ -82,37 +85,7 @@ class MainActivity : FlutterFragmentActivity() {
FileLogger.init(applicationContext)
// verity signing certificate

if (detectFrida()) {
finish()
}
val isSignatureValid = isSignatureValid(this, BuildConfig.SIGNATURE_HASH)
if (!isSignatureValid) {
Toast.makeText(this, "Invalid signature", Toast.LENGTH_SHORT).show()
finish()
return
}

// Detect rooted devices
// Create a RootBeer instance
val rootBeer = RootBeer(this)
if (rootBeer.isRooted) {
Toast.makeText(this, "This app cannot be used on rooted devices.", Toast.LENGTH_SHORT)
.show()
finish() // Close the app
}

// debugger detection
val hasTracerPid = hasTracerPid()
if (BuildConfig.ENABLE_DEBUGGER_DETECTION && hasTracerPid) {
Toast.makeText(
this,
"Debugging detected. Please try again without any debugging tools.",
Toast.LENGTH_SHORT
)
.show()
finish()
return
}
checkSecurity()
MethodChannel(
flutterEngine.dartExecutor.binaryMessenger,
CHANNEL
Expand Down Expand Up @@ -149,6 +122,54 @@ class MainActivity : FlutterFragmentActivity() {
private fun detectFrida(): Boolean {
return detectFridaPort() || detectFridaMem()
}
private fun checkSecurity() {
val handler = Handler(Looper.getMainLooper())

handler.postDelayed({
if (detectFrida()) {
captureMessage("[Security check] Reverse engineering tool detected")
finish()
}
val isSignatureValid = isSignatureValid(this, BuildConfig.SIGNATURE_HASH)
if (!isSignatureValid) {
captureMessage("[Security check] Invalid signature detected")
Toast.makeText(this, "Invalid signature", Toast.LENGTH_SHORT).show()
finish()
}

// Detect rooted devices
// Create a RootBeer instance
val rootBeer = RootBeer(this)
if (rootBeer.isRooted) {
captureMessage("[Security check] Rooted device detected")
Toast.makeText(this, "This app cannot be used on rooted devices.", Toast.LENGTH_SHORT)
.show()
finish() // Close the app
}

// debugger detection
val hasTracerPid = hasTracerPid()
if (BuildConfig.ENABLE_DEBUGGER_DETECTION && hasTracerPid) {
captureMessage("[Security check] Debugger detected")
Toast.makeText(
this,
"Debugging detected. Please try again without any debugging tools.",
Toast.LENGTH_SHORT
)
.show()
finish()
}
}, 5000L)
}

private fun captureMessage(message: String) {
try {
Sentry.captureMessage(message)
} catch (e: Exception) {
e.printStackTrace()
}
}


private fun detectFridaPort(): Boolean {
return try {
Expand Down
12 changes: 12 additions & 0 deletions android/app/src/main/res/xml/network_security_config.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<base-config cleartextTrafficPermitted="false" />
<domain-config cleartextTrafficPermitted="true">
<domain includeSubdomains="true">localhost</domain>
<domain includeSubdomains="true">127.0.0.1</domain>
<!--
- Enable usesCleartextTraffic for localhost only
- It will be used to rendering model viewer for 3d artworks.
-->
</domain-config>
</network-security-config>
2 changes: 1 addition & 1 deletion assets
Loading

0 comments on commit 69010d6

Please sign in to comment.