@danieltmn/openbridge 0.2.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 +30 -0
- package/README.md +221 -144
- package/docs/ARCHITECTURE.md +49 -8
- package/package.json +1 -1
- package/src/auth.js +44 -23
- package/src/bridge/bridge.js +77 -1
- package/src/cli.js +155 -9
- package/src/config.js +74 -4
- package/src/web/assets/app.js +286 -43
- package/src/web/assets/manifest.webmanifest +2 -0
- package/src/web/assets/sw.js +1 -1
- package/src/web/routes.js +49 -13
- package/src/web/server.js +7 -0
- package/src/web/templates/chat.html +54 -2
- package/src/web/templates/login.html +5 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,36 @@ Todos los cambios relevantes de OpenBridge. Formato basado en
|
|
|
4
4
|
[Keep a Changelog](https://keepachangelog.com/es-ES/1.1.0/) y
|
|
5
5
|
[Versionado Semantico](https://semver.org/lang/es/).
|
|
6
6
|
|
|
7
|
+
## [0.4.0] - 2026-09-14
|
|
8
|
+
|
|
9
|
+
### Agregado
|
|
10
|
+
|
|
11
|
+
- **Multiusuario** con roles `admin`/`user`: login con usuario + contrasena,
|
|
12
|
+
sesion ligada al usuario y a la version de contrasena, rate limit por
|
|
13
|
+
IP+usuario, y comando CLI `users`
|
|
14
|
+
(`list`/`add`/`remove`/`passwd`/`role`/`disable`/`enable`); `passwd --user`.
|
|
15
|
+
- Gate server-side: `session_delete` y los comandos mutantes del puente
|
|
16
|
+
(procesos, tuneles, revertir) solo para `admin`; la web oculta esos controles.
|
|
17
|
+
- **Autor** en cada mensaje (auditoria) y muestra del usuario en el sidebar.
|
|
18
|
+
- **Content-Security-Policy** y `Secure` de cookie solo desde loopback
|
|
19
|
+
(`trust proxy` explicito).
|
|
20
|
+
|
|
21
|
+
### Cambiado
|
|
22
|
+
|
|
23
|
+
- La sesion se invalida al cambiar la contrasena (`pv`); los usuarios
|
|
24
|
+
deshabilitados no pueden entrar.
|
|
25
|
+
- `app.json` migra el `username`/`password` legado a `users[]`.
|
|
26
|
+
|
|
27
|
+
## [0.3.0] - 2026-09-13
|
|
28
|
+
|
|
29
|
+
### Cambios
|
|
30
|
+
|
|
31
|
+
- web: revertir un archivo puntual desde la vista cambios
|
|
32
|
+
- cli: comando tunnel (estado/cambio de proveedor y dominio fijo)
|
|
33
|
+
- web: plantillas de prompts y boton de revertir cambios
|
|
34
|
+
- web: vista de cambios del proyecto (git status/diff) via el puente
|
|
35
|
+
- release: recupera flags que npm se queda (--yes, --tag, --dry-run, --preid)
|
|
36
|
+
|
|
7
37
|
## [0.2.0] - 2026-09-13
|
|
8
38
|
|
|
9
39
|
### Cambios
|
package/README.md
CHANGED
|
@@ -1,144 +1,221 @@
|
|
|
1
|
-
# OpenBridge
|
|
2
|
-
|
|
3
|
-
[](https://www.npmjs.com/package/@danieltmn/openbridge)
|
|
4
|
-
[](https://github.com/tamnora/openbridge/actions/workflows/ci.yml)
|
|
5
|
-
[](LICENSE)
|
|
6
|
-
|
|
7
|
-
Tu **opencode** en el celular, **sin hosting**: corre la app, el puente y un
|
|
8
|
-
túnel público desde tu PC. El celular entra por la URL del túnel y vos manejás
|
|
9
|
-
opencode (tus carpetas, modelos y chats) desde donde estés.
|
|
10
|
-
|
|
11
|
-
> Proyecto nuevo e independiente, portado a **Node** desde OpenConex (PHP).
|
|
12
|
-
> Ya no hace falta subir nada a un hosting ni depender de uno.
|
|
13
|
-
|
|
14
|
-
## Cómo funciona
|
|
15
|
-
|
|
16
|
-
```
|
|
17
|
-
[Celular] ──► URL del túnel ──► App Node en tu PC ──► .openbridge/data/ (JSON)
|
|
18
|
-
│
|
|
19
|
-
└──► bridge (Node) ──► opencode run
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
- **Un solo runtime: Node 18+.** La app web, la API, los datos y el puente viven
|
|
23
|
-
en el mismo proceso/hogar.
|
|
24
|
-
- **opencode** es el único requisito externo (el motor que responde).
|
|
25
|
-
- **Túnel** con TunnelMole (gratis, sin cuenta), ngrok o Cloudflare para exponer
|
|
26
|
-
la app a internet.
|
|
27
|
-
|
|
28
|
-
## Requisitos
|
|
29
|
-
|
|
30
|
-
- [Node.js](https://nodejs.org) 18 o superior.
|
|
31
|
-
- `opencode` instalado y autenticado: `npm i -g opencode-ai`.
|
|
32
|
-
|
|
33
|
-
## Instalación
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
# opción 1: sin instalar nada (npx)
|
|
37
|
-
npx @danieltmn/openbridge init # asistente: workspace, contraseña, túnel, puerto
|
|
38
|
-
npx @danieltmn/openbridge server # arranca en segundo plano y muestra el estado/URL
|
|
39
|
-
|
|
40
|
-
# opción 2: instalar global
|
|
41
|
-
npm i -g @danieltmn/openbridge
|
|
42
|
-
openbridge init
|
|
43
|
-
openbridge server
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
Al arrancar (queda en segundo plano) imprime el **estado con la URL pública**
|
|
47
|
-
(`https://….tunnelmole.net/chat.php`): abríla desde el celular y logueate con
|
|
48
|
-
usuario
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### Opciones de `init`
|
|
52
|
-
|
|
53
|
-
```
|
|
54
|
-
--workspace <ruta> carpeta de trabajo (donde están tus proyectos)
|
|
55
|
-
--name "PC 1" nombre visible de esta computadora
|
|
56
|
-
--id pc1 identificador corto (default: derivado del nombre)
|
|
57
|
-
--port 8799 puerto local
|
|
58
|
-
--password <clave> contraseña
|
|
59
|
-
--
|
|
60
|
-
--
|
|
61
|
-
--
|
|
62
|
-
--
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
1
|
+
# OpenBridge
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@danieltmn/openbridge)
|
|
4
|
+
[](https://github.com/tamnora/openbridge/actions/workflows/ci.yml)
|
|
5
|
+
[](LICENSE)
|
|
6
|
+
|
|
7
|
+
Tu **opencode** en el celular, **sin hosting**: corre la app, el puente y un
|
|
8
|
+
túnel público desde tu PC. El celular entra por la URL del túnel y vos manejás
|
|
9
|
+
opencode (tus carpetas, modelos y chats) desde donde estés.
|
|
10
|
+
|
|
11
|
+
> Proyecto nuevo e independiente, portado a **Node** desde OpenConex (PHP).
|
|
12
|
+
> Ya no hace falta subir nada a un hosting ni depender de uno.
|
|
13
|
+
|
|
14
|
+
## Cómo funciona
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
[Celular] ──► URL del túnel ──► App Node en tu PC ──► .openbridge/data/ (JSON)
|
|
18
|
+
│
|
|
19
|
+
└──► bridge (Node) ──► opencode run
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- **Un solo runtime: Node 18+.** La app web, la API, los datos y el puente viven
|
|
23
|
+
en el mismo proceso/hogar.
|
|
24
|
+
- **opencode** es el único requisito externo (el motor que responde).
|
|
25
|
+
- **Túnel** con TunnelMole (gratis, sin cuenta), ngrok o Cloudflare para exponer
|
|
26
|
+
la app a internet.
|
|
27
|
+
|
|
28
|
+
## Requisitos
|
|
29
|
+
|
|
30
|
+
- [Node.js](https://nodejs.org) 18 o superior.
|
|
31
|
+
- `opencode` instalado y autenticado: `npm i -g opencode-ai`.
|
|
32
|
+
|
|
33
|
+
## Instalación
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# opción 1: sin instalar nada (npx)
|
|
37
|
+
npx @danieltmn/openbridge init # asistente: workspace, contraseña, túnel, puerto
|
|
38
|
+
npx @danieltmn/openbridge server # arranca en segundo plano y muestra el estado/URL
|
|
39
|
+
|
|
40
|
+
# opción 2: instalar global
|
|
41
|
+
npm i -g @danieltmn/openbridge
|
|
42
|
+
openbridge init
|
|
43
|
+
openbridge server
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
Al arrancar (queda en segundo plano) imprime el **estado con la URL pública**
|
|
47
|
+
(`https://….tunnelmole.net/chat.php`): abríla desde el celular y logueate con tu
|
|
48
|
+
usuario y contraseña. Para correrlo en primer plano usá
|
|
49
|
+
`openbridge server --stream`; para detenerlo, `openbridge stop`.
|
|
50
|
+
|
|
51
|
+
### Opciones de `init`
|
|
52
|
+
|
|
53
|
+
```
|
|
54
|
+
--workspace <ruta> carpeta de trabajo (donde están tus proyectos)
|
|
55
|
+
--name "PC 1" nombre visible de esta computadora
|
|
56
|
+
--id pc1 identificador corto (default: derivado del nombre)
|
|
57
|
+
--port 8799 puerto local
|
|
58
|
+
--password <clave> contraseña del admin inicial
|
|
59
|
+
--user <nombre> nombre del admin inicial (default: admin)
|
|
60
|
+
--tunnel <prov> tunnelmole | ngrok | cloudflare | none
|
|
61
|
+
--domain <host> dominio fijo del túnel (ngrok)
|
|
62
|
+
--yes sin preguntas (usa defaults)
|
|
63
|
+
--force reconfigura aunque ya exista
|
|
64
|
+
--dir <ruta> casa portable (default: directorio actual)
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Actualizar
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
npm i -g @danieltmn/openbridge@latest # o: npx @danieltmn/openbridge@latest …
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
La configuración y los datos en `.openbridge/` se **migran solos**: el layout
|
|
74
|
+
viejo (archivos sueltos) pasa a `.openbridge/`, y el `username`/`password` de una
|
|
75
|
+
instalación de un solo usuario se convierte en el **primer admin** de `users[]`
|
|
76
|
+
(con la misma contraseña). Por el cambio de formato de sesión, **hay que volver a
|
|
77
|
+
iniciar sesión** una vez; los chats, carpetas, túnel y push se conservan.
|
|
78
|
+
|
|
79
|
+
## Comandos
|
|
80
|
+
|
|
81
|
+
| Comando | Qué hace |
|
|
82
|
+
|---|---|
|
|
83
|
+
| `openbridge init` | Configura la casa (workspace, contraseña, túnel, puerto) |
|
|
84
|
+
| `openbridge passwd` | Cambia la contraseña de acceso (`--user <nombre>`; detiene el server si corre) |
|
|
85
|
+
| `openbridge users` | Usuarios y roles: `list`, `add`, `remove`, `passwd`, `role`, `disable`, `enable` |
|
|
86
|
+
| `openbridge server` | Arranca app + puente + túnel en **segundo plano** y muestra el estado (`--stream` = primer plano) |
|
|
87
|
+
| `openbridge stop` | Detiene el server y su árbol de procesos |
|
|
88
|
+
| `openbridge status` | Estado, URL, puente en línea y chats |
|
|
89
|
+
| `openbridge qr` | Muestra la URL (pública o local) como QR para escanear desde el celular |
|
|
90
|
+
| `openbridge tunnel` | Muestra o cambia el proveedor de túnel y su dominio fijo (`--domain`) |
|
|
91
|
+
| `openbridge logs` | Logs (`--follow`, `--server`, `--bridge`) |
|
|
92
|
+
| `openbridge bridge` | Corre **solo** el puente (`--api --token --id --name`) |
|
|
93
|
+
| `openbridge import` | Trae `data/` de OpenConex (`<data-dir> [--force]`) |
|
|
94
|
+
| `openbridge reset` | Borra chats/datos (`--session <id>`, `--yes`) |
|
|
95
|
+
| `openbridge autostart` | Arranque automático (`install`/`remove`) |
|
|
96
|
+
| `openbridge doctor` | Verifica Node, opencode, configuración y puerto |
|
|
97
|
+
|
|
98
|
+
## Casa portable
|
|
99
|
+
|
|
100
|
+
Todo vive dentro de **`.openbridge/`** en el directorio donde corrés `init`
|
|
101
|
+
(o `--dir` / `OPENBRIDGE_HOME`):
|
|
102
|
+
|
|
103
|
+
```
|
|
104
|
+
.openbridge/
|
|
105
|
+
config.json config del puente (apiUrl, token, workspace, bridgeId…)
|
|
106
|
+
app.json config de la app (usuarios, token, VAPID, puerto, túnel)
|
|
107
|
+
folders.json lista blanca de carpetas que se ven desde el celular
|
|
108
|
+
data/ sesiones, mensajes, catálogo, registro de puentes, push
|
|
109
|
+
logs/ server.log y bridge.log
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Movés la carpeta a donde quieras y sigue funcionando (es portable). Si venías
|
|
113
|
+
de una versión anterior con los archivos sueltos, se **migran solos** a
|
|
114
|
+
`.openbridge/` la primera vez que corras un comando.
|
|
115
|
+
|
|
116
|
+
## Varias computadoras (hub + remotas)
|
|
117
|
+
|
|
118
|
+
La PC **hub** corre la app y el túnel; las demás PCs corren solo el **puente** y
|
|
119
|
+
apuntan al hub. En el sidebar de la web elegís qué PC usar y ves sus proyectos y
|
|
120
|
+
chats.
|
|
121
|
+
|
|
122
|
+
Ejemplo concreto:
|
|
123
|
+
|
|
124
|
+
1. En el **hub** (tiene la app y la URL pública):
|
|
125
|
+
```bash
|
|
126
|
+
openbridge init
|
|
127
|
+
openbridge server # muestra estado, URL y QR
|
|
128
|
+
openbridge status # volvés a ver la URL cuando quieras
|
|
129
|
+
```
|
|
130
|
+
2. Copiá el **token del puente** del hub: `.openbridge/app.json` → `bridgeToken`.
|
|
131
|
+
3. En la **PC 2** (remota):
|
|
132
|
+
```bash
|
|
133
|
+
openbridge init --tunnel none # no necesita túnel propio
|
|
134
|
+
openbridge bridge --api https://tu-url-publica/api.php \
|
|
135
|
+
--token <bridgeToken> --id pc2 --name "PC 2"
|
|
136
|
+
```
|
|
137
|
+
4. Abrí la URL del hub desde el celular: en el sidebar aparecen **PC 1** y
|
|
138
|
+
**PC 2** para alternar.
|
|
139
|
+
|
|
140
|
+
El puente remoto solo necesita salida a internet hacia el hub; no abre puertos ni
|
|
141
|
+
túnel propio. Para que arranque solo en cada PC: `openbridge autostart install`.
|
|
142
|
+
|
|
143
|
+
## Túnel y URL estable
|
|
144
|
+
|
|
145
|
+
Proveedores (`--tunnel` o `openbridge tunnel <prov>`): `tunnelmole` (gratis, sin
|
|
146
|
+
cuenta), `ngrok` (cuenta + authtoken; admite **dominio fijo**) y `cloudflare`
|
|
147
|
+
(quick tunnel). Ver/cambiar sin reconfigurar todo:
|
|
148
|
+
|
|
149
|
+
```bash
|
|
150
|
+
openbridge tunnel # estado actual
|
|
151
|
+
openbridge tunnel ngrok --domain mi-pc.ngrok.app # URL fija (recomendado)
|
|
152
|
+
openbridge stop && openbridge server # reiniciar para aplicar
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Con URL **aleatoria** la PWA y el push no persisten entre reinicios (están atados
|
|
156
|
+
al origen). Para una URL estable usá ngrok con dominio fijo (o un named tunnel de
|
|
157
|
+
Cloudflare). Escaneá el QR de `openbridge status`/`openbridge qr` para abrirla en
|
|
158
|
+
el celular.
|
|
159
|
+
|
|
160
|
+
## Avisos push
|
|
161
|
+
|
|
162
|
+
Las claves VAPID se generan solas en `init`. Con URL de túnel aleatoria la
|
|
163
|
+
suscripción no persiste entre reinicios (el push está atado al origen); la app la
|
|
164
|
+
vuelve a registrar cuando la abrís en la URL nueva. Para que sea estable, usá una
|
|
165
|
+
URL fija (ngrok con `--domain`).
|
|
166
|
+
|
|
167
|
+
## Seguridad
|
|
168
|
+
|
|
169
|
+
- La app escucha **solo en `127.0.0.1`**; el túnel la expone a internet.
|
|
170
|
+
- Login con **usuario y contraseña** (scrypt), cookie firmada `HttpOnly` +
|
|
171
|
+
`SameSite=Lax`, **CSRF** y **rate limit** (5 intentos / 15 min por IP+usuario);
|
|
172
|
+
token del puente autogenerado.
|
|
173
|
+
- La cookie usa `Secure` cuando el pedido llega por HTTPS **desde loopback** (el
|
|
174
|
+
túnel); no se confía en `X-Forwarded-Proto` de otros orígenes.
|
|
175
|
+
- Respuestas con `Content-Security-Policy` (orígenes externos, frames y objetos
|
|
176
|
+
bloqueados), `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY` y
|
|
177
|
+
`Referrer-Policy: no-referrer`.
|
|
178
|
+
- El túnel es **público mientras corre**: detenelo (`openbridge stop`) cuando no
|
|
179
|
+
lo uses y mantené la contraseña fuerte.
|
|
180
|
+
|
|
181
|
+
## Usuarios y roles
|
|
182
|
+
|
|
183
|
+
Cada persona entra con **usuario y contraseña**. Hay dos roles:
|
|
184
|
+
|
|
185
|
+
- **admin**: todo (crear/borrar chats, revertir cambios, procesos, túneles y
|
|
186
|
+
administrar usuarios).
|
|
187
|
+
- **user**: chat, archivos, cambios y búsqueda; no puede borrar chats, revertir
|
|
188
|
+
cambios ni correr procesos/túneles.
|
|
189
|
+
|
|
190
|
+
Se administran desde la PC con la CLI (los cambios requieren reiniciar el server):
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
openbridge users list
|
|
194
|
+
openbridge users add ana --role user --password <clave>
|
|
195
|
+
openbridge users passwd ana
|
|
196
|
+
openbridge users role ana admin
|
|
197
|
+
openbridge users disable ana # enable para reactivar
|
|
198
|
+
openbridge users remove ana
|
|
199
|
+
openbridge passwd --user admin # cambia la clave de un usuario
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
`init --user <nombre>` crea el admin inicial. La contraseña se guarda con scrypt,
|
|
203
|
+
y cambiar una clave **invalida las sesiones abiertas** de ese usuario. El último
|
|
204
|
+
admin no se puede borrar, degradar ni deshabilitar. Cada mensaje guarda **quién
|
|
205
|
+
lo envió** (se ve en el chat).
|
|
206
|
+
|
|
207
|
+
## Estado
|
|
208
|
+
|
|
209
|
+
Proyecto en desarrollo. Ya funciona: `init`, `server` (segundo plano; `--stream`
|
|
210
|
+
en primer plano), `stop`, `status`, `qr`, `tunnel`, `logs` (`--follow`), `bridge`
|
|
211
|
+
(con flags), `passwd`, `users`, `import`, `reset`, `autostart`, `doctor`; login
|
|
212
|
+
**multiusuario** con roles `admin`/`user` y rate limit; API completa y SSE;
|
|
213
|
+
catálogo por PC; Web Push; túnel (TunnelMole/ngrok/cloudflare); y en la web: chat
|
|
214
|
+
con streaming, adjuntar imagen, dictado por voz, plantillas de prompts,
|
|
215
|
+
tokens/contexto y **costo** por sesión, vista de archivos, vista de **cambios**
|
|
216
|
+
(git status/diff) con **revertir**, búsqueda global, sesiones de opencode y
|
|
217
|
+
**autor** en cada mensaje. Tests en `npm test` (28).
|
|
218
|
+
|
|
219
|
+
## Licencia
|
|
220
|
+
|
|
221
|
+
MIT.
|
package/docs/ARCHITECTURE.md
CHANGED
|
@@ -19,18 +19,20 @@ el estado); `--stream` lo deja en primer plano.
|
|
|
19
19
|
| Ruta | Responsabilidad |
|
|
20
20
|
|---|---|
|
|
21
21
|
| `bin/openbridge.js` | Entrada CLI + guard de Node. |
|
|
22
|
-
| `src/cli.js` | Comandos (`init`, `passwd`, `server`, `stop`, `status`, `logs`, `bridge`, `import`, `reset`, `autostart`, `doctor`). |
|
|
22
|
+
| `src/cli.js` | Comandos (`init`, `passwd`, `users`, `server`, `stop`, `status`, `qr`, `tunnel`, `logs`, `bridge`, `import`, `reset`, `autostart`, `doctor`). |
|
|
23
23
|
| `src/paths.js` | Casa portable: ubicacion de `config.json`, `app.json`, `data/`, `logs/`. |
|
|
24
|
-
| `src/config.js` | Lectura/escritura de config, hash scrypt, VAPID. |
|
|
25
|
-
| `src/auth.js` | Cookie de sesion firmada, CSRF, remember-me, rate limit, token del puente. |
|
|
24
|
+
| `src/config.js` | Lectura/escritura de config, hash scrypt, **usuarios/roles**, VAPID. |
|
|
25
|
+
| `src/auth.js` | Cookie de sesion firmada, CSRF, remember-me, **roles**, rate limit, token del puente. |
|
|
26
26
|
| `src/log.js` | Log a consola + `logs/server.log`. |
|
|
27
27
|
| `src/push.js` | Web Push (VAPID + `web-push`). |
|
|
28
|
+
| `src/qr.js` | Generador QR propio (terminal/SVG), sin dependencias. |
|
|
28
29
|
| `src/tunnel/` | Proveedores de tunel enchufables. |
|
|
29
|
-
| `src/web/server.js` | Servidor HTTP, estaticos, seguridad. |
|
|
30
|
-
| `src/web/routes.js` | Router de paginas y API (`?action=...`), compatible con `app.js`/`bridge.js`. |
|
|
30
|
+
| `src/web/server.js` | Servidor HTTP, estaticos, cabeceras de seguridad (CSP). |
|
|
31
|
+
| `src/web/routes.js` | Router de paginas y API (`?action=...`), gate de roles, compatible con `app.js`/`bridge.js`. |
|
|
31
32
|
| `src/web/assets/` | Frontend (`app.js`, temas, iconos, service worker, manifest). |
|
|
32
33
|
| `src/store/` | Store JSON con mutex por archivo y escritura atomica. |
|
|
33
|
-
| `src/bridge/bridge.js` | Puente: sincroniza catalogo, hace poll y ejecuta opencode. |
|
|
34
|
+
| `src/bridge/bridge.js` | Puente: sincroniza catalogo, hace poll y ejecuta opencode; comandos fs/proc/tunel/git. |
|
|
35
|
+
| `scripts/release.mjs` | Release local (fuera del paquete npm): version, changelog, tag, push y publish. |
|
|
34
36
|
|
|
35
37
|
## Casa portable
|
|
36
38
|
|
|
@@ -53,7 +55,8 @@ OpenBridge. La CLI pasa la **base** (`--dir`/cwd) al puente via
|
|
|
53
55
|
|
|
54
56
|
## Flujo de un mensaje
|
|
55
57
|
|
|
56
|
-
1. El celular envia `?action=send` (con CSRF) -> `src/web/routes.js
|
|
58
|
+
1. El celular envia `?action=send` (con CSRF) -> `src/web/routes.js`; el mensaje
|
|
59
|
+
se guarda con el **autor** de la sesion.
|
|
57
60
|
2. El mensaje queda `pending` en `data/messages-<id>.json`.
|
|
58
61
|
3. El puente hace `poll`, reclama el mensaje y corre
|
|
59
62
|
`opencode run --model <m> [--session <id>]`.
|
|
@@ -66,12 +69,50 @@ El hub corre la app; cada PC corre `openbridge bridge` apuntando al hub
|
|
|
66
69
|
(`apiUrl` + `apiToken` + `bridgeId`). El catalogo se guarda por PC
|
|
67
70
|
(`data/catalog-<id>.json`) y el sidebar permite elegir que PC usar.
|
|
68
71
|
|
|
72
|
+
## Usuarios y roles
|
|
73
|
+
|
|
74
|
+
`app.json` guarda `users[]` (`id`, `name`, `role`, `password` scrypt, `pv`,
|
|
75
|
+
`disabled`). El modelo viejo de un `username`/`password` se migra solo a
|
|
76
|
+
`users[0]` (admin).
|
|
77
|
+
|
|
78
|
+
- La sesion (cookie firmada) guarda el `id` del usuario y su `pv`; el **rol se lee
|
|
79
|
+
siempre del server** en cada request. Cambiar la contrasena sube `pv` e invalida
|
|
80
|
+
las sesiones abiertas; un usuario `disabled` no entra.
|
|
81
|
+
- Roles: `admin` (todo) y `user` (chat/lectura). El gate es **server-side** en
|
|
82
|
+
`routes.js`; la UI solo oculta los controles.
|
|
83
|
+
- Rate limit de login por IP+usuario y error generico (no filtra si el usuario
|
|
84
|
+
existe; corre scrypt igual contra un hash dummy).
|
|
85
|
+
- Cada mensaje guarda `author` (quien lo envio); la respuesta hereda el autor del
|
|
86
|
+
pedido.
|
|
87
|
+
|
|
88
|
+
## Comandos del puente
|
|
89
|
+
|
|
90
|
+
La web encola comandos (`?action=run_oc`) que el puente reclama por el poll y
|
|
91
|
+
resuelve (los resultados vuelven por `command_done`/`fs_result`). Sirve tanto en
|
|
92
|
+
local como en remoto:
|
|
93
|
+
|
|
94
|
+
- Lectura: `models`, `session_list`, `session_info`, `opencode_version`,
|
|
95
|
+
`fs_list`, `fs_read`, `proc_list`, `proc_log`, `tunnel_list`, `git_status`,
|
|
96
|
+
`git_diff`.
|
|
97
|
+
- Mutantes (solo `admin`): `proc_start`, `proc_stop`, `tunnel_start`,
|
|
98
|
+
`tunnel_stop`, `git_checkout`.
|
|
99
|
+
|
|
100
|
+
Las rutas se validan contra el workspace (`procResolveFolder`/`resolveInWorkspace`)
|
|
101
|
+
y los argumentos con una whitelist (`OC_ALLOWED`).
|
|
102
|
+
|
|
69
103
|
## Decisiones
|
|
70
104
|
|
|
71
105
|
- **Stateless sessions**: la cookie se firma con HMAC; no hay store de sesiones.
|
|
106
|
+
El `id`+`pv` del usuario van en el payload y el rol se resuelve en cada request.
|
|
107
|
+
- **Multiusuario con roles**: `admin`/`user`, gate server-side; el ultimo admin no
|
|
108
|
+
se puede borrar, degradar ni deshabilitar.
|
|
72
109
|
- **Escritura atomica + mutex**: `tmp` + `rename` y una cola por archivo evitan
|
|
73
110
|
corrupciones con polls concurrentes.
|
|
74
111
|
- **Sin dependencias de framework**: HTTP nativo de Node; la unica dependencia
|
|
75
|
-
es `web-push`.
|
|
112
|
+
es `web-push`. El QR se genera con codigo propio (`src/qr.js`).
|
|
113
|
+
- **Cabeceras de seguridad**: CSP restrictiva; permite scripts/estilos inline
|
|
114
|
+
porque los templates los usan.
|
|
115
|
+
- **Cola de comandos del puente**: un solo canal (poll) para fs, procesos,
|
|
116
|
+
tuneles y git, valido igual en local y remoto.
|
|
76
117
|
- **Proveedores de tunel detras de una interfaz**: `startTunnel(port, provider)`
|
|
77
118
|
devuelve `{ url, provider, pid, stop }`.
|
package/package.json
CHANGED