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 +15 -0
- package/README.md +70 -7
- package/dist/server/networking.d.ts +41 -0
- package/dist/server/networking.js +508 -0
- package/dist/server/networking_format.d.ts +38 -0
- package/dist/server/networking_format.js +651 -0
- package/dist/server/server.js +5 -1
- package/dist/server/session.d.ts +4 -1
- package/dist/server/session.js +23 -2
- package/dist/shared/networking.d.ts +178 -0
- package/dist/shared/networking.js +248 -0
- package/dist/shared/protocol.d.ts +18 -2
- package/dist/types/client/connection.d.ts +9 -1
- package/dist/types/client/icons.d.ts +6 -0
- package/dist/types/client/sdk/index.d.ts +2 -1
- package/dist/types/shared/networking.d.ts +178 -0
- package/dist/types/shared/protocol.d.ts +18 -2
- package/dist/www/assets/Joystick.js +1 -1
- package/dist/www/assets/RobotModelView.js +2 -2
- package/dist/www/assets/TerminalView.js +2 -2
- package/dist/www/assets/icons.js +1 -1
- package/dist/www/assets/index.css +1 -1
- package/dist/www/assets/index.js +42 -42
- package/dist/www/assets/shared/tassello-sdk.js +1 -1
- package/docs/plugins.md +2 -0
- package/package.json +1 -1
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
|
|
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),
|
|
327
|
-
files that user can (the File Manager)
|
|
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:
|
|
332
|
-
the host they reached (the `Host` header, or the `X-Forwarded-Host` a
|
|
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 {};
|