Skip to content

Development

Bofu Chen edited this page Sep 12, 2022 · 21 revisions

Product Flavors

Master (Main) Flavor

  • This is the public flavor.
  • It should be always buildable without manual configurations.
  • This flavor only contains a sample publisher.

Numbers Flavor

  • This is an internal product flavor, which cannot be build directly.
  • Crashlytics is enabled.

Build Requirements

Place the information required by the numbers backend in ./app/src/main/.../publisher/numbers_storage/Token.kt. For example:

package io.numbersprotocol.starlingcapture.publisher.numbers_storage

const val baseUrl = "https://sample.com"
const val token = "token 0123456789abcdef"

Build Types

  1. Debug
    • LeakCanary is enabled.
  2. QA
    • The quality of this build type should be product-ready. Thus, it should not contain any visible debugging artifacts (e.g. LeakCanary) except error messages.

Tech Stack

  1. Kotlin
  2. AndroidX
  3. MVVM Architecture
  4. Android Architecture Component
    • Paging Library
    • Work Manager
    • Preference Library
    • Navigation Component
    • Room Database
  5. Material Component
  6. Koin - dependecy injection
  7. Retrofit - networking
  8. Moshi - proof serialization
  9. Coil - image loading
  10. Timber - logging
  11. LeakCanary - memory leak detection

Contribution

  1. The committed codes should pass all GitHub workflows.
  2. The committed codes should not have warnings from Android Studio linter. You can use ./gradlew lint to verify.
  3. The committed codes should not have memory leak reports by LeakCanary, which is enabled in the debug variant.

Convention

The name in string.xml should match the English content in snake case. If the content of the string is a long message, the name should start with message_. For example:

<string name="public_key_signature">Public Key Signature</string>
<string name="message_are_you_sure">The action cannot be undone.</string>

Architecture

architecture

Source Providers

Currently, three types of media source are implemented:

  1. Internal camera (image)
  2. Internal camera (video)
  3. Canon Camera with CCAPI (image and video)

The components regarding media source should be placed in ./app/src/main/.../source/.

Information Providers

Currently, we only use android-info-snapshot as information provider. The components regarding information collection should be placed in ./app/src/main/.../collector/information/.

To add new information provider,

  1. Extends the InformationProvider.
  2. Override the provideInformation() method.
  3. Store the information to the DB with InformationRepository class.

Signature Providers

Currently, two types of signature provider are implemented:

  1. AndroidOpenSSL (default signature)
  2. Zion signature (opt-in)

The components regarding information collection should be placed in ./app/src/main/.../collector/signature/.

To add new signature provider,

  1. Extends the SignatureProvider.
  2. Override the provideSignature() method.
  3. Sign the SortedProofInformation from the given proof hash.
  4. Store the signature to the DB with SignatureRepository class.

Publishers

Currently, we only provide a sample publisher which does nothing.

The components regarding information collection should be placed in ./app/src/main/.../publisher/.

To add new signature provider, see the SampleProofPublisher class for details.

Data Flow

dataflow

Steps in ProofCollector

  1. Store the proof raw file into the internal directory.
  2. Store the hash of proof into proof repository.
  3. Collect information.
  4. Sign the proof and its collected information even if some information providers failed.

Serialization Schema

SortedProofInformation (Metadata)

The SortedProofInformation class provides the message of signature provider.

