tassello 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -66,6 +66,21 @@ change the plugin API (`tassello/sdk`, `tassello/server`, `tassello/vite`), as n
66
66
  `restartTerminal`, the `TerminalOutput` and `TerminalExit` types, and the `ShellIcon`,
67
67
  `KeyboardIcon`, `MaximizeIcon`, `MinimizeIcon`, `ClipboardIcon`, `TextSmallerIcon` and
68
68
  `TextLargerIcon` icons.
69
+ - Networking widget: the robot's networks, through NetworkManager (`nmcli`), as a phone's settings
70
+ show them. The Wi-Fi networks in range, joined with their password (WPA, WPA2 and WPA3 Personal,
71
+ WEP, WPA Enterprise with PEAP), hidden ones by name; the connections saved, connected and
72
+ disconnected, edited (password, interface, IPv4 by DHCP or static with gateway and DNS, shared,
73
+ connecting automatically and with which priority) and forgotten; wired connections with an
74
+ address of their own; the robot as an access point (WPA2, band, channel, its address), started
75
+ now or at boot, and a network shared by its password and a QR code; the interfaces, their state,
76
+ addresses, gateway, DNS, MAC address and speed. The server tells each page which interface it
77
+ reaches the robot through, and the widget asks before a change that would cut it off. The server
78
+ follows NetworkManager for every page (`nmcli monitor`), shows every page what is being done and
79
+ how it ended, and says when its user may not change the networks (a polkit rule, see the
80
+ README). Networks change from the dashboard's own pages only.
81
+ - Plugins: `connection.subscribeNetwork`, `networkAction`, the `Network*`, `WifiNetwork`,
82
+ `WifiSecurity` and `ConnectionKind` types, and the `NetworkIcon`, `WifiIcon`, `WifiOffIcon`,
83
+ `EthernetIcon`, `HotspotIcon` and `ShieldIcon` icons.
69
84
 
70
85
  ## 0.1.0
71
86
 
package/README.md CHANGED
@@ -11,7 +11,8 @@ and plugins add more.
11
11
  - **Every device**: a desktop canvas, and layouts of their own for tablets and phones.
12
12
  - **Built in**: teleop pads, a Nav2 map with goals, the robot's URDF in 3D, an arm jogger, cameras,
13
13
  images, command buttons, a systemd application manager, a behavior tree inspector and
14
- editor, the ROS log of every node, the robot's diagnostics, a file manager and a terminal.
14
+ editor, the ROS log of every node, the robot's diagnostics, a file manager, a terminal, and
15
+ its networks: Wi-Fi joined, connections switched, the robot as an access point.
15
16
  - **Plugins**: widgets of your own, with server-side code if they need it, as npm or ROS packages.
16
17
  - **One process**: a ROS 2 node in Node.js. Nothing to install on the robot but Node.js.
17
18
 
@@ -22,7 +23,8 @@ Tassello runs on the robot (or any machine on its ROS network) and needs:
22
23
  - ROS 2: Humble, Jazzy, Kilted or Lyrical, on x64 or arm64 (e.g. a Raspberry Pi), for which
