SatoshiPortal / bullbitcoin-mobile

The Bull Bitcoin Mobile Wallet and Exchange App
MIT License
62 stars 24 forks source link

[Feature] Reproducible builds #326

Open xrviv opened 1 month ago

xrviv commented 1 month ago

Hello team bullbitcoin! 😃

I'm Danny, and I work with WalletScrutiny.com. We have reviewed over 6500+ Bitcoin Android apps and firmware. You can read about our methodology here.


We'd love to work with your team on verifying the reproducibility of your app, with appID com.bullbitcoin.mobile To get there, may we suggest the following:

Hoping to hear from you again soon!

Kind Regards,

Danny

i5hi commented 1 month ago

Hey @xrviv,

Thanks for reviewing our project!

We will create a BUILD.md files with build instructions and keep you posted.

BullishNode commented 1 month ago

Thanks for your interest. This is an important issue for us. We will make sure to prioritize it before we move out of Beta.

xrviv commented 1 month ago

I was able to build 0.3.2, with this Dockerfile:

Proof of Build https://asciinema.org/a/677360

# Use a base Ubuntu image
FROM ubuntu:20.04

# Avoid prompts from apt
ENV DEBIAN_FRONTEND=noninteractive

# Install necessary dependencies
RUN apt-get update && apt-get install -y \
    curl \
    git \
    unzip \
    xz-utils \
    zip \
    libglu1-mesa \
    wget \
    clang \
    cmake \
    ninja-build \
    pkg-config \
    libgtk-3-dev \
    software-properties-common \
    && rm -rf /var/lib/apt/lists/*

# Add the repository for OpenJDK 17
RUN add-apt-repository ppa:openjdk-r/ppa

# Install OpenJDK 17
RUN apt-get update && apt-get install -y openjdk-17-jdk && rm -rf /var/lib/apt/lists/*

# Set up Java environment
ENV JAVA_HOME /usr/lib/jvm/java-17-openjdk-amd64
ENV PATH $JAVA_HOME/bin:$PATH

# Install bundletool
RUN wget https://github.com/google/bundletool/releases/download/1.15.5/bundletool-all-1.15.5.jar -O /usr/local/bin/bundletool.jar
RUN echo '#!/bin/sh\njava -jar /usr/local/bin/bundletool.jar "$@"' > /usr/local/bin/bundletool && chmod +x /usr/local/bin/bundletool

# Install Rust
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
ENV PATH="/root/.cargo/bin:${PATH}"

# Verify Rust installation
RUN rustc --version && cargo --version

# Install Flutter
ENV FLUTTER_HOME /opt/flutter
ENV PATH $FLUTTER_HOME/bin:$PATH
RUN git clone https://github.com/flutter/flutter.git $FLUTTER_HOME
RUN cd $FLUTTER_HOME && git checkout stable && ./bin/flutter --version

# Set up Android SDK
ENV ANDROID_SDK_ROOT /opt/android-sdk
ENV PATH $PATH:$ANDROID_SDK_ROOT/cmdline-tools/latest/bin:$ANDROID_SDK_ROOT/platform-tools
RUN mkdir -p ${ANDROID_SDK_ROOT}/cmdline-tools && \
    wget -q https://dl.google.com/android/repository/commandlinetools-linux-8092744_latest.zip -O android-cmdline-tools.zip && \
    unzip -q android-cmdline-tools.zip -d ${ANDROID_SDK_ROOT}/cmdline-tools && \
    mv ${ANDROID_SDK_ROOT}/cmdline-tools/cmdline-tools ${ANDROID_SDK_ROOT}/cmdline-tools/latest && \
    rm android-cmdline-tools.zip

# Accept licenses and install necessary Android SDK components
RUN yes | sdkmanager --licenses
RUN sdkmanager "platform-tools" "platforms;android-34" "build-tools;34.0.0"

# Clean up existing app directory
RUN rm -rf /app

# Clone the Bull Bitcoin mobile repository
RUN git clone https://github.com/SatoshiPortal/bullbitcoin-mobile /app

# Copy device-spec.json into the container
COPY device-spec.json /app/device-spec.json

# Set up the Flutter project
WORKDIR /app
RUN flutter pub get

# Generate a fake keystore
RUN keytool -genkey -v -keystore /app/android/app/upload-keystore.jks -keyalg RSA -keysize 2048 -validity 10000 -alias upload -storepass android -keypass android -dname "CN=Android Debug,O=Android,C=US"

# Set up key.properties
RUN echo "storePassword=android" > /app/android/key.properties && \
    echo "keyPassword=android" >> /app/android/key.properties && \
    echo "keyAlias=upload" >> /app/android/key.properties && \
    echo "storeFile=../app/upload-keystore.jks" >> /app/android/key.properties

# Pre-build the project to download all necessary dependencies
RUN flutter precache

# Build the AAB (Android App Bundle)
RUN flutter build appbundle --release

# Generate split APKs
RUN bundletool build-apks --bundle=/app/build/app/outputs/bundle/release/app-release.aab --output=/app/app.apks --device-spec=/app/device-spec.json

# List apks
# RUN unzip -l /app/app.apks

# Extract specific APKs
RUN unzip -p /app/app.apks splits/base-master.apk > /app/base.apk && \
    unzip -p /app/app.apks splits/base-armeabi_v7a.apk > /app/armeabi_v7a.apk && \
    unzip -p /app/app.apks splits/base-en.apk > /app/en.apk && \
    unzip -p /app/app.apks splits/base-xhdpi.apk > /app/xhdpi.apk

# Clean up
RUN rm /app/app.apks

# Create the output directory
RUN mkdir -p /app/build-output/

# Output the build artifacts
CMD ["sh", "-c", "cp /app/base.apk /app/armeabi_v7a.apk /app/en.apk /app/xhdpi.apk /app/build/app/outputs/bundle/release/app-release.aab /app/build-output/"]

The build had the following diffs:

danny@lw10:~/work/compare/com.bullbitcoin.mobile/0.3.2$ diff -r -q fromOfficial/ fromBuild/
Files fromOfficial/armeabi_v7a/AndroidManifest.xml and fromBuild/armeabi_v7a/AndroidManifest.xml differ
Files fromOfficial/armeabi_v7a/lib/armeabi-v7a/libapp.so and fromBuild/armeabi_v7a/lib/armeabi-v7a/libapp.so differ
Files fromOfficial/armeabi_v7a/lib/armeabi-v7a/libboltz_dart.so and fromBuild/armeabi_v7a/lib/armeabi-v7a/libboltz_dart.so differ
Files fromOfficial/armeabi_v7a/lib/armeabi-v7a/libflutter.so and fromBuild/armeabi_v7a/lib/armeabi-v7a/libflutter.so differ
Files fromOfficial/armeabi_v7a/lib/armeabi-v7a/liblwk_dart.so and fromBuild/armeabi_v7a/lib/armeabi-v7a/liblwk_dart.so differ
Only in fromOfficial/armeabi_v7a: META-INF
Only in fromOfficial/armeabi_v7a: stamp-cert-sha256
Files fromOfficial/armeabi_v7a.apk and fromBuild/armeabi_v7a.apk differ
Files fromOfficial/base/AndroidManifest.xml and fromBuild/base/AndroidManifest.xml differ
Files fromOfficial/base/assets/flutter_assets/NOTICES.Z and fromBuild/base/assets/flutter_assets/NOTICES.Z differ
Only in fromOfficial/base/META-INF: BNDLTOOL.RSA
Only in fromOfficial/base/META-INF: BNDLTOOL.SF
Only in fromOfficial/base/META-INF: MANIFEST.MF
Files fromOfficial/base/res/xml/splits0.xml and fromBuild/base/res/xml/splits0.xml differ
Files fromOfficial/base/resources.arsc and fromBuild/base/resources.arsc differ
Only in fromOfficial/base: stamp-cert-sha256
Files fromOfficial/base.apk and fromBuild/base.apk differ
Files fromOfficial/en/AndroidManifest.xml and fromBuild/en/AndroidManifest.xml differ
Only in fromOfficial/en: META-INF
Files fromOfficial/en/resources.arsc and fromBuild/en/resources.arsc differ
Only in fromOfficial/en: stamp-cert-sha256
Files fromOfficial/en.apk and fromBuild/en.apk differ
Files fromOfficial/xhdpi/AndroidManifest.xml and fromBuild/xhdpi/AndroidManifest.xml differ
Only in fromOfficial/xhdpi: META-INF
Files fromOfficial/xhdpi/resources.arsc and fromBuild/xhdpi/resources.arsc differ
Only in fromOfficial/xhdpi: stamp-cert-sha256
Files fromOfficial/xhdpi.apk and fromBuild/xhdpi.apk differ
i5hi commented 1 month ago

Thank you for creating that Dockerfile. I will add it to the repo and as we make progress I will update it.

So AndroidManifest.xml is the first differing file; which I am not sure why. I took a look at the existing AndroidManifest.xml file and there doesnt seem to be anything specific to the system building the project that is being added. Any ideas on what this could be about?

Regarding the libraries we are using; we had a bounty which a dev is working on and he found that if you use a different version of cargo as what we have used, the resulting binary differ.

I am building our android apks on a system running cargo 1.74.0 (ecb9851af 2023-10-18)

I assume we would also need a way of stripping the signature data from the binary.

I unfortunately am swamped with work at the moment to dig into the details but you've given me a great starting point.

Thanks again!

xrviv commented 1 month ago

Hello @i5hi, thank you for the attentive and quick reply!

I apologize for the late reply, as we've been handling several issues at the moment.

I actually would not know how this came to differ unless we ran a diffoscope on it. We can derive clues from various providers though,

For Bitkey's AndroidManifest.xml:

Our review for Bitkey:

image

They also mentioned something about the resources.arsc mismatch here:

https://github.com/proto-at-block/bitkey/blob/main/app/verifiable-build/android/README.md#verification-notes

resources.arsc mismatch
Until recently, once we normalized the APK names and contents, we could just run diff -r to check for identity. Unfortunately Google Play has changed how they build resources.arsc. From our testing, it seems like they are using a [previously reserved byte](https://android.googlesource.com/platform/frameworks/base/+/master/libs/androidfw/include/androidfw/ResourceTypes.h#1405). When built using bundletool, that byte is always 0, thus making direct comparison using diff impossible.

Since resources are important part of the application, we're using aapt2 diff to check for differences between APKs from device and from bundletool.

As for the reasoning for the other files, they're WiP