{
    proof: {
        hash: String,
        mimeType: String,
        timestamp: Long
    },
    information: [
        {
            provider: String,
            name: String,
            value: String
        },
        ...
    ]
}
Example (beautified), Sign with Zion is disabled:
$ jq . information.json
{
  "proof": {
    "hash": "3eb44256eb98c9d43c48ed0dcbc660e8dafa9bdf54abf4da406846cea8311014",
    "mimeType": "image/jpeg",
    "timestamp": 1652606172402
  },
  "information": [
    {
      "provider": "InfoSnapshot",
      "name": "Accelerometer",
      "value": "[0.4421997, 6.9092345, 6.9160113]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Board",
      "value": "QC_Reference_Phone"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Brand",
      "value": "Htc"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Country",
      "value": "United States"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Accuracy",
      "value": "17.307"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Address",
      "value": "No. 62, Anping Rd, Zhonghe District, New Taipei City, Taiwan 235"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Altitude",
      "value": "27.399999618530273"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Bearing",
      "value": "0.0"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Latitude",
      "value": "24.9960048"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Longitude",
      "value": "121.5104486"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Speed",
      "value": "0.0"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Current GPS Timestamp",
      "value": "2022-05-15T09:16:13.438Z"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Build Fingerprint",
      "value": "Htc/bre2exdugl_00400/htc_bre2exdugl:8.1.0/OPM1.171019.011/200630:user/release-keys"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Build ID",
      "value": "1.15.709.1"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Build Tags",
      "value": "release-keys"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Build Time",
      "value": "6/30/20 8:16 PM"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Build Type",
      "value": "user"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Device Name",
      "value": "htc_bre2exdugl"
    },
    {
      "provider": "InfoSnapshot",
      "name": "End Product Name",
      "value": "EXODUS 1s"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Game Rotation Vector",
      "value": "UNSUPPORTED"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Geomagnetic Rotation Vector",
      "value": "[0.4146733, -0.044002537, 0.09306122, 0.9041181, 0.0]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Gravity",
      "value": "[1.7164232, 7.280239, 6.3422546]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Gyroscope",
      "value": "UNSUPPORTED"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Hardware",
      "value": "qcom"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Hash of Android ID",
      "value": "0fa0b3f57c76d453433151b46ed2f6562bd31183f1e21d0c092318e519a9aed5"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Language",
      "value": "English"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Accuracy",
      "value": "15.709"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Address",
      "value": "No. 62, Anping Rd, Zhonghe District, New Taipei City, Taiwan 235"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Altitude",
      "value": "27.399999618530273"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Bearing",
      "value": "0.0"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Latitude",
      "value": "24.996015"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Longitude",
      "value": "121.5104355"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Speed",
      "value": "0.0"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Last Known GPS Timestamp",
      "value": "2022-05-15T09:03:14.455Z"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Light",
      "value": "[6.0]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Linear Accelerometer",
      "value": "[-1.2052132, -0.11499733, 0.21131894]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Magnetic Field",
      "value": "[-0.09765625, -6.1523438, -77.83144]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Manufacturer",
      "value": "HTC"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Name",
      "value": "English (United States)"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Overall Product Name",
      "value": "bre2exdugl_00400"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Rotation Vector",
      "value": "[0.4130853, -0.04073075, 0.08709024, 0.90559506, 0.0]"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Script",
      "value": ""
    },
    {
      "provider": "InfoSnapshot",
      "name": "Timestamp",
      "value": "2022-05-15T09:16:22.898Z"
    },
    {
      "provider": "InfoSnapshot",
      "name": "Variant",
      "value": ""
    }
  ]
}
Example (raw), Sign with Zion is disabled:
$ cat information.json
{"proof":{"hash":"3eb44256eb98c9d43c48ed0dcbc660e8dafa9bdf54abf4da406846cea8311014","mimeType":"image/jpeg","timestamp":1652606172402},"information":[{"provider":"InfoSnapshot","name":"Accelerometer","value":"[0.4421997, 6.9092345, 6.9160113]"},{"provider":"InfoSnapshot","name":"Board","value":"QC_Reference_Phone"},{"provider":"InfoSnapshot","name":"Brand","value":"Htc"},{"provider":"InfoSnapshot","name":"Country","value":"United States"},{"provider":"InfoSnapshot","name":"Current GPS Accuracy","value":"17.307"},{"provider":"InfoSnapshot","name":"Current GPS Address","value":"No. 62, Anping Rd, Zhonghe District, New Taipei City, Taiwan 235"},{"provider":"InfoSnapshot","name":"Current GPS Altitude","value":"27.399999618530273"},{"provider":"InfoSnapshot","name":"Current GPS Bearing","value":"0.0"},{"provider":"InfoSnapshot","name":"Current GPS Latitude","value":"24.9960048"},{"provider":"InfoSnapshot","name":"Current GPS Longitude","value":"121.5104486"},{"provider":"InfoSnapshot","name":"Current GPS Speed","value":"0.0"},{"provider":"InfoSnapshot","name":"Current GPS Timestamp","value":"2022-05-15T09:16:13.438Z"},{"provider":"InfoSnapshot","name":"Device Build Fingerprint","value":"Htc/bre2exdugl_00400/htc_bre2exdugl:8.1.0/OPM1.171019.011/200630:user/release-keys"},{"provider":"InfoSnapshot","name":"Device Build ID","value":"1.15.709.1"},{"provider":"InfoSnapshot","name":"Device Build Tags","value":"release-keys"},{"provider":"InfoSnapshot","name":"Device Build Time","value":"6/30/20 8:16 PM"},{"provider":"InfoSnapshot","name":"Device Build Type","value":"user"},{"provider":"InfoSnapshot","name":"Device Name","value":"htc_bre2exdugl"},{"provider":"InfoSnapshot","name":"End Product Name","value":"EXODUS 1s"},{"provider":"InfoSnapshot","name":"Game Rotation Vector","value":"UNSUPPORTED"},{"provider":"InfoSnapshot","name":"Geomagnetic Rotation Vector","value":"[0.4146733, -0.044002537, 0.09306122, 0.9041181, 0.0]"},{"provider":"InfoSnapshot","name":"Gravity","value":"[1.7164232, 7.280239, 6.3422546]"},{"provider":"InfoSnapshot","name":"Gyroscope","value":"UNSUPPORTED"},{"provider":"InfoSnapshot","name":"Hardware","value":"qcom"},{"provider":"InfoSnapshot","name":"Hash of Android ID","value":"0fa0b3f57c76d453433151b46ed2f6562bd31183f1e21d0c092318e519a9aed5"},{"provider":"InfoSnapshot","name":"Language","value":"English"},{"provider":"InfoSnapshot","name":"Last Known GPS Accuracy","value":"15.709"},{"provider":"InfoSnapshot","name":"Last Known GPS Address","value":"No. 62, Anping Rd, Zhonghe District, New Taipei City, Taiwan 235"},{"provider":"InfoSnapshot","name":"Last Known GPS Altitude","value":"27.399999618530273"},{"provider":"InfoSnapshot","name":"Last Known GPS Bearing","value":"0.0"},{"provider":"InfoSnapshot","name":"Last Known GPS Latitude","value":"24.996015"},{"provider":"InfoSnapshot","name":"Last Known GPS Longitude","value":"121.5104355"},{"provider":"InfoSnapshot","name":"Last Known GPS Speed","value":"0.0"},{"provider":"InfoSnapshot","name":"Last Known GPS Timestamp","value":"2022-05-15T09:03:14.455Z"},{"provider":"InfoSnapshot","name":"Light","value":"[6.0]"},{"provider":"InfoSnapshot","name":"Linear Accelerometer","value":"[-1.2052132, -0.11499733, 0.21131894]"},{"provider":"InfoSnapshot","name":"Magnetic Field","value":"[-0.09765625, -6.1523438, -77.83144]"},{"provider":"InfoSnapshot","name":"Manufacturer","value":"HTC"},{"provider":"InfoSnapshot","name":"Name","value":"English (United States)"},{"provider":"InfoSnapshot","name":"Overall Product Name","value":"bre2exdugl_00400"},{"provider":"InfoSnapshot","name":"Rotation Vector","value":"[0.4130853, -0.04073075, 0.08709024, 0.90559506, 0.0]"},{"provider":"InfoSnapshot","name":"Script","value":""},{"provider":"InfoSnapshot","name":"Timestamp","value":"2022-05-15T09:16:22.898Z"},{"provider":"InfoSnapshot","name":"Variant","value":""}]}

