Metadata-Version: 2.4
Name: upk-tool
Version: 0.1.2
Summary: Inspect, extract, and create UGREEN NAS .upk package files
Project-URL: Homepage, https://github.com/fuho/upk-tool
Project-URL: Issues, https://github.com/fuho/upk-tool/issues
Author-email: fuho <ondrej.dolejsi@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: firmware,nas,package,ugreen,upk
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: System :: Archiving :: Packaging
Classifier: Topic :: Utilities
Requires-Python: >=3.8
Provides-Extra: dev
Requires-Dist: build>=1.0; extra == 'dev'
Requires-Dist: pytest>=7.0; extra == 'dev'
Requires-Dist: twine>=4.0; extra == 'dev'
Provides-Extra: signing
Requires-Dist: cryptography>=3.0; extra == 'signing'
Description-Content-Type: text/markdown

# upk-tool

Inspect, extract, and create **UGREEN NAS `.upk` package files** (UGREEN-PKG-V2-FORMAT).

## What is a .upk file?

`.upk` files are application packages used by UGREEN NAS devices. They contain:

- **Cryptographic signatures** (RSA-2048) for file integrity and authenticity
- **Public keys** for signer and manufacturer verification
- **App icon** (PNG)
- **App payload** (gzip → tar → XZ → tar with app binaries, configs, web UI)
- **Hash chain** for additional integrity verification

### Format structure

```
UGREEN-PKG-V2-FORMAT
filesig:344:<base64 RSA signature>
userpub:392:<base64 DER public key>
usersig:344:<base64 RSA signature>
midpub:392:<base64 DER public key>
midsig:344:<base64 RSA signature>
ico:31350:<raw PNG binary>
ugb:15608334:<gzip compressed tar>
obj2:10204:<hex hash chain>
```

Each field follows the pattern `key:length:value` where `length` is the byte count of `value`.

## Installation

```bash
pip install upk-tool
```

For signing support:
```bash
pip install upk-tool[signing]
```

## Usage

### Inspect a .upk file

```bash
upk-tool verify firmware.upk
```

Output:
```
File: firmware.upk
Fields: 8
  filesig: 344 bytes
  userpub: 392 bytes
  usersig: 344 bytes
  midpub: 392 bytes
  midsig: 344 bytes
  ico: 31350 bytes
  ugb: 15608334 bytes
  obj2: 10204 bytes

  ugb contents (gzip tar): 2 entries
    uninstall.sh (657 bytes)
    com.ugreen.comic.ugb (15602856 bytes)
    -> com.ugreen.comic.ugb: XZ -> tar with 64 files

Signature verification:
  filesig: 256 bytes (RSA-2048)
  usersig: 256 bytes (RSA-2048)
  midsig: 256 bytes (RSA-2048)
  userpub: 294 bytes DER
  midpub: 294 bytes DER
```

### Extract a .upk file

```bash
upk-tool extract firmware.upk -o extracted/
```

This will:
1. Save all raw fields to the output directory
2. Create `metadata.json` with field metadata
3. Decompress the `ugb` payload (gzip → tar)
4. Decompress inner `.ugb` files (XZ → tar)
5. Extract the final app contents

Directory structure:
```
extracted/
├── metadata.json
├── ico.bin
├── ugb.bin
└── ugb_contents/
    ├── uninstall.sh
    ├── com.ugreen.app.ugb
    ├── com.ugreen.app_files.tar
    └── com.ugreen.app_app/
        ├── sbin/
        │   └── my_service
        ├── config.json
        ├── www/
        │   └── assets/
        └── ...
```

### Create a .upk file

```bash
upk-tool create ./my_app/ -o my_app.upk --icon icon.png --name myapp
```

Options:
- `--icon` - PNG icon file (optional, uses 1x1 placeholder if omitted)
- `--name` - App name used in the package (default: `app`)
- `--uninstall` - Custom uninstall script (optional)
- `--user-key` - RSA private key for user signing (PEM format)
- `--mfg-key` - RSA private key for manufacturer signing (PEM format)

### Create a signed .upk file

```bash
# Generate keys (for testing)
openssl genrsa -out user_key.pem 2048
openssl genrsa -out mfg_key.pem 2048

# Create signed package
upk-tool create ./my_app/ \
    -o my_app.upk \
    --icon icon.png \
    --name myapp \
    --user-key user_key.pem \
    --mfg-key mfg_key.pem
```

> **Note**: Without real UGREEN private keys, the package will have valid structure but signatures won't verify on actual hardware.

## How to Install Custom Apps on UGREEN NAS

There are **three paths** to running custom software on a UGREEN NAS:

### Path 1: Official Developer Program (Native .upk packages)

