oorja 1.4.1 → 1.5.1

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/README.md CHANGED
@@ -26,11 +26,15 @@ Your stream can be view-only or collaboration enabled (command-line flag).
26
26
 
27
27
  - Prerequisite: [nodejs `12.13.0` or later](https://nodejs.org/en/download/)
28
28
 
29
- - **optional but highly recommend for successful install -> [npm install without sudo](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md)**
29
+ - **optional but highly recommended for successful install -> [npm install without sudo](https://github.com/sindresorhus/guides/blob/master/npm-global-without-sudo.md)**.
30
30
  - `npm install -g oorja`
31
31
  - `teletype`
32
32
  - `teletype -m` (for collaboration mode)
33
33
 
34
+ Misc: If you have issues installing on apple M1 or similar systems:
35
+ - `sudo xcode-select --install`
36
+ - `CXXFLAGS="--std=c++17" npm install -g oorja`
37
+
34
38
  **your stream is end-to-end encrypted**
35
39
 
36
40
  **PRO TIP:**
package/bin/oorja ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+
3
+ require('@oclif/command').run()
4
+ .then(require('@oclif/command/flush'))
5
+ .catch(require('@oclif/errors/handle'))
@@ -7,8 +7,8 @@ class SignOut extends command_1.Command {
7
7
  async run() {
8
8
  const env = config_1.determineENV();
9
9
  config_1.setENVAccessToken(env, "");
10
- console.log("sign-out complete");
10
+ console.log("Sign-out complete");
11
11
  }
12
12
  }
13
13
  exports.SignOut = SignOut;
14
- SignOut.description = `sign-out of oorja. clears saved auth-token`;
14
+ SignOut.description = `Sign-out of oorja. Clears saved auth-token`;
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- const { Select, Input } = require("enquirer");
3
+ const { Select } = require("enquirer");
4
4
  const command_1 = require("@oclif/command");
5
5
  const ora = require("ora");
6
6
  const os = require("os");
7
7
  const chalk = require("chalk");
8
8
  const config_1 = require("../../lib/config");
9
9
  const oorja_1 = require("../../lib/oorja");
10
+ const utils_1 = require("../../lib/utils");
10
11
  const DEFAULT_SHELL = os.platform() === "win32" ? "powershell.exe" : process.env.SHELL || "bash";
11
12
  class TeleTypeCommand extends command_1.Command {
12
13
  async run() {
@@ -17,77 +18,63 @@ class TeleTypeCommand extends command_1.Command {
17
18
  }
18
19
  console.log("(use -h for description and options) \n");
19
20
  // room not known, prompt
20
- const ROOM = "to an existing room (you have the room link)";
21
- const NEW = "new room";
22
- try {
23
- const answer = await new Select({
24
- name: "",
25
- message: "Choose streaming destination",
26
- choices: [NEW, ROOM],
27
- }).run();
28
- switch (answer) {
29
- case ROOM:
30
- await this.streamToLink({ shell, multiplex });
31
- break;
32
- case NEW:
33
- await this.createRoomAndStream({ shell, multiplex });
34
- break;
35
- }
36
- }
37
- catch (e) {
38
- process.exit(100);
21
+ const ROOM = "To an existing room (you have the room link)";
22
+ const NEW = "New room";
23
+ const answer = await new Select({
24
+ name: "",
25
+ message: "Choose streaming destination",
26
+ choices: [NEW, ROOM],
27
+ }).run();
28
+ switch (answer) {
29
+ case ROOM:
30
+ await this.streamToLink({ shell, multiplex });
31
+ break;
32
+ case NEW:
33
+ await this.createRoomAndStream({ shell, multiplex });
34
+ break;
39
35
  }
40
36
  process.exit(0);
41
37
  }
42
38
  async streamToLink(options) {
43
- const roomLink = options.roomLink ||
44
- (await new Input({
45
- name: "room secret link",
46
- message: "enter the room secret link. (click the share button in the room)",
47
- }).run());
48
- try {
49
- const app = await oorja_1.getApp(roomLink);
50
- const roomKey = app.getRoomKey(roomLink);
51
- this.clearstdin();
52
- await app.teletype(Object.assign(Object.assign({ roomKey }, options), { process }));
53
- }
54
- catch (e) {
55
- if (e instanceof oorja_1.InvalidRoomLink) {
56
- console.log(config_1.INVALID_ROOM_LINK_MESSAGE);
57
- process.exit(3);
58
- }
39
+ const roomLink = options.roomLink || (await utils_1.promptRoomLink());
40
+ if (!roomLink) {
41
+ console.log(chalk.redBright("Room link not provided :("));
42
+ process.exit();
59
43
  }
44
+ const app = await oorja_1.getApp({ roomLink });
45
+ const roomKey = app.getRoomKey(roomLink);
46
+ this.clearstdin();
47
+ await app.teletype(Object.assign(Object.assign({ roomKey }, options), { process }));
60
48
  }
61
49
  async createRoomAndStream({ shell, multiplex, }) {
62
50
  const app = await oorja_1.getApp();
63
51
  const spinner = ora({
64
- text: chalk.bold("creating room with TeleType app"),
52
+ text: chalk.bold("Creating room with TeleType app"),
65
53
  discardStdin: false,
66
54
  }).start();
67
- try {
68
- const { roomKey } = await app.createRoom({
69
- roomName: "-",
70
- apps: {
71
- defaultFocus: "39",
72
- appList: [
73
- { appId: "39", config: {} },
74
- { appId: "31", config: {} },
75
- { appId: "40", config: {} },
76
- { appId: "100", config: {} },
77
- ],
78
- },
79
- });
80
- spinner.succeed(chalk.bold("room created")).clear();
81
- const link = app.linkForRoom(roomKey);
82
- console.log(`\n${chalk.bold(chalk.blueBright(link))}\n`);
83
- console.log(chalk.bold("^^ you'll be streaming here, share this link with your friends."));
84
- this.clearstdin();
85
- return await app.teletype({ roomKey, shell, multiplex, process });
86
- }
87
- catch (e) {
88
- console.log("failed to create room.");
55
+ const { roomKey } = await app
56
+ .createRoom({
57
+ roomName: "-",
58
+ apps: {
59
+ defaultFocus: "39",
60
+ appList: [
61
+ { appId: "39", config: {} },
62
+ { appId: "31", config: {} },
63
+ { appId: "40", config: {} },
64
+ { appId: "100", config: {} },
65
+ ],
66
+ },
67
+ })
68
+ .catch((e) => {
69
+ console.log("Failed to create room.");
89
70
  process.exit(9);
90
- }
71
+ });
72
+ spinner.succeed(chalk.bold("Room created")).clear();
73
+ const link = app.linkForRoom(roomKey);
74
+ console.log(`\n${chalk.bold(chalk.blueBright(link))}\n`);
75
+ console.log(chalk.bold("^^ You'll be streaming here, share this link with your friends."));
76
+ this.clearstdin();
77
+ return await app.teletype({ roomKey, shell, multiplex, process });
91
78
  }
92
79
  clearstdin() {
93
80
  process.stdin.read();
@@ -99,14 +86,14 @@ TeleTypeCommand.aliases = ["tty"];
99
86
  TeleTypeCommand.description = `Launch a terminal streaming session in oorja.`;
100
87
  TeleTypeCommand.examples = [
101
88
  `${chalk.blueBright("$ teletype")}
102
- will prompt to choose streaming destination - existing room or create a new one.
89
+ Will prompt to choose streaming destination - existing room or create a new one.
103
90
 
104
91
  `,
105
92
  `${chalk.blueBright(`$ teletype '${config_1.ROOM_LINK_SAMPLE}'`)}
106
- will stream to the room specified by secret link, you must have joined the room before streaming.
93
+ Will stream to the room specified by secret link, you must have joined the room before streaming.
107
94
 
108
95
  `,
109
- `${chalk.blueBright(`$ teletype -m '${config_1.ROOM_LINK_SAMPLE}'`)}
96
+ `${chalk.blueBright("$ teletype -m")}
110
97
  Will also allow room participants to write to your terminal!
111
98
 
112
99
  `,
@@ -120,7 +107,7 @@ TeleTypeCommand.flags = {
120
107
  }),
121
108
  multiplex: command_1.flags.boolean({
122
109
  char: "m",
123
- description: "allows room users to WRITE TO YOUR SHELL i.e enables collaboration mode. Make sure you trust room participants. Off by default",
110
+ description: "Allows room users to WRITE TO YOUR SHELL i.e enables collaboration mode. Make sure you trust room participants. Off by default",
124
111
  default: false,
125
112
  }),
126
113
  };
@@ -1,6 +1,6 @@
1
1
  /// <reference types="node" />
2
2
  import { URL } from "url";
3
- export declare const CLI_VERSION = 1.4;
3
+ export declare const CLI_VERSION = 1.5;
4
4
  export declare const config: any;
5
5
  export declare type env = "staging" | "local" | "prod" | "prod-teletype";
6
6
  export declare type SuryaConfig = {
package/lib/lib/config.js CHANGED
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getoorjaConfig = exports.setENVAccessToken = exports.getENVAccessToken = exports.determineENV = exports.INVALID_ROOM_LINK_MESSAGE = exports.ROOM_LINK_SAMPLE = exports.getSuryaConfig = exports.config = exports.CLI_VERSION = void 0;
4
4
  const chalk = require("chalk");
5
- exports.CLI_VERSION = 1.4;
5
+ exports.CLI_VERSION = 1.5;
6
6
  const Conf = require("conf");
7
7
  exports.config = new Conf({
8
8
  projectName: "oorja",
File without changes
File without changes
@@ -1,23 +1,23 @@
1
- import { env } from "../config";
1
+ import { oorjaConfig } from "../config";
2
2
  import { User, RoomKey } from "../surya/types";
3
3
  import { TeletypeOptions } from "../teletype";
4
- import { CreateRoomOptions } from "../surya";
4
+ import { CreateRoomOptions, SuryaClient } from "../surya";
5
5
  export declare class InvalidRoomLink extends Error {
6
6
  }
7
7
  declare class OORJA {
8
- user: User | null;
9
- private ready;
10
- private config?;
11
- initialize: (env: env) => Promise<this>;
8
+ private config;
9
+ private suryaClient;
10
+ user: User;
11
+ constructor(config: oorjaConfig, suryaClient: SuryaClient, user: User);
12
12
  createRoom: (options: CreateRoomOptions) => Promise<{
13
13
  room: import("../surya/types").Room;
14
14
  roomKey: RoomKey;
15
15
  }>;
16
16
  linkForRoom: (roomKey: RoomKey) => string;
17
17
  getRoomKey(roomLink: string): RoomKey;
18
- linkForTokenGen: () => string;
19
- teletype: (options: Omit<TeletypeOptions, "userId">) => Promise<unknown>;
20
- private oorjaURL;
18
+ teletype: (options: Omit<TeletypeOptions, "userId" | "joinChannel">) => Promise<unknown>;
21
19
  }
22
- export declare const getApp: (roomLink?: string | undefined) => Promise<OORJA>;
20
+ export declare const getApp: (options?: {
21
+ roomLink?: string;
22
+ }) => Promise<OORJA>;
23
23
  export {};
@@ -3,30 +3,21 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getApp = exports.InvalidRoomLink = void 0;
4
4
  const config_1 = require("../config");
5
5
  const teletype_1 = require("../teletype");
6
- const preflight_1 = require("./preflight");
7
6
  const surya_1 = require("../surya");
8
7
  const url_1 = require("url");
9
8
  const encryption_1 = require("../encryption");
9
+ const preflight_1 = require("./preflight");
10
10
  class InvalidRoomLink extends Error {
11
11
  }
12
12
  exports.InvalidRoomLink = InvalidRoomLink;
13
13
  class OORJA {
14
- constructor() {
15
- // should capture domain related commands and queries
16
- this.user = null;
17
- this.ready = false;
18
- this.initialize = (env) => {
19
- if (this.ready)
20
- throw "cannot reinit";
21
- this.config = config_1.getoorjaConfig(env);
22
- return preflight_1.preflightChecks(env, this.linkForTokenGen()).then((user) => {
23
- this.user = user;
24
- this.ready = true;
25
- return this;
26
- });
27
- };
14
+ // should capture domain related commands and queries
15
+ constructor(config, suryaClient, user) {
16
+ this.config = config;
17
+ this.suryaClient = suryaClient;
18
+ this.user = user;
28
19
  this.createRoom = async (options) => {
29
- const room = await surya_1.createRoom(options);
20
+ const room = await this.suryaClient.createRoom(options);
30
21
  const roomKey = encryption_1.createRoomKey(room.id);
31
22
  return {
32
23
  room,
@@ -34,39 +25,72 @@ class OORJA {
34
25
  };
35
26
  };
36
27
  this.linkForRoom = (roomKey) => {
37
- return `${this.oorjaURL()}/rooms?id=${roomKey.roomId}#${encryption_1.exportKey(roomKey.key)}`;
28
+ return `${oorjaURL(this.config)}/rooms?id=${roomKey.roomId}#${encryption_1.exportKey(roomKey.key)}`;
38
29
  };
39
- this.linkForTokenGen = () => `${this.oorjaURL()}/access_token`;
40
- this.teletype = (options) => teletype_1.teletypeApp(Object.assign({ userId: this.user.id }, options));
41
- this.oorjaURL = () => {
42
- const { host, enableTLS } = this.config;
43
- return enableTLS ? `https://${host}` : `http://${host}`;
30
+ this.teletype = (options) => {
31
+ return teletype_1.teletypeApp(Object.assign({ userId: this.user.id, joinChannel: this.suryaClient.joinChannel }, options));
44
32
  };
45
33
  }
46
34
  getRoomKey(roomLink) {
47
- const url = parseRoomLink(roomLink);
35
+ const url = parseRoomURL(roomLink);
48
36
  return {
49
37
  key: encryption_1.importKey(url.hash),
50
38
  roomId: url.searchParams.get("id"),
51
39
  };
52
40
  }
53
41
  }
54
- const parseRoomLink = (roomLink) => {
42
+ const parseRoomURL = (roomLink) => {
55
43
  const url = new url_1.URL(roomLink);
56
- if (!url.searchParams.get("id") || !url.hash)
57
- throw new InvalidRoomLink();
44
+ if (!url.searchParams.get("id") || !url.hash) {
45
+ console.log(config_1.INVALID_ROOM_LINK_MESSAGE);
46
+ process.exit(3);
47
+ }
58
48
  return url;
59
49
  };
50
+ const getRoomId = (roomURL) => {
51
+ const id = roomURL.searchParams.get("id");
52
+ return id || undefined;
53
+ };
54
+ const oorjaURL = (config) => {
55
+ const { host, enableTLS } = config;
56
+ return enableTLS ? `https://${host}` : `http://${host}`;
57
+ };
58
+ const linkForTokenGen = (config) => `${oorjaURL(config)}/access_token`;
59
+ const init = async (env, options = {}) => {
60
+ const config = config_1.getoorjaConfig(env);
61
+ let suryaClient = new surya_1.SuryaClient(env);
62
+ await preflight_1.validateCliVersion(suryaClient);
63
+ let user = await preflight_1.resumeSession(env, suryaClient, options.roomId);
64
+ if (!user) {
65
+ let token = "";
66
+ if (options.roomId) {
67
+ token = await preflight_1.loginByRoomOTP(suryaClient, options.roomId);
68
+ }
69
+ else {
70
+ token = await preflight_1.promptAuth(suryaClient, linkForTokenGen(config));
71
+ if (!token) {
72
+ console.log("Token not provided :(");
73
+ process.exit(12);
74
+ }
75
+ }
76
+ config_1.setENVAccessToken(env, token);
77
+ }
78
+ await suryaClient.destroy();
79
+ suryaClient = new surya_1.SuryaClient(env);
80
+ user = await preflight_1.preflight(env, suryaClient);
81
+ return new OORJA(config, suryaClient, user);
82
+ };
60
83
  let currentEnv;
61
84
  let oorja;
62
- exports.getApp = (roomLink) => {
63
- const env = config_1.determineENV(roomLink ? parseRoomLink(roomLink) : undefined);
85
+ exports.getApp = async (options = {}) => {
86
+ const { roomLink } = options;
87
+ const roomURL = roomLink ? parseRoomURL(roomLink) : undefined;
88
+ const env = config_1.determineENV(undefined);
64
89
  if (oorja) {
65
90
  if (env !== currentEnv) {
66
- return Promise.reject("attempt to run different env in same session");
91
+ return Promise.reject("Attempt to run different env in same session");
67
92
  }
68
93
  return Promise.resolve(oorja);
69
94
  }
70
- oorja = new OORJA();
71
- return oorja.initialize(env);
95
+ return await init(env, { roomId: roomURL ? getRoomId(roomURL) : undefined });
72
96
  };
@@ -1,2 +1,9 @@
1
1
  import { env } from "../config";
2
- export declare const preflightChecks: (env: env, generateTokenLink: string) => Promise<import("../surya/types").User>;
2
+ import { SuryaClient } from "../surya";
3
+ import { User } from "../surya/types";
4
+ export declare const promptRoomParticipantOTP: () => Promise<string>;
5
+ export declare const promptAuth: (suryaClient: SuryaClient, generateTokenLink: string) => Promise<string>;
6
+ export declare const loginByRoomOTP: (suryaClient: SuryaClient, roomId: string) => Promise<string>;
7
+ export declare const validateCliVersion: (suryaClient: SuryaClient) => Promise<void>;
8
+ export declare const resumeSession: (env: env, suryaClient: SuryaClient, roomId?: string | undefined) => Promise<User | null>;
9
+ export declare const preflight: (env: env, suryaClient: SuryaClient) => Promise<User>;
@@ -1,71 +1,106 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.preflightChecks = void 0;
3
+ exports.preflight = exports.resumeSession = exports.validateCliVersion = exports.loginByRoomOTP = exports.promptAuth = exports.promptRoomParticipantOTP = void 0;
4
4
  const chalk = require("chalk");
5
5
  const { Input, Select } = require("enquirer");
6
6
  const ora = require("ora");
7
7
  const config_1 = require("../config");
8
- const surya_1 = require("../surya");
9
8
  const errors_1 = require("../surya/errors");
10
9
  const promptToken = () => new Input({
11
10
  name: "Access Token",
12
11
  message: "Please enter your access token for authentication:",
13
12
  }).run();
14
- const promptAuth = async (env, generateTokenLink) => {
15
- const HAS_TOKEN = "I have a token with me";
13
+ exports.promptRoomParticipantOTP = () => new Input({
14
+ name: "OTP prompt",
15
+ message: "Please enter your OTP for authentication:",
16
+ }).run();
17
+ const OTP_HELP_MESSAGE = "You can generate OTP from the room, it's in the instruction steps";
18
+ exports.promptAuth = async (suryaClient, generateTokenLink) => {
16
19
  const ANON = "Proceed as an anonymous user";
17
- const SIGN_IN = "sign-in with oorja";
18
- console.log(`\n${chalk.bold("PRO-TIP:")} if you sign-in, you can control your shell from the web-ui as well, without enabling collaboration mode for all participants\n`);
20
+ const SIGN_IN = "Sign-in with oorja";
21
+ console.log(`\n${chalk.bold("PRO-TIP:")} If you sign-in, you can control your shell from the web-ui as well, without enabling collaboration mode for the other participants\n`);
19
22
  const answer = await new Select({
20
23
  message: "You need an access-token for authentication.\n ",
21
- choices: [HAS_TOKEN, ANON, SIGN_IN],
24
+ choices: [ANON, SIGN_IN],
22
25
  }).run();
23
26
  switch (answer) {
24
- case HAS_TOKEN:
25
- return promptToken();
26
27
  case ANON:
27
- console.log("creating anonymous user...");
28
- return surya_1.createAnonymousUser(env);
28
+ console.log("Creating anonymous user...");
29
+ return suryaClient.createAnonymousUser();
29
30
  case SIGN_IN:
30
31
  console.log(`You can sign-in and generate your token here: ${chalk.blue(generateTokenLink)}`);
31
32
  return promptToken();
32
33
  }
33
- throw Error("unexpected input");
34
+ throw Error("Unexpected input");
35
+ };
36
+ exports.loginByRoomOTP = async (suryaClient, roomId) => {
37
+ const otp = await exports.promptRoomParticipantOTP();
38
+ if (!otp) {
39
+ console.log("OTP not provided :(");
40
+ console.log(OTP_HELP_MESSAGE);
41
+ process.exit(213);
42
+ }
43
+ try {
44
+ return await suryaClient.accessTokenFromRoomParticipantOTP(roomId, otp);
45
+ }
46
+ catch (e) {
47
+ if (e instanceof errors_1.BadRequest) {
48
+ console.log(chalk.redBright("Invalid otp. It may have expired."));
49
+ console.log(OTP_HELP_MESSAGE);
50
+ process.exit();
51
+ }
52
+ throw e;
53
+ }
54
+ };
55
+ exports.validateCliVersion = async (suryaClient) => {
56
+ const manifest = await suryaClient.fetchCliManifest();
57
+ if (manifest.cliVersion > config_1.CLI_VERSION) {
58
+ console.log(chalk.redBright("Your oorja cli is outdated. Please run: npm update -g oorja"));
59
+ process.exit(1);
60
+ }
34
61
  };
35
- exports.preflightChecks = async (env, generateTokenLink) => {
36
- const token = config_1.getENVAccessToken(env) || (await promptAuth(env, generateTokenLink)).trim();
37
- if (!token) {
38
- console.log("token not provided :(");
39
- process.exit(12);
62
+ exports.resumeSession = async (env, suryaClient, roomId) => {
63
+ const token = config_1.getENVAccessToken(env);
64
+ if (!token)
65
+ return null;
66
+ // try to validate authorization with existing token
67
+ try {
68
+ const user = await suryaClient.fetchSessionUser();
69
+ if (roomId) {
70
+ await suryaClient.fetchRoom(roomId);
71
+ }
72
+ return user;
40
73
  }
41
- config_1.setENVAccessToken(env, token);
74
+ catch (e) {
75
+ if (e instanceof errors_1.Unauthorized) {
76
+ config_1.setENVAccessToken(env, "");
77
+ return null;
78
+ }
79
+ throw e;
80
+ }
81
+ };
82
+ exports.preflight = async (env, suryaClient) => {
42
83
  const spinner = ora({
43
- text: "authenticating",
84
+ text: "Authenticating",
44
85
  discardStdin: false,
45
86
  }).start();
46
- const suryaConfig = config_1.getSuryaConfig(env);
47
- surya_1.initializeSurya(suryaConfig);
48
87
  try {
49
- const manifest = await surya_1.fetchCliManifest();
50
- if (manifest.cliVersion > config_1.CLI_VERSION) {
51
- spinner.fail(chalk.yellowBright("your oorja cli is outdated. please run: npm update -g oorja"));
52
- process.exit(1);
53
- }
54
- const user = await surya_1.fetchSessionUser();
55
- spinner.succeed(`authenticated: Welcome ${user.name}`);
88
+ const user = await suryaClient.fetchSessionUser();
89
+ spinner.succeed(`Authenticated: Welcome ${user.name}`);
56
90
  if (user.profileType === "anon") {
57
91
  // don't persist tokens for anonymous users
58
92
  config_1.setENVAccessToken(env, "");
59
93
  console.log(chalk.yellowBright("You're an anonymous user. CLI will not remember the auth-token"));
60
94
  }
61
- spinner.start("connecting..");
62
- return surya_1.establishSocket(suryaConfig)
95
+ spinner.start("Connecting..");
96
+ return suryaClient
97
+ .establishSocket()
63
98
  .then(() => {
64
- spinner.succeed("connected").clear();
99
+ spinner.succeed("Connected").clear();
65
100
  return user;
66
101
  })
67
102
  .catch((e) => {
68
- spinner.fail("socket connection failure..");
103
+ spinner.fail("Socket connection failure..");
69
104
  throw e;
70
105
  });
71
106
  }
@@ -76,7 +111,7 @@ exports.preflightChecks = async (env, generateTokenLink) => {
76
111
  process.exit(33);
77
112
  }
78
113
  else {
79
- spinner.fail("something went wrong :(");
114
+ spinner.fail("Something went wrong :(");
80
115
  }
81
116
  throw e;
82
117
  }
@@ -1,4 +1,6 @@
1
- export declare class Unauthorized extends Error {
1
+ export declare class ClientError extends Error {
2
2
  }
3
- export declare class BadRequest extends Error {
3
+ export declare class Unauthorized extends ClientError {
4
+ }
5
+ export declare class BadRequest extends ClientError {
4
6
  }
@@ -1,9 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.BadRequest = exports.Unauthorized = void 0;
4
- class Unauthorized extends Error {
3
+ exports.BadRequest = exports.Unauthorized = exports.ClientError = void 0;
4
+ class ClientError extends Error {
5
+ }
6
+ exports.ClientError = ClientError;
7
+ class Unauthorized extends ClientError {
5
8
  }
6
9
  exports.Unauthorized = Unauthorized;
7
- class BadRequest extends Error {
10
+ class BadRequest extends ClientError {
8
11
  }
9
12
  exports.BadRequest = BadRequest;
@@ -1,19 +1,27 @@
1
1
  import { User, RoomApps, Room, CliManifest } from "./types";
2
- import { SuryaConfig, env } from "../config";
2
+ import { env } from "../config";
3
3
  import { Channel } from "./vendor/phoenix";
4
4
  export declare class SuryaError extends Error {
5
5
  }
6
- export declare const initializeSurya: (config: SuryaConfig) => void;
7
- export declare const fetchCliManifest: () => Promise<CliManifest>;
8
- export declare const fetchSessionUser: () => Promise<User>;
6
+ export declare class SuryaClient {
7
+ private config;
8
+ private client;
9
+ private socket?;
10
+ constructor(env: env);
11
+ fetchCliManifest: () => Promise<CliManifest>;
12
+ fetchSessionUser: () => Promise<User>;
13
+ createRoom: ({ roomName, apps }: CreateRoomOptions) => Promise<Room>;
14
+ createAnonymousUser: () => Promise<string>;
15
+ accessTokenFromRoomParticipantOTP: (roomId: string, otp: string) => Promise<string>;
16
+ fetchRoom: (roomId: string) => Promise<Room>;
17
+ establishSocket: () => Promise<void>;
18
+ joinChannel: ({ channel, params, onJoin, onClose, onError, onMessage, handleSessionJoin, handleSessionLeave, }: JoinChannelOptions<any>) => Channel;
19
+ destroy: () => Promise<unknown>;
20
+ }
9
21
  export declare type CreateRoomOptions = {
10
22
  roomName: string;
11
23
  apps: RoomApps;
12
24
  };
13
- export declare const createRoom: ({ roomName, apps, }: CreateRoomOptions) => Promise<Room>;
14
- export declare const createAnonymousUser: (env: env) => Promise<string>;
15
- export declare const fetchRoom: (roomId: string) => Promise<Room>;
16
- export declare const establishSocket: (config: SuryaConfig) => Promise<void>;
17
25
  export declare type JoinChannelOptions<T> = {
18
26
  channel: string;
19
27
  params: T;
@@ -24,4 +32,3 @@ export declare type JoinChannelOptions<T> = {
24
32
  handleSessionJoin: (session: string) => void;
25
33
  handleSessionLeave: (session: string) => void;
26
34
  };
27
- export declare const joinChannel: ({ channel, params, onJoin, onClose, onError, onMessage, handleSessionJoin, handleSessionLeave, }: JoinChannelOptions<any>) => Channel;
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.joinChannel = exports.establishSocket = exports.fetchRoom = exports.createAnonymousUser = exports.createRoom = exports.fetchSessionUser = exports.fetchCliManifest = exports.initializeSurya = exports.SuryaError = void 0;
3
+ exports.SuryaClient = exports.SuryaError = void 0;
4
4
  // backend api client
5
5
  const https = require("https");
6
6
  const axios_1 = require("axios");
@@ -13,23 +13,175 @@ const camelcaseKeys = require("camelcase-keys");
13
13
  class SuryaError extends Error {
14
14
  }
15
15
  exports.SuryaError = SuryaError;
16
- let client;
17
- let socket;
16
+ class SuryaClient {
17
+ constructor(env) {
18
+ this.fetchCliManifest = async () => {
19
+ try {
20
+ const response = await this.client.get("/cli");
21
+ return camelcaseKeys(response.data);
22
+ }
23
+ catch (error) {
24
+ return handleError(error);
25
+ }
26
+ };
27
+ this.fetchSessionUser = async () => {
28
+ try {
29
+ const response = await this.client.get("/session/user");
30
+ return resources_1.defaultParser(response.data.data);
31
+ }
32
+ catch (error) {
33
+ return handleError(error);
34
+ }
35
+ };
36
+ this.createRoom = async ({ roomName, apps }) => {
37
+ const body = {
38
+ room: {
39
+ apps,
40
+ locked: false,
41
+ name: roomName || "-",
42
+ },
43
+ };
44
+ try {
45
+ const response = await this.client.post("/rooms", body);
46
+ return resources_1.defaultParser(response.data.data);
47
+ }
48
+ catch (error) {
49
+ return handleError(error);
50
+ }
51
+ };
52
+ this.createAnonymousUser = async () => {
53
+ try {
54
+ const response = await this.client.post("/session/anon");
55
+ return response.data.access_token;
56
+ }
57
+ catch (error) {
58
+ return handleError(error);
59
+ }
60
+ };
61
+ this.accessTokenFromRoomParticipantOTP = async (roomId, otp) => {
62
+ try {
63
+ const response = await this.client.post("/access_tokens/from_room_participant_otp", {
64
+ room_id: roomId,
65
+ otp: otp,
66
+ });
67
+ return response.data.data.token;
68
+ }
69
+ catch (error) {
70
+ return handleError(error);
71
+ }
72
+ };
73
+ this.fetchRoom = async (roomId) => {
74
+ try {
75
+ const response = await this.client.get(`/rooms/${roomId}`);
76
+ return resources_1.defaultParser(response.data.data);
77
+ }
78
+ catch (error) {
79
+ return handleError(error);
80
+ }
81
+ };
82
+ this.establishSocket = async () => {
83
+ const protocolPrefix = this.config.enableTLS ? `wss://` : `ws://`;
84
+ const host = this.config.host;
85
+ let encodeMessage = (rawdata, callback) => {
86
+ if (!rawdata)
87
+ return;
88
+ return callback(msgpack_1.encode(rawdata));
89
+ };
90
+ let decodeMessage = (rawdata, callback) => {
91
+ if (!rawdata)
92
+ return;
93
+ const data = new Uint8Array(rawdata);
94
+ return callback(msgpack_1.decode(data.buffer));
95
+ };
96
+ return new Promise((resolve, reject) => {
97
+ let initialConnection = false;
98
+ this.socket = new phoenix_1.Socket(`${protocolPrefix}${host}/socket`, {
99
+ params: {
100
+ access_token: this.config.token,
101
+ },
102
+ binaryType: "arraybuffer",
103
+ encode: encodeMessage,
104
+ decode: decodeMessage,
105
+ });
106
+ this.socket.onOpen(() => {
107
+ initialConnection = true;
108
+ resolve();
109
+ });
110
+ this.socket.onError(() => {
111
+ if (!initialConnection) {
112
+ reject();
113
+ return;
114
+ }
115
+ console.error("connection error");
116
+ process.exit(2);
117
+ });
118
+ // @ts-ignore
119
+ this.socket.connect();
120
+ });
121
+ };
122
+ this.joinChannel = ({ channel, params, onJoin, onClose, onError, onMessage, handleSessionJoin, handleSessionLeave, }) => {
123
+ if (!this.socket)
124
+ throw Error("no socket connection");
125
+ const chan = this.socket.channel(channel, params);
126
+ if (onError)
127
+ chan.onError(onError);
128
+ if (onClose)
129
+ chan.onClose(onClose);
130
+ let presences = [];
131
+ chan.on("new_msg", (msg) => {
132
+ onMessage(msg);
133
+ });
134
+ chan.on("presence_state", (response) => {
135
+ phoenix_1.Presence.syncState(presences, response, handleSessionJoin, undefined);
136
+ presences = response;
137
+ });
138
+ chan.on("presence_diff", (newPresence) => {
139
+ presences = phoenix_1.Presence.syncDiff(presences, newPresence, handleSessionJoin, handleSessionLeave);
140
+ });
141
+ chan
142
+ .join()
143
+ .receive("ok", () => {
144
+ if (onJoin)
145
+ onJoin();
146
+ })
147
+ .receive("error", (resp) => {
148
+ if (resp && resp.reason === "unauthorized") {
149
+ if (onError)
150
+ onError(new errors_1.Unauthorized("unauthorized: user needs to join the room before a stream can be started."));
151
+ return;
152
+ }
153
+ process.exit(3);
154
+ });
155
+ return chan;
156
+ };
157
+ this.destroy = async () => {
158
+ return new Promise((resolve) => {
159
+ if (this.socket) {
160
+ this.socket.disconnect(resolve, 1000, "disconnecting surya client");
161
+ }
162
+ else {
163
+ resolve(undefined);
164
+ }
165
+ });
166
+ };
167
+ const config = config_1.getSuryaConfig(env);
168
+ this.client = axios_1.default.create({
169
+ httpsAgent: new https.Agent({
170
+ minVersion: "TLSv1.2",
171
+ maxVersion: "TLSv1.2",
172
+ }),
173
+ baseURL: suryaBaseURL(config.host, config.enableTLS),
174
+ timeout: 5000,
175
+ responseType: "json",
176
+ headers: {
177
+ "x-access-token": config.token || "",
178
+ },
179
+ });
180
+ this.config = config;
181
+ }
182
+ }
183
+ exports.SuryaClient = SuryaClient;
18
184
  const suryaBaseURL = (host, tlsEnabled) => `${tlsEnabled ? "https" : "http"}://${host}/api/v1`;
19
- exports.initializeSurya = (config) => {
20
- client = axios_1.default.create({
21
- httpsAgent: new https.Agent({
22
- minVersion: "TLSv1.2",
23
- maxVersion: "TLSv1.2",
24
- }),
25
- baseURL: suryaBaseURL(config.host, config.enableTLS),
26
- timeout: 5000,
27
- responseType: "json",
28
- headers: {
29
- "x-access-token": config.token || "",
30
- },
31
- });
32
- };
33
185
  const handleError = (error) => {
34
186
  const { response } = error;
35
187
  if (response) {
@@ -42,131 +194,3 @@ const handleError = (error) => {
42
194
  }
43
195
  throw error;
44
196
  };
45
- exports.fetchCliManifest = async () => {
46
- try {
47
- const response = await client.get("/cli");
48
- return camelcaseKeys(response.data);
49
- }
50
- catch (error) {
51
- return handleError(error);
52
- }
53
- };
54
- exports.fetchSessionUser = async () => {
55
- try {
56
- const response = await client.get("/session/user");
57
- return resources_1.defaultParser(response.data.data);
58
- }
59
- catch (error) {
60
- return handleError(error);
61
- }
62
- };
63
- exports.createRoom = async ({ roomName, apps, }) => {
64
- const body = {
65
- room: {
66
- apps,
67
- locked: false,
68
- name: roomName || "-",
69
- },
70
- };
71
- try {
72
- const response = await client.post("/rooms", body);
73
- return resources_1.defaultParser(response.data.data);
74
- }
75
- catch (error) {
76
- return handleError(error);
77
- }
78
- };
79
- exports.createAnonymousUser = async (env) => {
80
- const config = config_1.getSuryaConfig(env);
81
- try {
82
- const response = await axios_1.default.post(`${suryaBaseURL(config.host, config.enableTLS)}/session/anon`);
83
- return response.data.access_token;
84
- }
85
- catch (error) {
86
- return handleError(error);
87
- }
88
- };
89
- exports.fetchRoom = async (roomId) => {
90
- try {
91
- const response = await client.get(`/rooms/${roomId}`);
92
- return resources_1.defaultParser(response.data.data);
93
- }
94
- catch (error) {
95
- return handleError(error);
96
- }
97
- };
98
- exports.establishSocket = async (config) => {
99
- const protocolPrefix = config.enableTLS ? `wss://` : `ws://`;
100
- const host = config.host;
101
- let encodeMessage = (rawdata, callback) => {
102
- if (!rawdata)
103
- return;
104
- return callback(msgpack_1.encode(rawdata));
105
- };
106
- let decodeMessage = (rawdata, callback) => {
107
- if (!rawdata)
108
- return;
109
- const data = new Uint8Array(rawdata);
110
- return callback(msgpack_1.decode(data.buffer));
111
- };
112
- return new Promise((resolve, reject) => {
113
- let initialConnection = false;
114
- socket = new phoenix_1.Socket(`${protocolPrefix}${host}/socket`, {
115
- params: {
116
- access_token: config.token,
117
- },
118
- binaryType: "arraybuffer",
119
- encode: encodeMessage,
120
- decode: decodeMessage,
121
- });
122
- socket.onOpen(() => {
123
- initialConnection = true;
124
- resolve();
125
- });
126
- socket.onError(() => {
127
- if (!initialConnection) {
128
- reject();
129
- return;
130
- }
131
- console.error("connection error");
132
- process.exit(2);
133
- });
134
- // @ts-ignore
135
- socket.connect();
136
- });
137
- };
138
- exports.joinChannel = ({ channel, params, onJoin, onClose, onError, onMessage, handleSessionJoin, handleSessionLeave, }) => {
139
- if (!socket)
140
- throw Error("no socket connection");
141
- const chan = socket.channel(channel, params);
142
- if (onError)
143
- chan.onError(onError);
144
- if (onClose)
145
- chan.onClose(onClose);
146
- let presences = [];
147
- chan.on("new_msg", (msg) => {
148
- onMessage(msg);
149
- });
150
- chan.on("presence_state", (response) => {
151
- phoenix_1.Presence.syncState(presences, response, handleSessionJoin, undefined);
152
- presences = response;
153
- });
154
- chan.on("presence_diff", (newPresence) => {
155
- presences = phoenix_1.Presence.syncDiff(presences, newPresence, handleSessionJoin, handleSessionLeave);
156
- });
157
- chan
158
- .join()
159
- .receive("ok", () => {
160
- if (onJoin)
161
- onJoin();
162
- })
163
- .receive("error", (resp) => {
164
- if (resp && resp.reason === "unauthorized") {
165
- if (onError)
166
- onError(new errors_1.Unauthorized("unauthorized: user needs to join the room before a stream can be started."));
167
- return;
168
- }
169
- process.exit(3);
170
- });
171
- return chan;
172
- };
@@ -8,7 +8,7 @@ exports.initScreen = (username, hostname, shell, multiplexed) => {
8
8
  if (multiplexed) {
9
9
  console.log(chalk.yellowBright("You have allowed room participants to write to your shell"));
10
10
  }
11
- console.log(chalk.blue(`${chalk.bold(`${username}@${hostname}`)} spawning streaming shell: ${chalk.bold(`${shell}`)}`));
11
+ console.log(chalk.blue(`${chalk.bold(`${username}@${hostname}`)} Spawning streaming shell: ${chalk.bold(`${shell}`)}`));
12
12
  console.log(`Note: Your shell size may adjust for optimum viewing experience for all participants.\n
13
13
  This session is end-to-end encrypted.
14
14
  To terminate stream run ${chalk.yellowBright("exit")} or press ${chalk.yellowBright("ctrl-d")} \n`);
@@ -1,10 +1,13 @@
1
1
  /// <reference types="node" />
2
2
  import { RoomKey } from "../surya/types";
3
+ import { JoinChannelOptions } from "../surya";
4
+ import { Channel } from "../surya/vendor/phoenix";
3
5
  export declare type TeletypeOptions = {
4
6
  userId: string;
5
7
  roomKey: RoomKey;
6
8
  shell: string;
7
9
  multiplex: boolean;
8
10
  process: NodeJS.Process;
11
+ joinChannel: (options: JoinChannelOptions<any>) => Channel;
9
12
  };
10
- export declare const teletypeApp: (config: TeletypeOptions) => Promise<unknown>;
13
+ export declare const teletypeApp: (options: TeletypeOptions) => Promise<unknown>;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.teletypeApp = void 0;
4
4
  const node_pty_1 = require("node-pty");
5
5
  const os = require("os");
6
- const surya_1 = require("../surya");
7
6
  const auxiliary_1 = require("./auxiliary");
8
7
  const chalk = require("chalk");
9
8
  const errors_1 = require("../surya/errors");
@@ -15,7 +14,7 @@ var MessageType;
15
14
  MessageType["DIMENSIONS"] = "d";
16
15
  })(MessageType || (MessageType = {}));
17
16
  const SELF = "self";
18
- exports.teletypeApp = (config) => {
17
+ exports.teletypeApp = (options) => {
19
18
  const username = os.userInfo().username;
20
19
  const hostname = os.hostname();
21
20
  const userDimensions = {};
@@ -31,25 +30,25 @@ exports.teletypeApp = (config) => {
31
30
  auxiliary_1.resizeBestFit(term, userDimensions);
32
31
  };
33
32
  return new Promise((resolve, reject) => {
34
- const channel = surya_1.joinChannel({
35
- channel: `teletype:${config.roomKey.roomId}`,
33
+ const channel = options.joinChannel({
34
+ channel: `teletype:${options.roomKey.roomId}`,
36
35
  params: {
37
36
  username,
38
37
  hostname,
39
- multiplexed: config.multiplex,
38
+ multiplexed: options.multiplex,
40
39
  },
41
40
  onJoin: () => {
42
- auxiliary_1.initScreen(username, hostname, config.shell, config.multiplex);
43
- const stdin = config.process.stdin;
44
- const stdout = config.process.stdout;
41
+ auxiliary_1.initScreen(username, hostname, options.shell, options.multiplex);
42
+ const stdin = options.process.stdin;
43
+ const stdout = options.process.stdout;
45
44
  const dimensions = userDimensions[SELF];
46
- term = node_pty_1.spawn(config.shell, [], {
45
+ term = node_pty_1.spawn(options.shell, [], {
47
46
  name: "xterm-256color",
48
47
  cols: dimensions.cols,
49
48
  rows: dimensions.rows,
50
- cwd: config.process.cwd(),
49
+ cwd: options.process.cwd(),
51
50
  // @ts-ignore
52
- env: config.process.env,
51
+ env: options.process.env,
53
52
  });
54
53
  // track own dimensions and keep it up to date
55
54
  setInterval(reEvaluateOwnDimensions, 1000);
@@ -60,7 +59,7 @@ exports.teletypeApp = (config) => {
60
59
  channel.push("new_msg", {
61
60
  t: MessageType.OUT,
62
61
  b: true,
63
- d: encryption_1.encrypt(d, config.roomKey),
62
+ d: encryption_1.encrypt(d, options.roomKey),
64
63
  });
65
64
  });
66
65
  term.on("exit", () => {
@@ -91,13 +90,13 @@ exports.teletypeApp = (config) => {
91
90
  auxiliary_1.resizeBestFit(term, userDimensions);
92
91
  break;
93
92
  case MessageType.IN:
94
- const data = encryption_1.decrypt(d, config.roomKey);
93
+ const data = encryption_1.decrypt(d, options.roomKey);
95
94
  const userId = session.split(":")[0];
96
- if (config.multiplex) {
95
+ if (options.multiplex) {
97
96
  term.write(data);
98
97
  return;
99
98
  }
100
- if (userId === config.userId) {
99
+ if (userId === options.userId) {
101
100
  term.write(data);
102
101
  }
103
102
  else {
@@ -0,0 +1 @@
1
+ export declare const promptRoomLink: () => Promise<string>;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.promptRoomLink = void 0;
4
+ const { Input } = require("enquirer");
5
+ exports.promptRoomLink = async () => {
6
+ return await new Input({
7
+ name: "room secret link",
8
+ message: "Enter the room secret link. (click the share button in the room)",
9
+ }).run();
10
+ };
@@ -1 +1 @@
1
- {"version":"1.4.1","commands":{"signout":{"id":"signout","description":"sign-out of oorja. clears saved auth-token","pluginName":"oorja","pluginType":"core","aliases":[],"flags":{},"args":[]},"teletype":{"id":"teletype","description":"Launch a terminal streaming session in oorja.","pluginName":"oorja","pluginType":"core","aliases":["tty"],"examples":["\u001b[94m$ teletype\u001b[39m\nwill prompt to choose streaming destination - existing room or create a new one.\n\n","\u001b[94m$ teletype 'https://oorja.io/rooms?id=foo#key'\u001b[39m\nwill stream to the room specified by secret link, you must have joined the room before streaming.\n\n","\u001b[94m$ teletype -m 'https://oorja.io/rooms?id=foo#key'\u001b[39m\nWill also allow room participants to write to your terminal!\n\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"shell":{"name":"shell","type":"option","char":"s","description":"shell to use. e.g. bash, fish","default":"/usr/bin/zsh"},"multiplex":{"name":"multiplex","type":"boolean","char":"m","description":"allows room users to WRITE TO YOUR SHELL i.e enables collaboration mode. Make sure you trust room participants. Off by default","allowNo":false}},"args":[{"name":"room"}]}}}
1
+ {"version":"1.5.1","commands":{"signout":{"id":"signout","description":"Sign-out of oorja. Clears saved auth-token","pluginName":"oorja","pluginType":"core","aliases":[],"flags":{},"args":[]},"teletype":{"id":"teletype","description":"Launch a terminal streaming session in oorja.","pluginName":"oorja","pluginType":"core","aliases":["tty"],"examples":["\u001b[94m$ teletype\u001b[39m\nWill prompt to choose streaming destination - existing room or create a new one.\n\n","\u001b[94m$ teletype 'https://oorja.io/rooms?id=foo#key'\u001b[39m\nWill stream to the room specified by secret link, you must have joined the room before streaming.\n\n","\u001b[94m$ teletype -m\u001b[39m\nWill also allow room participants to write to your terminal!\n\n"],"flags":{"help":{"name":"help","type":"boolean","char":"h","description":"show CLI help","allowNo":false},"shell":{"name":"shell","type":"option","char":"s","description":"shell to use. e.g. bash, fish","default":"/usr/bin/zsh"},"multiplex":{"name":"multiplex","type":"boolean","char":"m","description":"Allows room users to WRITE TO YOUR SHELL i.e enables collaboration mode. Make sure you trust room participants. Off by default","allowNo":false}},"args":[{"name":"room"}]}}}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "oorja",
3
3
  "description": "stream terminals to the web and more.",
4
- "version": "1.4.1",
4
+ "version": "1.5.1",
5
5
  "author": "Akshay Kumar @akshaykmr",
6
6
  "bin": {
7
7
  "oorja": "./bin/run",
@@ -13,7 +13,7 @@
13
13
  "@oclif/command": "^1",
14
14
  "@oclif/config": "^1",
15
15
  "@oclif/plugin-help": "^3",
16
- "axios": "^0.19.2",
16
+ "axios": "^0.21.1",
17
17
  "camelcase-keys": "^6.2.2",
18
18
  "chalk": "^4.1.0",
19
19
  "conf-cli": "^0.1.9",
@@ -28,14 +28,14 @@
28
28
  "@oclif/dev-cli": "^1",
29
29
  "@types/node": "^10",
30
30
  "globby": "^10",
31
+ "prettier": "^2.0.5",
31
32
  "ts-node": "^8",
32
33
  "tslint": "^6.1.1",
33
34
  "tslint-config-airbnb": "^5.11.2",
34
35
  "tslint-config-prettier": "^1.18.0",
35
36
  "tslint-plugin-prettier": "^2.3.0",
36
37
  "tslint-react": "^4.2.0",
37
- "typescript": "^3.3",
38
- "prettier": "^2.0.5"
38
+ "typescript": "^3.3"
39
39
  },
40
40
  "engines": {
41
41
  "node": ">=10.4.0"