fied 0.2.7 → 0.2.8

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.
Files changed (2) hide show
  1. package/dist/bin.js +46 -5
  2. package/package.json +2 -4
package/dist/bin.js CHANGED
@@ -274,7 +274,15 @@ async function share(options) {
274
274
  console.log(` Size: ${cols}x${rows}`);
275
275
  console.log("");
276
276
  }
277
- const bridge = new RelayBridge(relayTarget, cryptoKey, keyFragment, pty, options.background, options.sessionId);
277
+ const bridge = new RelayBridge(
278
+ relayTarget,
279
+ cryptoKey,
280
+ keyFragment,
281
+ pty,
282
+ options.background,
283
+ options.showReadonlyLink,
284
+ options.sessionId
285
+ );
278
286
  const onUrl = (url) => {
279
287
  if (options.background) {
280
288
  const sessionId = bridge.getSessionId();
@@ -352,19 +360,27 @@ async function createSession(relayHttpBase) {
352
360
  throw new Error(`Failed to create session: ${res.status} ${res.statusText}`);
353
361
  }
354
362
  const data = await res.json();
355
- return data.sessionId;
363
+ if (typeof data.sessionId !== "string" || typeof data.viewerAccessToken !== "string" || typeof data.readonlyAccessToken !== "string") {
364
+ throw new Error("Invalid session creation response");
365
+ }
366
+ return {
367
+ sessionId: data.sessionId,
368
+ viewerAccessToken: data.viewerAccessToken,
369
+ readonlyAccessToken: data.readonlyAccessToken
370
+ };
356
371
  }
357
372
  var WS_CONNECT_TIMEOUT_MS = 1e4;
358
373
  function typeAAD(type) {
359
374
  return new Uint8Array([type & 255]);
360
375
  }
361
376
  var RelayBridge = class {
362
- constructor(relayTarget, key, keyFragment, pty, silent = false, sessionId) {
377
+ constructor(relayTarget, key, keyFragment, pty, silent = false, showReadonlyLink = false, sessionId) {
363
378
  this.relayTarget = relayTarget;
364
379
  this.key = key;
365
380
  this.keyFragment = keyFragment;
366
381
  this.pty = pty;
367
382
  this.silent = silent;
383
+ this.showReadonlyLink = showReadonlyLink;
368
384
  this.sessionId = sessionId ?? null;
369
385
  this.pty.onData((data) => {
370
386
  if (this.ws?.readyState === WebSocket.OPEN) {
@@ -380,6 +396,8 @@ var RelayBridge = class {
380
396
  encoder = new TextEncoder();
381
397
  decoder = new TextDecoder();
382
398
  sessionId = null;
399
+ viewerAccessToken = null;
400
+ readonlyAccessToken = null;
383
401
  onUrl = null;
384
402
  invalidResizeFrames = 0;
385
403
  invalidInputFrames = 0;
@@ -395,19 +413,29 @@ var RelayBridge = class {
395
413
  }
396
414
  if (!this.sessionId) {
397
415
  try {
398
- this.sessionId = await createSession(this.relayTarget.httpBase);
416
+ const created = await createSession(this.relayTarget.httpBase);
417
+ this.sessionId = created.sessionId;
418
+ this.viewerAccessToken = created.viewerAccessToken;
419
+ this.readonlyAccessToken = created.readonlyAccessToken;
399
420
  } catch {
400
421
  if (!this.silent) console.error(" \x1B[31mRelay unreachable, retrying...\x1B[0m");
401
422
  this.scheduleReconnect();
402
423
  return;
403
424
  }
404
425
  const shareUrl = new URL(`s/${this.sessionId}`, this.relayTarget.httpBase);
426
+ if (!this.viewerAccessToken || !this.readonlyAccessToken) {
427
+ throw new Error("missing access tokens");
428
+ }
429
+ shareUrl.searchParams.set("token", this.viewerAccessToken);
405
430
  const interactiveUrl = `${shareUrl.toString()}#${this.keyFragment}`;
406
431
  const readonlyShareUrl = new URL(`${shareUrl.pathname.replace(/\/$/, "")}/v`, shareUrl);
432
+ readonlyShareUrl.searchParams.set("token", this.readonlyAccessToken);
407
433
  const readonlyUrl = `${readonlyShareUrl.toString()}#${this.keyFragment}`;
408
434
  if (!this.silent) {
409
435
  await printShareLinkWithQr("interactive", interactiveUrl);
410
- await printShareLinkWithQr("view-only", readonlyUrl);
436
+ if (this.showReadonlyLink) {
437
+ await printShareLinkWithQr("view-only", readonlyUrl);
438
+ }
411
439
  console.log("");
412
440
  console.log(" \x1B[2mThe encryption key is in the URL fragment (#) \u2014 the server never sees it.\x1B[0m");
413
441
  console.log(" \x1B[2mPress Ctrl+C to stop sharing.\x1B[0m");
@@ -661,12 +689,14 @@ if (args.includes("--help") || args.includes("-h")) {
661
689
  \x1B[1mOptions:\x1B[0m
662
690
  --session, -s <name> tmux session to share (auto-detected if only one)
663
691
  --relay <url> relay server URL (default: https://fied.app)
692
+ --view-only print a separate view-only share link
664
693
  --allow-insecure-relay allow http://localhost relay (dev only)
665
694
  --help, -h show this help
666
695
 
667
696
  \x1B[1mExamples:\x1B[0m
668
697
  npx fied share the only tmux session
669
698
  npx fied -s mysession share a specific session
699
+ npx fied --view-only include a view-only link
670
700
  npx fied --relay http://localhost:8787 use a local relay
671
701
  `);
672
702
  process.exit(0);
@@ -680,6 +710,8 @@ if (args.includes("--__daemon")) {
680
710
  options.relay = args[++i];
681
711
  } else if (args[i] === "--allow-insecure-relay") {
682
712
  options.allowInsecureRelay = true;
713
+ } else if (args[i] === "--view-only") {
714
+ options.showReadonlyLink = true;
683
715
  } else if (args[i] === "--__session-id" && args[i + 1]) {
684
716
  options.sessionId = args[++i];
685
717
  } else if (args[i] === "--__key" && args[i + 1]) {
@@ -697,6 +729,8 @@ async function main() {
697
729
  let relay;
698
730
  let session;
699
731
  let allowInsecureRelay = false;
732
+ let showReadonlyLink = false;
733
+ let showReadonlyLinkExplicit = false;
700
734
  for (let i = 0; i < args.length; i++) {
701
735
  if ((args[i] === "--session" || args[i] === "-s") && args[i + 1]) {
702
736
  session = args[++i];
@@ -704,6 +738,9 @@ async function main() {
704
738
  relay = args[++i];
705
739
  } else if (args[i] === "--allow-insecure-relay") {
706
740
  allowInsecureRelay = true;
741
+ } else if (args[i] === "--view-only") {
742
+ showReadonlyLink = true;
743
+ showReadonlyLinkExplicit = true;
707
744
  } else if (!args[i].startsWith("-")) {
708
745
  continue;
709
746
  } else {
@@ -763,10 +800,14 @@ async function main() {
763
800
  if (!session) {
764
801
  throw new Error("No tmux session selected");
765
802
  }
803
+ if (!showReadonlyLinkExplicit && process.stdin.isTTY && process.stderr.isTTY) {
804
+ showReadonlyLink = await confirm("Enable view-only share link?");
805
+ }
766
806
  await share({
767
807
  session,
768
808
  relay,
769
809
  allowInsecureRelay,
810
+ showReadonlyLink,
770
811
  onShareUrl: async (url) => {
771
812
  const background = await confirm("Run in background?");
772
813
  if (!background) {
package/package.json CHANGED
@@ -1,11 +1,9 @@
1
1
  {
2
2
  "name": "fied",
3
- "version": "0.2.7",
3
+ "version": "0.2.8",
4
4
  "description": "Share your tmux session in the browser with end-to-end encryption",
5
5
  "type": "module",
6
- "bin": {
7
- "fied": "./dist/bin.js"
8
- },
6
+ "bin": "dist/bin.js",
9
7
  "files": [
10
8
  "dist/bin.js",
11
9
  "README.md"