CatShare Documentation

repository·main·Indexed 20 days ago

https://github.com/kmod-midori/catshare

A file and text transfer application for Android featuring Bluetooth discovery and cross-device compatibility. Part of the Mutual Transfer Alliance (互传联盟), it supports file sending via Shizuku and secure BLE sessions using ECDH key exchange and AES-CTR encryption. The documentation covers core features, P2P sender and receiver services, the GattServerService for BLE operations, and application configuration via AppSettings.

Tokens
3.3K
Snippets
14
Records
19
Agent score
72%

What's inside CatShare

  1. Core Features of CatShare

    main

    CatShare provides the following capabilities:

    • Bluetooth Discovery: Finding nearby devices via Bluetooth.
    • File Receiving: Receiving files from other devices.
    • File Sending: Sending files (requires Shizuku support).
    • Text Transfer:
      • If both devices are running CatShare: Copies text to the clipboard on the receiving side.
      • If the receiver is a different device: Sends the text as a text file.
  2. Capture and export logcat logs

    main

    CatShare allows users to capture the current logcat output and export it as a text file.

    When the 'Capture Logs' option is selected:

    1. A logcat.txt file is generated in the application's cache directory under the logs folder.
    2. The system executes logcat -d to dump the current logs.
    3. An Android ACTION_SEND intent is triggered, allowing the user to share the resulting text file via other applications (e.g., email, file manager, or messaging apps).

    If the capture process fails, a toast message with the error notification will be displayed.

  3. Establish a secure BLE session using BleSecurity

    main

    To secure communication over Bluetooth Low Energy (BLE), use BleSecurity to perform an Elliptic Curve Diffie-Hellman (ECDH) key exchange.

    1. Retrieve your local public key using getEncodedPublicKey() and share it with the remote device.
    2. Receive the remote device's public key as a Base64 encoded string.
    3. Call deriveSessionKey(publicKey) with the remote key to obtain a SessionCipher instance.
    4. Use the SessionCipher instance to encrypt or decrypt messages.

    Encryption uses AES in CTR mode with a fixed IV (0102030405060708).

    // 1. Get your public key to send to the other device
    val myPublicKey = BleSecurity.getEncodedPublicKey()
    
    // 2. After receiving the remote public key (as a Base64 string)
    val remotePublicKey = "REMOTE_PUBLIC_KEY_BASE64"
    val session = BleSecurity.deriveSessionKey(remotePublicKey)
    
    // 3. Encrypt a message
    val encrypted = session.encrypt("Hello, secure world!")
    
    // 4. Decrypt a message
    val decrypted = session.decrypt(encrypted)
  4. Configure application settings

    main

    The SettingsActivity provides a user interface to manage application behavior. Users can modify the following settings:

    • Device Name: A text field to set the identifier for the device.
    • Verbose Mode: A toggle switch to enable or disable verbose logging.
    • Auto Accept: A toggle switch to enable or disable automatic acceptance of requests.

    Changes are applied when the user clicks the checkmark icon in the top app bar. The device name is only saved if the input is not blank.

  5. Retrieve adb logcat for troubleshooting

    main

    When reporting issues in the GitHub issue tracker, please provide the adb logcat logs from the device. Use the specific command corresponding to your build type (Release or Debug) and your operating system (Linux/macOS or Windows).

    ### Release Version
    
    **Linux/macOS:**
    ```shell
    adb logcat --pid $(adb shell pidof -s moe.reimu.catshare)

    Windows (CMD):

    for /f "tokens=1" %i in ('adb shell pidof -s moe.reimu.catshare') do adb logcat --pid %i

    Debug Version

    Linux/macOS:

    adb logcat --pid $(adb shell pidof -s moe.reimu.catshare.debug)

    Windows (CMD):

    for /f "tokens=1" %i in ('adb shell pidof -s moe.reimu.catshare.debug') do adb logcat --pid %i
  6. Get an Intent for P2pSenderService

    main

    If you need to manually construct an Intent to bind to or start the P2pSenderService, use the getIntent helper method. This ensures the TaskInfo is correctly attached to the intent extras.

    Parameters:

    • context: The Android Context.
    • task: The TaskInfo object representing the transfer job.
    val intent = P2pSenderService.getIntent(context, task)
    // Use this intent with context.startService(intent) or context.bindService(...)
  7. Cancel a running P2P transfer task

    main

    You can cancel an active transfer task by calling the cancel method on the P2pSenderService instance. This is typically done via a broadcast receiver that listens for the ACTION_CANCEL_SENDING intent. The service uses a currentTaskLock to ensure only the currently active task is cancelled.

    Parameters:

    • taskId: The unique integer ID of the task to be cancelled.
    // If you have access to the service instance via a Binder:
    p2pSenderService.cancel(task.id)
  8. Start a P2P file transfer task

    main

    To initiate a file transfer via the P2pSenderService, use the startTaskChecked method. This method checks if the application is already busy with another task before starting the service. If the application is busy, it returns false and shows a toast notification. If successful, it starts the service in the foreground with a notification.

    Parameters:

    • context: The Android Context used to start the service.
    • task: A TaskInfo object containing the files to be sent and the target device information.

    Returns:

    • Boolean: true if the task was successfully started, false if the application was already busy.
    val task = TaskInfo(/* ... */)
    val success = P2pSenderService.startTaskChecked(context, task)
    if (!success) {
        // Handle the case where the app is already busy
    }
  9. Start the P2pReceiverService to receive files

    main

    To initiate a file or data reception task via P2P, start the P2pReceiverService using an Intent created via P2pReceiverService.getIntent(context, p2pInfo). The p2pInfo object must contain the necessary connection details (SSID, PSK, and port) to establish the P2P link.

    When the service starts:

    1. It attempts to connect to the specified P2P network.
    2. It establishes a WebSocket connection to the sender.
    3. It listens for a sendrequest action.
    4. If autoAccept is disabled in AppSettings, it displays a notification asking the user to accept or reject the incoming transfer.
    5. Files are downloaded and saved to the device's Downloads/CatShare directory via the MediaStore API.
    // Example of how to start the receiver service
    val p2pInfo = P2pInfo(
        ssid = "ExampleSSID",
        psk = "ExamplePassword",
        port = 8080
    )
    val intent = P2pReceiverService.getIntent(context, p2pInfo)
    context.startService(intent)
  10. Cancel a running P2pReceiverService task

    main

    You can cancel a specific ongoing reception task by calling the cancel(taskId: Int) method on the P2pReceiverService instance. This method targets the task associated with the provided taskId and cancels its underlying coroutine job.

    // Assuming you have access to the service instance or a way to trigger the cancel action
    p2pReceiverService.cancel(localTaskId)
  11. Start or stop the GattServerService

    main

    The GattServerService is a foreground service responsible for Bluetooth GATT server operations, including device discovery via advertising and handling P2P connections. You can control the service lifecycle using the start and stop methods in its companion object.

    Note: The service requires Bluetooth permissions and will automatically stop itself if permissions are missing or if Bluetooth is disabled.

    // To start the service
    GattServerService.start(context)
    
    // To stop the service
    GattServerService.stop(context)