merged from gramsrv upstream
This commit is contained in:
parent
79c64ee916
commit
21a0856587
651 changed files with 54774 additions and 4590 deletions
175
docs/update-service.md
Normal file
175
docs/update-service.md
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
# Native client update service
|
||||
|
||||
`cmd/telesrv-update` is a standalone HTTP service that provides two
|
||||
Telegram-compatible update surfaces:
|
||||
|
||||
- `/current4` and `/files/*` for the built-in Telegram Desktop updater;
|
||||
- `/v1/resolve` for the main `telesrv` process to answer
|
||||
`help.getAppUpdate` for Android, iOS, and other supported builds.
|
||||
|
||||
The service has no HTTP upload endpoint. Operators publish a release by placing
|
||||
an immutable artifact in the configured `files` directory and atomically
|
||||
replacing `manifest.json`. The catalog validates the file size and SHA-256
|
||||
before exposing it, so truncated or accidentally replaced packages fail closed.
|
||||
|
||||
## Quick start
|
||||
|
||||
Create the working directories and start with the disabled example catalog:
|
||||
|
||||
```powershell
|
||||
New-Item -ItemType Directory -Force data\updates\files
|
||||
Copy-Item deploy\update\manifest.example.json data\updates\manifest.json
|
||||
|
||||
go run ./cmd/telesrv-update -check
|
||||
go run ./cmd/telesrv-update
|
||||
```
|
||||
|
||||
Check the local endpoints:
|
||||
|
||||
```powershell
|
||||
Invoke-RestMethod http://127.0.0.1:2402/readyz
|
||||
Invoke-RestMethod http://127.0.0.1:2402/current4
|
||||
```
|
||||
|
||||
Connect the main server:
|
||||
|
||||
```dotenv
|
||||
TELESRV_UPDATE_PUBLIC_URL=https://updates.example.test
|
||||
TELESRV_UPDATE_SERVICE_URL=http://127.0.0.1:2402
|
||||
TELESRV_UPDATE_REQUEST_TIMEOUT=2s
|
||||
```
|
||||
|
||||
`PUBLIC_URL` must be reachable by clients and is advertised as
|
||||
`help.getConfig.autoupdate_url_prefix`. `SERVICE_URL` may remain a loopback or
|
||||
private route. When both routes are identical, `SERVICE_URL` may be omitted.
|
||||
Production deployments should place an HTTPS reverse proxy in front of the
|
||||
service without rewriting `/current4` or `/files/*`.
|
||||
|
||||
Standalone service settings:
|
||||
|
||||
```dotenv
|
||||
TELESRV_UPDATE_LISTEN=127.0.0.1:2402
|
||||
TELESRV_UPDATE_MANIFEST=data/updates/manifest.json
|
||||
TELESRV_UPDATE_FILES_DIR=data/updates/files
|
||||
```
|
||||
|
||||
The manifest is reloaded automatically when its timestamp or size changes. A
|
||||
malformed replacement makes readiness and catalog requests return `503`; it is
|
||||
never combined with the previously validated snapshot. Validate a candidate
|
||||
before atomically replacing the active file:
|
||||
|
||||
```powershell
|
||||
go run ./cmd/telesrv-update `
|
||||
-manifest .\manifest.next.json `
|
||||
-files .\data\updates\files `
|
||||
-check
|
||||
```
|
||||
|
||||
## Telegram Desktop contract
|
||||
|
||||
TDesktop requests `<autoupdate_url_prefix>/current4`. A Windows x64 stable
|
||||
release is represented as:
|
||||
|
||||
```json
|
||||
{
|
||||
"win64": {
|
||||
"stable": {
|
||||
"released": 7000007,
|
||||
"link": "/files/tx64upd7000007"
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The client compares `released` with its numeric `AppVersion`, downloads the
|
||||
artifact with HTTP Range support, verifies the embedded RSA signature, unpacks
|
||||
it, and only then exposes the normal update banner. A regular EXE or ZIP is not
|
||||
a valid update package.
|
||||
|
||||
Build packages with TDesktop's `Packer` target. The equivalent Windows x64
|
||||
command is:
|
||||
|
||||
```powershell
|
||||
Packer.exe `
|
||||
-version 7000007 `
|
||||
-path Telegram.exe `
|
||||
-path Updater.exe `
|
||||
-path "modules\x64\d3d\d3dcompiler_47.dll" `
|
||||
-target win64
|
||||
```
|
||||
|
||||
It produces `tx64upd7000007` and must report `Signature verified!` before the
|
||||
artifact is published.
|
||||
|
||||
| Platform | `/current4` key | Typical package name |
|
||||
|---|---|---|
|
||||
| Windows x64 | `win64` | `tx64upd<build>` |
|
||||
| Windows ARM64 | `winarm` | `tarm64upd<build>` |
|
||||
| Windows x86 | `win` | `tupdate<build>` |
|
||||
| macOS Intel | `mac` | `tmacupd<build>` |
|
||||
| macOS Apple Silicon | `armac` | `tarmacupd<build>` |
|
||||
| Linux | `linux` | `tlinuxupd<build>` |
|
||||
|
||||
## Update signing
|
||||
|
||||
The public TDesktop sources contain Telegram's public update key; the matching
|
||||
private key is not published. A custom deployment must establish its own update
|
||||
signing identity:
|
||||
|
||||
1. Generate a dedicated RSA-1024 key pair and keep the private key only in a
|
||||
protected build secret store.
|
||||
2. Provide the private key to TDesktop's local `DesktopPrivate/packer_private.h`.
|
||||
3. Embed the matching public key in both the client update verifier and Packer.
|
||||
4. Rebuild the bootstrap client and Packer before publishing updates.
|
||||
5. Do not rotate the key without a transition client that trusts both identities.
|
||||
|
||||
The update service never reads the private key and never creates signatures. It
|
||||
checks SHA-256 and serves an artifact that Packer has already signed. A stock
|
||||
TDesktop binary cannot install a package signed only by a custom key; the first
|
||||
custom client build must be distributed out of band.
|
||||
|
||||
## HTTP behavior
|
||||
|
||||
- `/healthz` reports process liveness.
|
||||
- `/readyz` validates the current catalog.
|
||||
- `/current`, `/current1` ... `/current4` return desktop metadata with
|
||||
`Cache-Control: no-cache`.
|
||||
- `/files/<name>` serves only artifacts referenced by the current validated
|
||||
catalog, supports GET/HEAD and Range, and emits an immutable cache policy and
|
||||
a SHA-256-based ETag.
|
||||
- `/v1/resolve` returns a newer application release or `204 No Content`.
|
||||
|
||||
Unknown package names are not exposed merely because a file exists in the
|
||||
directory. Published package names are immutable: changing an active file makes
|
||||
the endpoint return `503` until a matching manifest snapshot is loaded.
|
||||
|
||||
## Android and iOS
|
||||
|
||||
The main server forwards the client platform, current `app_version`, source,
|
||||
channel, and `lang_code` to `/v1/resolve`. The resolver selects localized notes,
|
||||
does not offer an equal or older version, and applies `url_by_source` when a
|
||||
matching installer/store source is configured.
|
||||
|
||||
- A standalone Android build may open or install an APK URL, but the APK must be
|
||||
signed with the same Android application signing key as the installed build.
|
||||
- Google Play and other store builds should use the corresponding store URL;
|
||||
this mechanism does not bypass store policy.
|
||||
- iOS may display information returned by `help.getAppUpdate`, but installation
|
||||
still happens through App Store, TestFlight, or MDM. A normal iOS application
|
||||
cannot replace itself from an arbitrary IPA URL.
|
||||
- Set `can_not_skip` only after confirming that the target release is actually
|
||||
available to every affected client.
|
||||
|
||||
## Manifest fields
|
||||
|
||||
- `desktop.<platform>.<channel>.build`: numeric TDesktop `AppVersion`.
|
||||
- `file`, `sha256`, `size`: immutable signed artifact and integrity metadata.
|
||||
- `apps.<platform>.<channel>.id`: stable positive release identifier.
|
||||
- `version`: value compared with the client's `initConnection.app_version`.
|
||||
- `notes`: localized text keyed by `en`, `ru`, `ru-ru`, and similar codes.
|
||||
- `url_by_source`: source-specific installer or store URL.
|
||||
- `can_not_skip`: whether the client may dismiss the application update.
|
||||
- `disabled`: keep a valid entry as a draft without publishing it.
|
||||
|
||||
Supported channels are `stable`, `beta`, and `alpha`. See
|
||||
`deploy/update/manifest.example.json` for a complete disabled example.
|
||||
Loading…
Add table
Add a link
Reference in a new issue