UGREEN has an **official developer program** at [developer.ugnas.com](https://developer.ugnas.com) that provides a CLI tool (`ugcli`) and a signing workflow.

**Steps:**

1. **Apply for developer authorization** - Email `developer@ugreen.com` with your NAS serial number, MAC address, and admin username
2. **Receive authorization file** - UGREEN sends back a signature file
3. **Upload to NAS** - Rename it to `ugdev.sig` and upload to admin's Personal Folder
4. **Authorize device** - Open App Center > Settings > App Development Settings > click "Authorize" (requires UGOS Pro 1.16.0+)
5. **Develop your app** - Use `ugcli` to create, package, and test your app

```bash
# Download ugcli (macOS)
curl -o ugcli https://osswaf.ugnas.com/pro/ugcli/download/ugcli-v1.1.0.12-darwin-amd64
chmod +x ugcli && sudo mv ugcli /usr/local/bin/

# Create a new app project
ugcli create com.mycompany.myapp

# Package into a signed .upk
ugcli pack --build 1
```

**App types supported:**
- **Native APP** - Compiled binary (Go/C/C++) + web frontend (Vue/React/HTML)
- **Docker APP** - Docker image + docker-compose.yaml + web frontend

**Publishing:** After testing, email your .upk to `developer@ugreen.com` for review and listing in the App Center.

Full docs: https://developer.ugnas.com

### Path 2: Docker (No Signing Required)

The most popular community approach. No .upk needed at all - just run Docker containers via Portainer or the UGREEN Docker app.

```bash
# Install Docker from UGREEN App Center first
# Then use Portainer or docker-compose to run any container
docker run -d --name myapp -p 8899:8080 myimage:latest
```

See [this guide](https://www.abrandao.com/2025/01/ugreen-nas-ugos-alternatives-to-missing-apps/) for popular Docker apps on UGREEN NAS.

### Path 3: This Tool (Analysis & Extraction)

`upk-tool` is useful for **inspecting, extracting, and analyzing** existing .upk packages. It can also create structurally valid packages, but those packages won't install on real hardware without UGREEN's signing keys (see `ugcli` in Path 1).

## ⚠️ Package Signing

**Packages created by this tool will not install on UGREEN NAS devices** because they lack valid RSA-2048 signatures from UGREEN's signing infrastructure. The `ugcli` tool from UGREEN's developer program handles signing automatically.

### How UGREEN Package Signing Works

UGREEN uses a dual-signature RSA-2048 system:

1. **filesig** - RSA-2048 signature of the entire package content
2. **userpub/usersig** - Signer's public key and signature (developer/3rd party)
3. **midpub/midsig** - Manufacturer's public key and signature (UGREEN)

The NAS validates these signatures cryptographically. Any modification to the package content (even 1 byte) invalidates the signature.

### What This Tool CAN Do

✅ **Extract and analyze** existing UGREEN packages  
✅ **Inspect package structure** and signatures  
✅ **Decompress all layers** (gzip, XZ, tar)  
✅ **Create structurally valid** .upk packages  
✅ **Modify extracted packages** (then repack - but signatures will be invalid)  
❌ **Create installable packages** - use `ugcli` from [developer.ugnas.com](https://developer.ugnas.com) instead  

## Reverse Engineering Findings

Analysis of UGREEN's official `ugcli` tool reveals interesting details about the signing process:

### Key Strings Found in ugcli

| String | Significance |
|--------|-------------|
| `"start signing upk"` | Confirms local signing during `pack` |
| `"appmaker.MakePkg(rootfs:%s,ugb:%s,dest:%s)"` | Internal packaging function |
| `"private key error"` | Handles RSA keys locally |
| `"RSA PRIVATE KEY"` / `"RSA PUBLIC KEY"` | Standard PEM markers |
| `"sig:%d:%s"` / `"ico:%d:%s"` / `"pub:%d:%s"` / `"obj:%d:%s"` | Field format strings |
| `"UGREEN-PKG-FORMAT"` | Note: **no V2** in this string! vs original file's `UGREEN-PKG-V2-FORMAT` |
| `"gen app check md5 error"` | MD5 checksum generation |

### Signing Flow

Based on the external [UgreenNAS-SDK](https://github.com/uguraltinsoy/UgreenNAS-SDK) project, the signing flow appears to be:

1. Each authorized developer gets a **UID-based keypair** stored in `/var/cache/ugreen-rsa/` on the NAS
2. `ugcli pack` likely **contacts the NAS** (or uses the `ugdev.sig` authorization) to sign the package remotely
3. The `userpub`/`usersig` fields correspond to your developer key, while `midpub`/`midsig` are UGREEN's manufacturer keys

### Potential for Custom Signing

The signing likely happens via communication with your authorized NAS device. The `ugdev.sig` file authorizes the device to accept packages signed by your developer UID key stored at `/var/cache/ugreen-rsa/<uid>.pub`.

Our tool could potentially replicate this workflow if anyone with an authorized NAS wants to investigate where `ugcli` contacts it for signing.

## Python API

```python
from upk_tool import parse_upk, extract_upk, create_upk, verify_upk

# Parse and inspect
fields = parse_upk("firmware.upk")
print(fields.keys())  # ['filesig', 'userpub', 'usersig', ...]

# Extract
extract_upk("firmware.upk", "output_dir/")

# Create
create_upk(
    app_dir="./my_app/",
    output_path="output.upk",
    icon_path="icon.png",
    app_name="myapp",
)

# Verify/inspect
verify_upk("firmware.upk")
```

## Development

```bash
# Clone and install in development mode
git clone https://github.com/fuho/upk-tool.git
cd upk-tool
pip install -e ".[dev]"

# Run tests
pytest

# Build package
python -m build

# Upload to PyPI
twine upload dist/*
```

## License

MIT
