dsh-relay-phone 0.11.2 → 0.11.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-relay-phone",
3
- "version": "0.11.2",
3
+ "version": "0.11.3",
4
4
  "description": "Remote-control your local DeepSeek Harness from a phone through your own zero-knowledge relay: phone-first page, QR pairing, end-to-end encryption, approvals, full desktop UI fallback.",
5
5
  "type": "module",
6
6
  "main": "src/index.js",
package/src/index.js CHANGED
@@ -165,6 +165,23 @@ export default class RelayBridgeService extends Service {
165
165
  }
166
166
  }
167
167
 
168
+ /**
169
+ * The root token DSH 0.2 wants on the index exchange. A browser that opens the
170
+ * desktop UI locally already has it in its URL; one arriving through the relay
171
+ * does not, which is why that shell used to come back unauthenticated.
172
+ */
173
+ upstreamIndexToken() {
174
+ const connection = this.ctx.get('connection')
175
+ if (!connection || typeof connection.authenticatedUrl !== 'function') return null
176
+ try {
177
+ const target = this.upstreamTarget()
178
+ const url = new URL(connection.authenticatedUrl(`${target.protocol}//${target.authority}/`))
179
+ return url.searchParams.get('token')
180
+ } catch {
181
+ return null
182
+ }
183
+ }
184
+
168
185
  mergeConfig(base, stored) {
169
186
  return {
170
187
  relayScheme: stored.relayScheme ?? base.relayScheme ?? 'http',
@@ -219,6 +236,7 @@ export default class RelayBridgeService extends Service {
219
236
  dshPort: this.config.dshPort,
220
237
  resolveTarget: () => this.upstreamTarget(),
221
238
  resolveAuthCookie: () => this.upstreamAuthCookie(),
239
+ resolveIndexToken: () => this.upstreamIndexToken(),
222
240
  pairing: this.pairing,
223
241
  cryptoBox: this.cryptoBox,
224
242
  mobile: this.mobile,
package/src/pump.js CHANGED
@@ -59,6 +59,8 @@ export class PumpManager {
59
59
  protocol: 'http:',
60
60
  }))
61
61
  this.resolveAuthCookie = options.resolveAuthCookie ?? (() => null)
62
+ // Root token for DSH 0.2's index exchange; null on older hosts.
63
+ this.resolveIndexToken = options.resolveIndexToken ?? (() => null)
62
64
  this.pairing = options.pairing // PairingService
63
65
  this.cryptoBox = options.cryptoBox
64
66
  this.client = options.client
@@ -641,7 +643,21 @@ export class PumpManager {
641
643
  // Any inbound copy was dropped in the loop above, so a client cannot forge it.
642
644
  rewritten.push('x-dsh-relay: 1')
643
645
  if (authCookie) rewritten.push(`Cookie: ${authCookie}`)
644
- const out = `${lines[0]}\r\n${rewritten.join('\r\n')}\r\n\r\n`
646
+
647
+ // DSH 0.2 guards the index exchange with a root token, and the pump already
648
+ // uses that token to mint the API cookie. A browser arriving through the
649
+ // relay has no token of its own, so the desktop shell it received came back
650
+ // unauthenticated even though every later API call would have worked.
651
+ let requestLine = lines[0]
652
+ if (stream.relay && isDocument && !isUpgrade && info.path === '/') {
653
+ const token = this.resolveIndexToken()
654
+ if (token) {
655
+ const query = new URLSearchParams(info.query)
656
+ query.set('token', token)
657
+ requestLine = `${info.method} /?${query.toString()} ${info.version}`
658
+ }
659
+ }
660
+ const out = `${requestLine}\r\n${rewritten.join('\r\n')}\r\n\r\n`
645
661
 
646
662
  if (isUpgrade) {
647
663
  const upstream = net.connect({ host: target.host, port: target.port })