171 lines
4.9 KiB
Markdown
171 lines
4.9 KiB
Markdown
# DFP Bootstrap Design
|
|
|
|
## Goal
|
|
|
|
Add a pure Python DFP bootstrap layer that consumes `DeviceProfile` and builds
|
|
DFP/unifiedId request material without depending on APP runtime, HAR templates,
|
|
Frida logs, or scripts under `out/`.
|
|
|
|
The first deliverable is deterministic dry-run request construction. Online
|
|
POST and profile update are added only after dry-run form material is isolated,
|
|
tested, and stable.
|
|
|
|
## Current Evidence
|
|
|
|
Recovered relationships and algorithms already available in `core/`:
|
|
|
|
- `core.enc_data.kwsg_10400_raw()` builds the 10400 `deviceInfo` envelope.
|
|
- `core.dfp_sign.sign_dfp_form()` builds 10405 `sign`.
|
|
- `core.device_profile.DeviceProfile` holds local `did/oDid/rdid/egid` state.
|
|
- `egid` is returned by `/rest/infra/gdfp/report/kuaishou/android`.
|
|
- cloud `did/cdid_tag` comes from unifiedId fetch/repair responses.
|
|
|
|
Useful prototype code currently lives under `out/`:
|
|
|
|
- `out/dfp_sq0_proto.py`
|
|
- `out/build_dfp_lite_knn.py`
|
|
- `out/build_dfp_full_knn.py`
|
|
- `out/build_dfp_fetch_form.py`
|
|
- `out/build_dfp_repair_form.py`
|
|
- `out/build_dfp_check_repair_form.py`
|
|
- `out/build_dfp_report_form.py`
|
|
- `out/dfp_protocol_client.py`
|
|
|
|
Phase 2 migrates the reusable pieces into `core/` and leaves analysis scripts in
|
|
`out/` as historical evidence only.
|
|
|
|
## Scope
|
|
|
|
### Included
|
|
|
|
- Encode DFP sq0 protobuf bytes for lite and full kNN maps.
|
|
- Build lite and full kNN maps from `DeviceProfile` plus optional static
|
|
environment/profile fields.
|
|
- Build signed forms for:
|
|
- `unifiedId/fetch/android`
|
|
- `unifiedId/checkRepair`
|
|
- `unifiedId/repair/android`
|
|
- `gdfp/report/kuaishou/android`
|
|
- Export request specs with URL, headers, ordered form, body, and debug hashes.
|
|
- Add optional online POST client after dry-run builders pass tests.
|
|
- Parse cloud DID / did tag / egid responses and write them back through
|
|
`DeviceProfile.apply_cloud_identity()`.
|
|
|
|
### Excluded
|
|
|
|
- Live APP instrumentation.
|
|
- HAR runtime templates.
|
|
- Mutating `main.py` task flow.
|
|
- Claiming `egid` is locally generated.
|
|
|
|
## Architecture
|
|
|
|
```text
|
|
DeviceProfile
|
|
-> core.dfp_knn.build_lite_knn()
|
|
-> core.dfp_sq0.encode_sq0_device_info()
|
|
-> core.enc_data.kwsg_10400_raw()
|
|
-> core.dfp_forms.build_unified_fetch_form()
|
|
-> core.dfp_forms.build_unified_check_repair_form()
|
|
-> core.dfp_forms.build_gdfp_report_form()
|
|
-> core.dfp_client.post_request() # online only
|
|
-> DeviceProfile.apply_cloud_identity()
|
|
```
|
|
|
|
### `core/dfp_sq0.py`
|
|
|
|
Pure sq0 protobuf encoder/decoder.
|
|
|
|
Responsibilities:
|
|
|
|
- load embedded lite/full key-to-proto-tag schema
|
|
- encode ordered kNN string maps
|
|
- decode fields for tests and diagnostics
|
|
|
|
### `core/dfp_knn.py`
|
|
|
|
Build DFP plaintext kNN maps.
|
|
|
|
Responsibilities:
|
|
|
|
- build lite 33-key map
|
|
- build full 119-key map
|
|
- compute `k14` CRC
|
|
- use `DeviceProfile` for identity fields:
|
|
- `k31` android id
|
|
- `k66` oDid suffix
|
|
- `k83` current cached egid or empty first-run value
|
|
- `k107` did tag
|
|
- `k112` cache marker if supplied
|
|
- `k93.28` gRdi2
|
|
|
|
### `core/dfp_forms.py`
|
|
|
|
Build signed form objects.
|
|
|
|
Responsibilities:
|
|
|
|
- wrap sq0 bytes in 10400 `deviceInfo`
|
|
- Java-style base64 and form encoding
|
|
- preserve request form order
|
|
- use `core.dfp_sign.sign_dfp_form()`
|
|
- expose `DfpRequestSpec`
|
|
|
|
### `core/dfp_client.py`
|
|
|
|
Optional online client.
|
|
|
|
Responsibilities:
|
|
|
|
- POST request specs using `requests`
|
|
- parse JSON safely
|
|
- return structured `DfpResponse`
|
|
- update `DeviceProfile` only when response fields pass validation
|
|
|
|
### `tools/new_device.py`
|
|
|
|
Extends current CLI:
|
|
|
|
- `--dfp-dry-run`: write DFP request material without sending.
|
|
- `--online`: send DFP bootstrap requests and update saved profile.
|
|
- `--profile PATH`: load an existing profile instead of creating a new one.
|
|
|
|
## Error Handling
|
|
|
|
- Missing required identity fields raise `ValueError`.
|
|
- Invalid DFP response fields are recorded and not applied.
|
|
- Online mode records HTTP status, JSON parse failures, and business result.
|
|
- Request builders never silently omit known empty fields; empty strings remain
|
|
present when the Java form includes the key.
|
|
|
|
## Test Strategy
|
|
|
|
Use TDD and `unittest` because this project does not currently depend on
|
|
`pytest`.
|
|
|
|
Required checks:
|
|
|
|
- sq0 encoder keeps key order and skips empty values in the same way as the
|
|
prototype.
|
|
- k14 CRC changes when any mapped value changes.
|
|
- lite kNN uses `DeviceProfile` identity fields.
|
|
- form builders preserve known form order.
|
|
- DFP sign input material matches `core.dfp_sign` rules.
|
|
- dry-run request specs produce deterministic body ordering.
|
|
- online response parser only applies valid `cloud_did/did_tag/egid`.
|
|
|
|
## Milestones
|
|
|
|
1. Dry-run migration:
|
|
- `core/dfp_sq0.py`
|
|
- `core/dfp_knn.py`
|
|
- `core/dfp_forms.py`
|
|
2. CLI integration:
|
|
- `tools/new_device.py --dfp-dry-run`
|
|
3. Online bootstrap:
|
|
- `core/dfp_client.py`
|
|
- `tools/new_device.py --online`
|
|
4. Request/profile persistence:
|
|
- save request material under `out/devices/<profile>/dfp_*.json`
|
|
- save updated profile JSON after accepted server identity response
|