23
24
  [rclnodejs](https://github.com/RobotWebTools/rclnodejs) ships prebuilt binaries;
24
25
  - Node.js 22 or newer, and npm;
25
- - Python 3, which ROS 2 comes with: the Terminal widget's pseudo-terminals.
26
+ - Python 3, which ROS 2 comes with: the Terminal widget's pseudo-terminals;
27
+ - NetworkManager, which Ubuntu runs, for the Networking widget.
26
28
 
27
29
  ```bash
28
30
  npm install -g tassello
@@ -121,6 +123,7 @@ after the others on the devices already arranged.
121
123
  | **Diagnostics** | The robot's diagnostics (`/diagnostics`, or the aggregator's `/diagnostics_agg`), as rqt_robot_monitor shows them: each status's level, the groups with the worst under them, those with problems unfolded. As a tree, as a list (the worst first) or as the latest changes of level, filtered by level and by text; a widget can be for some statuses only. A status's details: its message, hardware ID, values and latest changes. Pause, download, and forget the statuses no longer published |
122
124
  | **File Manager** | The robot's files: folders unfolded in place, places (home, the ROS workspaces, bookmarks) and the disks' free space, an entry's details and permissions, what takes a folder's space. Make, rename, cut, copy, paste, drag onto folders, delete, download (folders as `.tar.gz`) and upload (drop files and folders onto it). Text files edited in tabs as gedit does: highlighting, search and replace, undo; images and PGM maps shown |
123
125
  | **Terminal** | A shell on the robot, or a command (`htop`, `tmux attach`), in a full terminal: colours, full screen programs, the mouse. It outlives the page: reloaded, reconnected or shown again, it is as it was. On touch screens, the keys phones lack, as Termux has them: Esc, Tab, Ctrl, Alt, Home, End, the arrows, Page Up and Down, and while typing the terminal fills the screen above the on-screen keyboard |
126
+ | **Networking** | The robot's networks, through NetworkManager, as a phone's settings show them: the Wi-Fi networks in range, joined with their password; the connections saved, switched between, edited (their addresses by DHCP or static), forgotten; the robot as an access point, its network shared by a QR code; the interfaces, their state and addresses. Asks before a change that would cut the page off from the robot |
124
127
 
125
128
  Their properties (topics, frames, speeds, colours, ...) are edited in the side panel of edit mode.
126
129
 
@@ -296,6 +299,60 @@ Notes on some of them:
296
299
  types after a colon (`-:|`). While the on-screen keyboard is open, the terminal fills the screen
297
300
  above it, the keys right above the keyboard (*Full screen while typing*). One finger scrolls (the
298
301
  scrollback, or the program: less, htop), flung or not; two pinch the text's size.
302
+ - **Networking** changes the networks through NetworkManager (`nmcli`), which Ubuntu runs (a
303
+ robot whose netplan renders with systemd-networkd shows its interfaces as not managed). Its
304
+ **Wi-Fi** view lists the networks in range of each Wi-Fi interface, the one connected to first,
305
+ then those saved, then by signal. *Join* asks for the password (WPA and WPA2 Personal, WPA3
306
+ Personal, WEP, and WPA Enterprise with PEAP and MSCHAPv2), *Connect* uses the one saved, and
307
+ asks for it again if it is found wrong; *Join a hidden network…* looks for one by name. *New
308
+ access point…* makes the robot a Wi-Fi network of its own: WPA2 with a password made for it,
309
+ 2.4 or 5 GHz, a channel, the robot's address on it (10.42.0.1 if not given), giving addresses to
310
+ who joins (NetworkManager's shared mode, with `dnsmasq-base`). *Start automatically* makes it
311
+ the robot's network from when it starts, wherever it is. *Share…* shows a network's name and
312
+ password, and the QR code phones join it by. The **Saved** view lists the connections saved, by
313
+ kind (Wi-Fi networks, access points, wired, VPN), the active then the latest used first: connect
314
+ and disconnect them, edit them (their name, password, interface, IPv4: DHCP, static with a
315
+ gateway and DNS servers, shared or disabled, whether they connect by themselves and with which
316
+ priority) and forget them; *New wired connection…* gives a cable an address of its own, e.g. on
317
+ a lidar's network. The **Interfaces** view shows each interface's state, addresses, gateway, DNS
318
+ servers, MAC address and speed, and the connections it may connect with. A widget can be for
319
+ some interfaces only (`wlan0, eth*`), or read-only. Those other programs configure (docker's
320
+ bridges, VPN clients' tunnels) are left out, unless *Show every interface*.
321
+
322
+ The server tells each page which interface it reaches the robot through: a change that would
323
+ cut the page off (disconnecting that interface, switching its Wi-Fi to another network, making
324
+ it an access point, turning Wi-Fi off) is asked about first, saying so. What is being done shows
325
+ on every page, and how it ended, also to a page that lost the robot meanwhile: after switching
326
+ networks, the robot is reached on the new one; if it could not join it, NetworkManager connects
327
+ by itself to one of those saved that connect automatically. A Wi-Fi network or an access point
328
+ that fails to start is not kept; a cable's waits for its cable.
329
+
330
+ A desktop's NetworkManager lets the users of its session change the networks, not a service's:
331
+ give the server's user the right with a polkit rule. On Ubuntu 22.04 (polkit 0.105),
332
+ `/etc/polkit-1/localauthority/50-local.d/tassello-networking.pkla`, for the user `robot`:
333
+
334
+ ```ini
335
+ [Let the dashboard change the networks]
336
+ Identity=unix-user:robot
337
+ Action=org.freedesktop.NetworkManager.*
338
+ ResultAny=yes
339
+ ResultInactive=yes
340
+ ResultActive=yes
341
+ ```
342
+
343
+ From Ubuntu 24.04 (and Debian 12), `/etc/polkit-1/rules.d/50-tassello-networking.rules`:
344
+
345
+ ```js
346
+ polkit.addRule(function (action, subject) {
347
+ if (action.id.indexOf('org.freedesktop.NetworkManager.') === 0 && subject.user === 'robot') {
348
+ return polkit.Result.YES;
349
+ }
350
+ });
351
+ ```
352
+
353
+ Without it, the widget says the networks cannot be changed. *Share…* reads the passwords with
354
+ `nmcli --show-secrets`, which needs the same right; those a desktop's keyring keeps cannot be
355
+ read.
299
356
 
300
357
  ## Plugins
301
358
 
@@ -323,14 +380,15 @@ and ship example panels. See **[docs/plugins.md](docs/plugins.md)**.
323
380
  ## Security
324
381
 
325
382
  Tassello has no login. **Anyone who can open the page can drive the robot, run any command as
326
- the server's user (the Terminal, a shell), and read, write, upload, move and delete any of the
327
- files that user can (the File Manager)**: keep it on a network you trust, or behind a reverse proxy
383
+ the server's user (the Terminal, a shell), read, write, upload, move and delete any of the
384
+ files that user can (the File Manager), and change the robot's networks and read their passwords
385
+ (Networking)**: keep it on a network you trust, or behind a reverse proxy
328
386
  with authentication (it serves everything under `/`, its WebSocket at `/ws`). Changes to the files
329
387
  are accepted from the dashboard's own pages only (they send a header that another site's page
330
388
  cannot), and the root, the home folder and the system's top folders (`/usr`, `/etc`…) are never
331
- deleted nor moved. Terminals open from the dashboard's own pages only too: those whose origin is
332
- the host they reached (the `Host` header, or the `X-Forwarded-Host` a reverse proxy sets), which
333
- another site's page cannot pretend.
389
+ deleted nor moved. Terminals open, and networks change, from the dashboard's own pages only too:
390
+ those whose origin is the host they reached (the `Host` header, or the `X-Forwarded-Host` a
391
+ reverse proxy sets), which another site's page cannot pretend.
334
392
 
335
393
  ## How it works
336
394
 
@@ -342,6 +400,7 @@ another site's page cannot pretend.
342
400
  ├─ sharp: raw images to JPEG, maps to PNG
343
401
  ├─ bash: the buttons' commands
344
402
  ├─ python3: the terminals' pseudo-terminals
403
+ ├─ nmcli: the networks (NetworkManager)
345
404
  └─ the plugins' server sides
346
405
  ```
347
406
 
@@ -371,6 +430,10 @@ Safety and bandwidth are the server's concern:
371
430
  paces the program, never the pages: a page gets at most 256 KB ahead of what it has drawn, and a
372
431
  page further behind (a slow phone, a hidden tab, a flood of output) gets the screen as it is
373
432
  instead of all that led to it. A page that reconnects gets what it missed, from the last 1 MB.
433
+ - The networks are read once for every page: again as soon as `nmcli monitor` reports a change,
434
+ and every 3 s for the signals of the Wi-Fi networks in range, which are scanned for when a page
435
+ opens the widget (at most every 30 s) or asks. Passwords are on `nmcli`'s command line only for
436
+ the moment it takes to save them, activating a connection being another command.
374
437
  - The File Manager's folders are read again every 3 s, and answered "unchanged" while they are;
375
438
  the largest are listed in part (5,000 entries), and only the rows in sight are drawn. Uploads
376
439
  and downloads are streamed, folders archived by `tar` as they are sent; saves replace files at
@@ -0,0 +1,41 @@
1
+ import { type NetworkRequest, type NetworkResult, type NetworkSecrets, type NetworkState } from '../shared/networking.ts';
2
+ import { type Logger } from './util.ts';
3
+ type NetworkListener = (state: NetworkState) => void;
4
+ export declare class Networking {
5
+ private readonly logger;
6
+ private readonly listeners;
7
+ private latest;
8
+ private latestJson;
9
+ private timer;
10
+ private reading;
11
+ private again;
12
+ private monitor;
13
+ private monitorTimer;
14
+ private debounce;
15
+ private settings;
16
+ private settingsKey;
17
+ private settingsAt;
18
+ private permissions;
19
+ private permissionsAt;
20
+ private activity;
21
+ private nextActivity;
22
+ private scannedAt;
23
+ private scanning;
24
+ private scanTimer;
25
+ constructor(logger: Logger);
26
+ watch(listener: NetworkListener): () => void;
27
+ act(request: NetworkRequest): Promise<NetworkResult | NetworkSecrets>;
28
+ stopAll(): void;
29
+ private connection;
30
+ private track;
31
+ private rescan;
32
+ private setScanning;
33
+ private secrets;
34
+ private publish;
35
+ private emit;
36
+ private refresh;
37
+ private read;
38
+ private startMonitor;
39
+ private stop;
40
+ }
41
+ export {};