Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
node_modules/
coverage/
dist/
*.tsbuildinfo
ci-logs/
*.log
.DS_Store
.env
.env.*
!.env.example
web/public/tdweb.js
web/public/*.worker.js
web/public/*.wasm
web/public/*.mem
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ This repository is in the foundation phase. The current implementation establish
- Desktop wrapper contract for the Electron stack, runnable debug artifact metadata for Linux, macOS, and Windows, tray menu behavior, system notifications, shortcuts, autostart, protocol routing, and DMG/EXE/AppImage packaging targets.
- Responsive tablet layout contract for chats, settings, agent, and wallet views, including shared breakpoints, portrait and landscape navigation modes, split-pane frames, and narrow-tablet sheet fallback behavior.
- PWA wrapper contract for the web app manifest, service worker strategy, offline shell validation, update behavior, installability metadata, and browser fallbacks for unsupported native capabilities.
- Alpha Web client in `web/` with React 18, Vite, TypeScript, TailwindCSS, TDWeb service bindings, encrypted opt-in settings/session storage, proxy configuration, Teleton Agent controls, and TON operation panels.
- Local Teleton Agent runtime supervisor contract with mock lifecycle tests for start, stop, health, resource monitoring, and logs.
- Teleton Agent action notification contract for proposals, starts, completions, approval-required states, and failures with settings-aware delivery and redacted lock-screen text.
- Teleton Agent action history contract for redacted action records, retention filtering, rollback eligibility, and irreversible action markers.
Expand Down Expand Up @@ -81,7 +82,7 @@ The project is intended to evolve through these layers:
4. TON blockchain integrations for wallet, transfers, swaps, NFTs, staking, and DNS.
5. Security and privacy controls for credentials, user consent, and auditability.

See `SECURITY.md`, `docs/architecture.md`, `docs/backlog.md`, `docs/tdlib-adapter.md`, `docs/android-wrapper.md`, `docs/ios-wrapper.md`, `docs/desktop-wrapper.md`, `docs/tablet-layout.md`, `docs/web-pwa-wrapper.md`, `docs/security-audit.md`, `docs/license-matrix.md`, `docs/release-strategy.md`, `docs/release-packaging.md`, and `docs/release-readiness.md` for the current foundation plan. The agent settings, local runtime, input action map, Android wrapper, iOS wrapper, desktop wrapper, tablet layout, PWA, message database encryption, secure data deletion, security policy, security audit, license matrix, release packaging, and release readiness sections record the shared settings UI contract, supported runtime directions, platform execution boundaries, shortcut and gesture behavior, hardware security key capability checks, responsive tablet behavior, web installability behavior, vulnerability reporting expectations, credential rotation expectations, secure storage review requirements, upstream license obligations, source publication review, protected signing boundaries, human release approval, and remaining native packaging implementation gaps for Android, iOS, desktop, and web wrappers.
See `SECURITY.md`, `docs/architecture.md`, `docs/backlog.md`, `docs/AUTH.md`, `docs/tdlib-adapter.md`, `docs/android-wrapper.md`, `docs/ios-wrapper.md`, `docs/desktop-wrapper.md`, `docs/tablet-layout.md`, `docs/web-pwa-wrapper.md`, `web/README.md`, `docs/security-audit.md`, `docs/license-matrix.md`, `docs/release-strategy.md`, `docs/release-packaging.md`, and `docs/release-readiness.md` for the current foundation plan and alpha web client. The agent settings, local runtime, input action map, Android wrapper, iOS wrapper, desktop wrapper, tablet layout, PWA, authentication flows, message database encryption, secure data deletion, security policy, security audit, license matrix, release packaging, and release readiness sections record the shared settings UI contract, supported runtime directions, platform execution boundaries, shortcut and gesture behavior, hardware security key capability checks, responsive tablet behavior, web installability behavior, vulnerability reporting expectations, credential rotation expectations, secure storage review requirements, upstream license obligations, source publication review, protected signing boundaries, human release approval, and remaining native packaging implementation gaps for Android, iOS, desktop, and web wrappers.

## Contribution Templates

Expand Down
36 changes: 36 additions & 0 deletions docs/AUTH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Authentication

Teleton Client Web uses TDWeb/TDLib authorization. The alpha supports two interactive user flows:

- Phone number, one-time code, and optional two-step password.
- Telegram QR login through TDLib native QR authorization.

## Telegram API Credentials

The browser client still needs `VITE_TELEGRAM_API_ID` and `VITE_TELEGRAM_API_HASH` from `.env` before either sign-in method can start. These values are read by the TDLib service and are not hardcoded in source.

## Phone Sign-In

The default flow follows the TDLib authorization state machine:

1. `authorizationStateWaitPhoneNumber`
2. `setAuthenticationPhoneNumber`
3. `authorizationStateWaitCode`
4. `checkAuthenticationCode`
5. `authorizationStateWaitPassword`, when the account requires two-step verification
6. `authorizationStateReady`

Telegram session data remains runtime-only by default. The UI can save an encrypted session marker only after explicit user consent.

## QR Sign-In

The QR option uses TDLib directly instead of a separate web backend. When TDLib is in `authorizationStateWaitPhoneNumber`, the client calls `requestQrCodeAuthentication` with an empty `other_user_ids` list. TDLib then emits `authorizationStateWaitOtherDeviceConfirmation` with a `link` field. The UI renders that `tg://` link as a QR code and refreshes it whenever TDLib sends a new link.

The QR payload is never stored in localStorage. The rendered code is derived from the latest in-memory TDLib authorization update and is cleared when the user switches back to phone login, restarts auth, or reaches `authorizationStateReady`.

## Security Notes

- Do not add bot tokens, Telegram API hashes, or session strings to source control.
- Do not place login tokens in URLs owned by the web app.
- Keep QR payloads one-session only and in memory.
- If a future backend flow is added, implement short TTLs, single-use server state, rate limiting, and audit logging before exposing it.
1 change: 1 addition & 0 deletions docs/license-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ Verified on 2026-04-26 UTC from GitHub license metadata and upstream license or
| [`ton-org/ton-core`](https://github.com/ton-org/ton-core) | Low-level TypeScript TON cell, address, and serialization utilities for shared TON adapters. | MIT | Permissive license with notice preservation. No copyleft source publication obligation is expected from the top-level license. | Candidate dependency. Preserve MIT notice, pin package version or commit, and review transitive dependencies before release readiness. |
| [`toncenter/tonweb`](https://github.com/toncenter/tonweb) | Candidate fallback JavaScript SDK for TON wallet and provider interactions. | MIT | Permissive license with notice preservation. No copyleft source publication obligation is expected from the top-level license. | Candidate fallback only. Preserve MIT notice, compare maintenance/security posture with `ton-org/ton`, and review transitive dependencies before release readiness. |
| [`ton-connect/sdk`](https://github.com/ton-connect/sdk) | Candidate wallet-provider connection SDK for TON confirmation and signing handoff flows. | Apache-2.0 | Permissive license with NOTICE and patent-license conditions. No copyleft source publication obligation is expected, but NOTICE files and local modifications must be preserved. | Candidate dependency. Preserve Apache-2.0 license and NOTICE content, pin package version or commit, and include patent/notice review in release readiness. |
| [`soldair/node-qrcode`](https://github.com/soldair/node-qrcode) | Web QR image generation for TDLib Telegram QR authorization in `web/`. | MIT | Permissive license with notice preservation. No copyleft source publication obligation is expected from the top-level license. | Web dependency. Preserve MIT notice, pin npm package version, and include transitive dependency review before release readiness. |
| [`ston-fi/sdk`](https://github.com/ston-fi/sdk) | Candidate STON.fi swap provider SDK for quote and unsigned swap transaction preparation. | MIT | Permissive license with notice preservation. No copyleft source publication obligation is expected from the top-level license. | Candidate dependency for swap work. Preserve MIT notice, pin package version or commit, and review transitive dependencies before release readiness. |
| [`dedust-io/sdk`](https://github.com/dedust-io/sdk) | Candidate DeDust swap provider SDK for quote and unsigned swap transaction preparation. | Apache-2.0 | Permissive license with NOTICE and patent-license conditions. No copyleft source publication obligation is expected, but NOTICE files and local modifications must be preserved. | Candidate dependency for swap work. Preserve Apache-2.0 license and NOTICE content, pin package version or commit, and include patent/notice review in release readiness. |
| [`xssnick/tonutils-go`](https://github.com/xssnick/tonutils-go) | Candidate native helper or service implementation for TON protocol operations where a Go bridge is preferred. | MIT | Permissive license with notice preservation. No copyleft source publication obligation is expected from the top-level license. | Optional native helper candidate. Preserve MIT notice, pin revision, audit transitive Go modules, and review binary distribution notices before release readiness. |
Expand Down
Binary file added docs/screenshots/web-alpha-auth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/web-alpha-qr-auth-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/web-alpha-qr-auth.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/screenshots/web-alpha-settings-mobile.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
106 changes: 106 additions & 0 deletions test/web-alpha-release.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import assert from 'node:assert/strict';
import { existsSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { test } from 'node:test';

const root = new URL('../', import.meta.url);

function pathFor(relativePath) {
return new URL(relativePath, root);
}

async function readJson(relativePath) {
return JSON.parse(await readFile(pathFor(relativePath), 'utf8'));
}

test('alpha web client release project is scaffolded with the required runtime contracts', async () => {
const requiredFiles = [
'web/package.json',
'web/index.html',
'web/vite.config.ts',
'web/.env.example',
'web/README.md',
'web/deploy.sh',
'docs/AUTH.md',
'web/public/manifest.webmanifest',
'web/public/service-worker.js',
'web/public/offline.html',
'web/public/icons/icon-192.png',
'web/public/icons/icon-512.png',
'web/src/app/App.tsx',
'web/src/services/tdlib.service.ts',
'web/src/services/agent.service.ts',
'web/src/services/proxy.service.ts',
'web/src/services/crypto.service.ts',
'web/src/shared/store/useTeletonStore.ts',
'web/src/widgets/ChatList.tsx',
'web/src/widgets/MessageWindow.tsx',
'web/src/widgets/InputBar.tsx',
'web/tests/services.test.ts'
];

for (const requiredFile of requiredFiles) {
assert.equal(existsSync(pathFor(requiredFile)), true, `${requiredFile} is required for the alpha web release`);
}

const packageJson = await readJson('web/package.json');
assert.equal(packageJson.scripts.dev, 'vite --host 0.0.0.0');
assert.equal(packageJson.scripts.build, 'tsc -b && vite build');
assert.equal(packageJson.scripts.test, 'vitest run');

for (const dependency of ['@tonconnect/ui-react', 'qrcode', 'react', 'react-router-dom', 'tdweb', 'zustand']) {
assert.ok(packageJson.dependencies[dependency], `web/package.json must depend on ${dependency}`);
}

assert.ok(packageJson.devDependencies.tailwindcss, 'web/package.json must configure TailwindCSS');

const envExample = await readFile(pathFor('web/.env.example'), 'utf8');
assert.match(envExample, /VITE_TELEGRAM_API_ID=/);
assert.match(envExample, /VITE_TELEGRAM_API_HASH=/);
assert.match(envExample, /VITE_TELETON_AGENT_WS_URL=ws:\/\/localhost:8765/);
assert.match(envExample, /VITE_TELETON_AGENT_MANAGEMENT_URL=https:\/\/localhost:7778/);

const tdlibService = await readFile(pathFor('web/src/services/tdlib.service.ts'), 'utf8');
assert.match(tdlibService, /authPhone/);
assert.match(tdlibService, /requestQrCodeAuthentication/);
assert.match(tdlibService, /authCode/);
assert.match(tdlibService, /getChats/);
assert.match(tdlibService, /sendMessage/);
assert.match(tdlibService, /setProxy/);
assert.match(tdlibService, /tdweb/);
assert.match(tdlibService, /loadTdClientConstructor/);

const agentService = await readFile(pathFor('web/src/services/agent.service.ts'), 'utf8');
assert.match(agentService, /jsonrpc: '2\.0'/);
assert.match(agentService, /agent\.enable/);
assert.match(agentService, /agent\.disable/);
assert.match(agentService, /ton\.getBalance/);
assert.match(agentService, /ton\.sendTx/);
assert.match(agentService, /\/v1\/agent\/status/);

const cryptoService = await readFile(pathFor('web/src/services/crypto.service.ts'), 'utf8');
assert.match(cryptoService, /AES-GCM/);
assert.match(cryptoService, /indexedDB/);
assert.match(cryptoService, /persistEncryptedSession/);
assert.match(cryptoService, /consent !== true/);

const store = await readFile(pathFor('web/src/shared/store/useTeletonStore.ts'), 'utf8');
assert.doesNotMatch(store, /localStorage\.setItem\([^)]*session/i, 'Telegram sessions must not be persisted to localStorage');
assert.match(store, /authorizationStateWaitOtherDeviceConfirmation/);
assert.match(store, /qrLoginLink/);

const authScreen = await readFile(pathFor('web/src/features/auth/AuthScreen.tsx'), 'utf8');
assert.match(authScreen, /QRCode\.toDataURL/);
assert.match(authScreen, /requestQrLogin/);

const webReadme = await readFile(pathFor('web/README.md'), 'utf8');
assert.match(webReadme, /npm install/);
assert.match(webReadme, /npm run build/);
assert.match(webReadme, /teleton-agent/i);
assert.match(webReadme, /encrypted/i);

const authDocs = await readFile(pathFor('docs/AUTH.md'), 'utf8');
assert.match(authDocs, /QR/i);
assert.match(authDocs, /requestQrCodeAuthentication/);
assert.match(authDocs, /authorizationStateWaitOtherDeviceConfirmation/);
});
6 changes: 6 additions & 0 deletions web/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
VITE_TELEGRAM_API_ID=
VITE_TELEGRAM_API_HASH=
VITE_TDLIB_LOG_VERBOSITY=2
VITE_TELETON_AGENT_WS_URL=ws://localhost:8765
VITE_TELETON_AGENT_MANAGEMENT_URL=https://localhost:7778
VITE_TONCONNECT_MANIFEST_URL=/tonconnect-manifest.json
69 changes: 69 additions & 0 deletions web/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# Teleton Client Web Alpha

This directory contains the React 18 + Vite web client for issue `#135`.

## Start

```sh
npm install
cp .env.example .env
npm run dev
```

Open `http://localhost:5173/app/`.

## Required Environment

Set Telegram API credentials before using live TDLib authentication:

```sh
VITE_TELEGRAM_API_ID=123456
VITE_TELEGRAM_API_HASH=your_hash
```

The sign-in screen supports both phone/code authorization and Telegram QR login. QR login calls TDLib `requestQrCodeAuthentication` and renders the `authorizationStateWaitOtherDeviceConfirmation.link` payload locally; no QR token is stored in `localStorage`.

The default Teleton Agent endpoints are:

```sh
VITE_TELETON_AGENT_WS_URL=ws://localhost:8765
VITE_TELETON_AGENT_MANAGEMENT_URL=https://localhost:7778
```

The WebSocket endpoint implements the issue contract with JSON-RPC 2.0 methods:

- `agent.enable({ session, userId })`
- `agent.disable()`
- `ton.getBalance({ address })`
- `ton.sendTx({ to, amount, comment })`

The Management API status button calls the current `teleton-agent` HTTPS API at `/v1/agent/status` with an optional `tltn_` Bearer key.

## TDWeb Assets

`npm install` runs `scripts/copy-tdweb-assets.mjs`, copying `node_modules/tdweb/dist/*` into `web/public/`.
Those generated WASM, worker, and memory files are intentionally not committed because they are large upstream runtime artifacts.

## Storage

Telegram session data is runtime-only by default. The sign-in screen can persist an encrypted session marker only after explicit user consent.

Proxy and agent settings are saved as AES-256-GCM envelopes in `localStorage`; the non-extractable browser key is stored in IndexedDB. Raw Telegram API hashes, proxy secrets, and agent API keys must stay out of source control.

## Checks

```sh
npm run test
npm run build
npm run preview
```

`npm audit --omit=dev` currently reports a moderate `tdweb -> uuid` advisory with no upstream fix available in `tdweb@1.8.0`. Keep that dependency under release review before publishing the alpha.

## Deploy

```sh
./deploy.sh
```

The script builds the app and uses `vercel` or `wrangler` when either CLI is installed.
13 changes: 13 additions & 0 deletions web/deploy.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env sh
set -eu

npm install
npm run build

if command -v vercel >/dev/null 2>&1; then
vercel deploy --prod dist
elif command -v wrangler >/dev/null 2>&1; then
wrangler pages deploy dist --project-name teleton-client-web
else
printf '%s\n' "Build is ready in web/dist. Install vercel or wrangler to deploy from this script."
fi
15 changes: 15 additions & 0 deletions web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="theme-color" content="#1f7a8c" />
<link rel="manifest" href="/manifest.webmanifest" />
<link rel="icon" type="image/png" sizes="192x192" href="/icons/icon-192.png" />
<title>Teleton Client</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
Loading
Loading