@danieltmn/openbridge 0.3.0 → 0.5.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/src/web/server.js CHANGED
@@ -70,6 +70,13 @@ function securityHeaders(res) {
70
70
  res.setHeader('X-Content-Type-Options', 'nosniff');
71
71
  res.setHeader('Referrer-Policy', 'no-referrer');
72
72
  res.setHeader('X-Frame-Options', 'DENY');
73
+ // La app usa scripts/estilos inline (templates) y data: para imagenes
74
+ // adjuntas. Igual bloquea origenes externos, frames y objetos.
75
+ res.setHeader('Content-Security-Policy',
76
+ "default-src 'self'; img-src 'self' data:; style-src 'self' 'unsafe-inline'; "
77
+ + "script-src 'self' 'unsafe-inline'; connect-src 'self'; worker-src 'self'; "
78
+ + "manifest-src 'self'; object-src 'none'; base-uri 'none'; "
79
+ + "frame-ancestors 'none'; form-action 'self'");
73
80
  }
74
81
 
75
82
  async function handle(app, req, res) {
@@ -280,6 +280,11 @@
280
280
  text-align: center;
281
281
  border: 1px solid var(--border);
282
282
  }
283
+ #sidebar .footer .userbadge {
284
+ flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
285
+ color: var(--muted); font-size: 12px;
286
+ }
287
+ #sidebar .footer .userbadge.admin { color: var(--accent); }
283
288
  #scrim {
284
289
  display: none;
285
290
  position: fixed; inset: 0;
@@ -1198,13 +1203,17 @@
1198
1203
  <button data-view="preview" type="button" title="Vista previa del proyecto (túnel)">preview</button>
1199
1204
  <button data-view="procs" type="button" title="Procesos de la sesión">procs</button>
1200
1205
  <button data-view="changes" type="button" title="Cambios del proyecto (git)">cambios</button>
1206
+ <button data-view="mcp" type="button" title="Servidores MCP de opencode">mcp</button>
1201
1207
  </div>
1202
1208
  <div class="footer">
1203
1209
  <div class="row" id="bridgeStatusRow">
1204
1210
  <span class="dot" id="bridgeDot"></span>
1205
1211
  <span id="bridgeStatusText">puente: desconocido</span>
1206
1212
  </div>
1207
- <a class="logout" href="logout.php">salir</a>
1213
+ <div class="row">
1214
+ <span class="userbadge" id="userBadge" title="sesión actual">{{USER_NAME}}</span>
1215
+ <a class="logout" href="logout.php">salir</a>
1216
+ </div>
1208
1217
  </div>
1209
1218
  <div class="resizer" id="sbResizer" title="Arrastrá para ajustar · doble clic para restablecer"></div>
1210
1219
  </aside>
@@ -1277,6 +1286,7 @@
1277
1286
  <div id="viewPreview" class="view" style="display:none"></div>
1278
1287
  <div id="viewProcs" class="view" style="display:none"></div>
1279
1288
  <div id="viewChanges" class="view" style="display:none"></div>
1289
+ <div id="viewMcp" class="view" style="display:none"></div>
1280
1290
 
1281
1291
  <footer id="statusbar">
1282
1292
  <span class="dot" id="sbDot"></span>
@@ -1344,7 +1354,9 @@
1344
1354
  themes: {{THEMES_JSON}},
1345
1355
  sseDisabled: {{SSE_DISABLED}},
1346
1356
  pushEnabled: {{PUSH_ENABLED}},
1347
- pushKey: "{{PUSH_KEY}}"
1357
+ pushKey: "{{PUSH_KEY}}",
1358
+ userName: "{{USER_NAME}}",
1359
+ userRole: "{{USER_ROLE}}"
1348
1360
  };
1349
1361
  </script>
1350
1362
  <script src="app.js?v={{APPJS_VER}}" defer></script>
@@ -89,12 +89,12 @@
89
89
  (function () {
90
90
  var knownThemes = {{THEMES_JSON}};
91
91
  var params = new URLSearchParams(location.search);
92
- var cookie = document.cookie.match(/(?:^|;\s*)ocx_theme=([^;]+)/);
92
+ var cookie = document.cookie.match(/(?:^|;\s*)ob_theme=([^;]+)/) || document.cookie.match(/(?:^|;\s*)ocx_theme=([^;]+)/);
93
93
  var saved = (params.get('theme') || (cookie && decodeURIComponent(cookie[1])) || document.body.getAttribute('data-theme') || 'terminal');
94
94
  if (knownThemes.indexOf(saved) === -1) saved = 'terminal';
95
95
  document.body.setAttribute('data-theme', saved);
96
96
  document.getElementById('themeStylesheet').setAttribute('href', 'themes/' + saved + '.css');
97
- document.cookie = 'ocx_theme=' + encodeURIComponent(saved) + ';path=/;max-age=' + (60 * 60 * 24 * 365) + ';SameSite=Lax';
97
+ document.cookie = 'ob_theme=' + encodeURIComponent(saved) + ';path=/;max-age=' + (60 * 60 * 24 * 365) + ';SameSite=Lax';
98
98
  window.addEventListener('load', function () {
99
99
  var bg = getComputedStyle(document.documentElement).getPropertyValue('--bg').trim();
100
100
  if (bg) document.getElementById('themeColor').setAttribute('content', bg);
@@ -111,7 +111,11 @@
111
111
  <input type="hidden" name="csrf" value="{{CSRF}}">
112
112
  <label class="field">
113
113
  <span class="prompt">❯</span>
114
- <input type="password" id="password" name="password" placeholder="contraseña" required autofocus autocomplete="current-password">
114
+ <input type="text" id="username" name="username" placeholder="usuario" required autofocus autocomplete="username" value="{{USER_PREFILL}}">
115
+ </label>
116
+ <label class="field">
117
+ <span class="prompt">❯</span>
118
+ <input type="password" id="password" name="password" placeholder="contraseña" required autocomplete="current-password">
115
119
  <button type="button" class="peek" id="btnPeek" aria-label="Mostrar u ocultar contraseña" tabindex="-1">👁</button>
116
120
  </label>
117
121
  <label class="keep" for="keep">