Signature

signature.json provides both a digital signature and a public key. The content of signature.json does not equal to the digital signature of a Sorted Proof Information directly.

[
    {
        proofHash: Hex String,  # raw asset's sha256
        provider: String,       # cryptographic signing algorithm provider
        signature: Hex String,  # cryptographic digital signature signed by the private key
        publicKey: Hex String   # cryptographic public key for verifying the signature above
    },
    ...
]
Example (beautified), Sign with Zion is disabled:
$ jq . signature.json
[
  {
    "proofHash": "3eb44256eb98c9d43c48ed0dcbc660e8dafa9bdf54abf4da406846cea8311014",
    "provider": "AndroidOpenSSL",
    "signature": "304502203ced7a2eb4faee3422156066fd8da9afd8a851608f421340c437c3a1f0180fe7022100fdad1b273f5e4851077429ca4b692b223c9f20c0db5140a987aa2c6a86ea286b",
    "publicKey": "3059301306072a8648ce3d020106082a8648ce3d03010703420004813afd7f6ba95fdebeac7812c7ab5af9ca59547b2a73f5aa75accca4e4ad2eb6849d4948a9fcfb8c2b890ba0dfbe4463bbfe4ac163981a93517bfb34598fc850"
  }
]
Example (raw), Sign with Zion is disabled:
$ cat signature.json
[{"proofHash":"3eb44256eb98c9d43c48ed0dcbc660e8dafa9bdf54abf4da406846cea8311014","provider":"AndroidOpenSSL","signature":"304502203ced7a2eb4faee3422156066fd8da9afd8a851608f421340c437c3a1f0180fe7022100fdad1b273f5e4851077429ca4b692b223c9f20c0db5140a987aa2c6a86ea286b","publicKey":"3059301306072a8648ce3d020106082a8648ce3d03010703420004813afd7f6ba95fdebeac7812c7ab5af9ca59547b2a73f5aa75accca4e4ad2eb6849d4948a9fcfb8c2b890ba0dfbe4463bbfe4ac163981a93517bfb34598fc850"}]

Verification

The verification concept is that

  1. If Proof Information is trustworthy, the Asset checksum is trustworthy.
  2. If the Asset checksum is trustworthy, the Asset is trustworthy.

The Verification Tool and starling-capture-verification-examples.zip demonstrate the steps to verify the signatures.

verify.sh is a wrapper of starling_capture_verifier.py. If you want to assign the metadata (information.json) and signature (signature.json) individually, you can use starling_capture_verifier.py.

$ cd util/verification/

$ unzip starling-capture-verification-examples.zip

$ ./verify.sh starling-capture-verification-examples/1.8.0/d7a07fafcbafceb5d626d673f0aabdb4db9d4ce6058f4e9859380831e556aa5a
Verification result: Pass

Summary:
        SW key verification: True
        HW key verification (Zion): False
        HW key verification classic (Zion): False
        HW session key verification (Zion): False
        HW session key verification classic (Zion): True

Wallet Addresses:
        Zion singer wallet address: 0x5f5ad77f4f924232a6e486216ddefba8a732b96b

Note
        1. For the HW-related verifications, only one of them will be True.

$ ./verify.sh starling-capture-verification-examples/1.9.2/7e96c9fe16f96540de449a422852138d723c9ae80269fe4ae0e802323bf6ac7d 
Verification result: Pass

Summary:
        SW key verification: True
        HW key verification (Zion): False
        HW key verification classic (Zion): False
        HW session key verification (Zion): True
        HW session key verification classic (Zion): False

Wallet Addresses:
        Zion singer wallet address: 0x5f5ad77f4f924232a6e486216ddefba8a732b96b
        Recovered wallet address: 0x5f5ad77f4f924232a6e486216ddefba8a732b96b

Note
        1. For the HW-related verifications, only one of them will be True.

Before v1.9.2, Starling Capture uses "classic" signature/verification. The signature and verification flow charts are below.

Zion signature and verification

Starling - 22 08 11 Zion signature and verification

Zion session-based signature and verification

Starling - 22 08 11 Zion session-based signature and verification

Zion signature and verification classic (< v1.9.2)

Starling - 22 08 11 Zion signature and verification classic

Zion session-based signature and verification classic (< v1.9.2)

Starling - 22 08 11 Zion session-based signature and verification classic

Verification for v1.7.x

The known regression in v1.7.x (non-public pre-release) was due to that signatures were generated before the completion of HW metadata collection (#122). The issue was first introduced by commit a1f381df on 12 Oct 2020 and fixed 11 days after (23 Oct 2020) by commit 5f53d87.

Tips for verifying v1.7.0 metadata

  1. Metadata (information.json) ends with "noeol"

    1. Open Node.js
    2. Create metadata JSON object
    3. Save file by running fs.writeFileSync("information.json", JSON.stringify(metadataObj))
  2. Make value of the information key to be an empty list

  3. Make metadata look like

    {"proof":{"hash":"8e57db457dfb242405f31122318990cac21450a4bfed424e722a964ede1fe8e8","mimeType":"image/jpeg","timestamp":1662967587804},"information":[]}
    

Please kindly be noted that since Starling Capture is a project to experiment with new concepts, fast iteration and sometimes unmatured technologies are expected. It is always safer to use the latest tagged version instead of the old versions and the code branches.