@mux/cli 0.7.1 → 0.8.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/README.md +39 -12
- package/lib/command-bases/base.d.ts +3 -3
- package/lib/command-bases/base.js +1 -0
- package/lib/commands/sign.d.ts +1 -5
- package/lib/commands/sign.js +28 -11
- package/lib/commands/spaces/sign.d.ts +11 -0
- package/lib/commands/spaces/sign.js +79 -0
- package/oclif.manifest.json +1 -1
- package/package.json +3 -1
- package/src/command-bases/base.ts +4 -3
- package/src/commands/sign.ts +33 -14
- package/src/commands/spaces/sign.ts +90 -0
- package/yarn.lock +7 -0
package/README.md
CHANGED
|
@@ -21,7 +21,7 @@ $ npm install -g @mux/cli
|
|
|
21
21
|
$ mux COMMAND
|
|
22
22
|
running command...
|
|
23
23
|
$ mux (-v|--version|version)
|
|
24
|
-
@mux/cli/0.
|
|
24
|
+
@mux/cli/0.8.0 linux-x64 node-v14.18.3
|
|
25
25
|
$ mux --help [COMMAND]
|
|
26
26
|
USAGE
|
|
27
27
|
$ mux COMMAND
|
|
@@ -48,6 +48,7 @@ USAGE
|
|
|
48
48
|
* [`mux plugins:uninstall PLUGIN...`](#mux-pluginsuninstall-plugin)
|
|
49
49
|
* [`mux plugins:update`](#mux-pluginsupdate)
|
|
50
50
|
* [`mux sign PLAYBACK-ID`](#mux-sign-playback-id)
|
|
51
|
+
* [`mux spaces:sign SPACE-ID`](#mux-spacessign-space-id)
|
|
51
52
|
* [`mux update [CHANNEL]`](#mux-update-channel)
|
|
52
53
|
|
|
53
54
|
## `mux assets:create INPUT`
|
|
@@ -65,7 +66,7 @@ OPTIONS
|
|
|
65
66
|
-p, --private add a private playback policy to the created asset
|
|
66
67
|
```
|
|
67
68
|
|
|
68
|
-
_See code: [src/commands/assets/create.ts](https://github.com/muxinc/cli/blob/v0.
|
|
69
|
+
_See code: [src/commands/assets/create.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/assets/create.ts)_
|
|
69
70
|
|
|
70
71
|
## `mux assets:upload PATH`
|
|
71
72
|
|
|
@@ -84,7 +85,7 @@ OPTIONS
|
|
|
84
85
|
-p, --private
|
|
85
86
|
```
|
|
86
87
|
|
|
87
|
-
_See code: [src/commands/assets/upload.ts](https://github.com/muxinc/cli/blob/v0.
|
|
88
|
+
_See code: [src/commands/assets/upload.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/assets/upload.ts)_
|
|
88
89
|
|
|
89
90
|
## `mux autocomplete [SHELL]`
|
|
90
91
|
|
|
@@ -135,20 +136,20 @@ _See code: [@oclif/plugin-commands](https://github.com/oclif/plugin-commands/blo
|
|
|
135
136
|
|
|
136
137
|
## `mux help [COMMAND]`
|
|
137
138
|
|
|
138
|
-
|
|
139
|
+
display help for mux
|
|
139
140
|
|
|
140
141
|
```
|
|
141
142
|
USAGE
|
|
142
143
|
$ mux help [COMMAND]
|
|
143
144
|
|
|
144
145
|
ARGUMENTS
|
|
145
|
-
COMMAND
|
|
146
|
+
COMMAND command to show help for
|
|
146
147
|
|
|
147
148
|
OPTIONS
|
|
148
|
-
|
|
149
|
+
--all see all commands in CLI
|
|
149
150
|
```
|
|
150
151
|
|
|
151
|
-
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/
|
|
152
|
+
_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.18/src/commands/help.ts)_
|
|
152
153
|
|
|
153
154
|
## `mux init [ENVFILE]`
|
|
154
155
|
|
|
@@ -165,7 +166,7 @@ OPTIONS
|
|
|
165
166
|
-f, --force Will initialize a new file even if one already exists.
|
|
166
167
|
```
|
|
167
168
|
|
|
168
|
-
_See code: [src/commands/init.ts](https://github.com/muxinc/cli/blob/v0.
|
|
169
|
+
_See code: [src/commands/init.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/init.ts)_
|
|
169
170
|
|
|
170
171
|
## `mux live:complete STREAMNAME`
|
|
171
172
|
|
|
@@ -183,7 +184,7 @@ OPTIONS
|
|
|
183
184
|
-t, --streamId=stream-id [default: stream-id] the type of the provided reference name
|
|
184
185
|
```
|
|
185
186
|
|
|
186
|
-
_See code: [src/commands/live/complete.ts](https://github.com/muxinc/cli/blob/v0.
|
|
187
|
+
_See code: [src/commands/live/complete.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/live/complete.ts)_
|
|
187
188
|
|
|
188
189
|
## `mux live:disable STREAMNAME`
|
|
189
190
|
|
|
@@ -200,7 +201,7 @@ OPTIONS
|
|
|
200
201
|
-t, --streamId=stream-id [default: stream-id] the type of the provided reference name
|
|
201
202
|
```
|
|
202
203
|
|
|
203
|
-
_See code: [src/commands/live/disable.ts](https://github.com/muxinc/cli/blob/v0.
|
|
204
|
+
_See code: [src/commands/live/disable.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/live/disable.ts)_
|
|
204
205
|
|
|
205
206
|
## `mux live:enable STREAMNAME`
|
|
206
207
|
|
|
@@ -217,7 +218,7 @@ OPTIONS
|
|
|
217
218
|
-t, --streamId=stream-id [default: stream-id] the type of the provided reference name
|
|
218
219
|
```
|
|
219
220
|
|
|
220
|
-
_See code: [src/commands/live/enable.ts](https://github.com/muxinc/cli/blob/v0.
|
|
221
|
+
_See code: [src/commands/live/enable.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/live/enable.ts)_
|
|
221
222
|
|
|
222
223
|
## `mux plugins`
|
|
223
224
|
|
|
@@ -372,10 +373,36 @@ OPTIONS
|
|
|
372
373
|
-e, --expiresIn=expiresIn [default: 7d] How long the signature is valid for. If no unit is specified,
|
|
373
374
|
milliseconds is assumed.
|
|
374
375
|
|
|
376
|
+
-r, --raw If set, emits only the URL+JWT. Defaults to true for non-TTY.
|
|
377
|
+
|
|
375
378
|
-t, --type=video|thumbnail|gif|storyboard [default: video] What type of token this signature is for.
|
|
376
379
|
```
|
|
377
380
|
|
|
378
|
-
_See code: [src/commands/sign.ts](https://github.com/muxinc/cli/blob/v0.
|
|
381
|
+
_See code: [src/commands/sign.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/sign.ts)_
|
|
382
|
+
|
|
383
|
+
## `mux spaces:sign SPACE-ID`
|
|
384
|
+
|
|
385
|
+
Creates a new signed token for a Mux Space
|
|
386
|
+
|
|
387
|
+
```
|
|
388
|
+
USAGE
|
|
389
|
+
$ mux spaces:sign SPACE-ID
|
|
390
|
+
|
|
391
|
+
ARGUMENTS
|
|
392
|
+
SPACE-ID Space ID for which a token shall be generated.
|
|
393
|
+
|
|
394
|
+
OPTIONS
|
|
395
|
+
-R, --role=role [default: publisher] One of 'publisher' or 'subscriber'.
|
|
396
|
+
|
|
397
|
+
-e, --expiresIn=expiresIn [default: 7d] How long the signature is valid for. If no unit is specified,
|
|
398
|
+
milliseconds is assumed.
|
|
399
|
+
|
|
400
|
+
-p, --participantId=participantId Optional, user-specified participant ID.
|
|
401
|
+
|
|
402
|
+
-r, --raw prints a raw JWT to stdout (default if not tty)
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
_See code: [src/commands/spaces/sign.ts](https://github.com/muxinc/cli/blob/v0.8.0/src/commands/spaces/sign.ts)_
|
|
379
406
|
|
|
380
407
|
## `mux update [CHANNEL]`
|
|
381
408
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Mux, { Video as MuxVideo, Data as MuxData } from '@mux/mux-node';
|
|
1
|
+
import Mux, { Video as MuxVideo, Data as MuxData, JWT as MuxJWT } from '@mux/mux-node';
|
|
2
2
|
import Command from '@oclif/command';
|
|
3
3
|
import { MuxCliConfigV1 } from '../config';
|
|
4
4
|
export declare const MUX_API_BASE_URL = "https://api.mux.com";
|
|
@@ -8,7 +8,7 @@ export default abstract class CommandBase extends Command {
|
|
|
8
8
|
Mux: Mux;
|
|
9
9
|
Video: MuxVideo;
|
|
10
10
|
Data: MuxData;
|
|
11
|
-
JWT:
|
|
12
|
-
readConfigV1(): Promise<MuxCliConfigV1
|
|
11
|
+
JWT: typeof MuxJWT;
|
|
12
|
+
readConfigV1(): Promise<MuxCliConfigV1>;
|
|
13
13
|
init(): Promise<void>;
|
|
14
14
|
}
|
|
@@ -53,6 +53,7 @@ class CommandBase extends command_1.default {
|
|
|
53
53
|
baseUrl: config === null || config === void 0 ? void 0 : config.baseUrl,
|
|
54
54
|
});
|
|
55
55
|
this.Mux = mux;
|
|
56
|
+
this.MuxConfig = config;
|
|
56
57
|
this.Video = this.Mux.Video;
|
|
57
58
|
this.Data = this.Mux.Data;
|
|
58
59
|
this.JWT = mux_node_1.default.JWT;
|
package/lib/commands/sign.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { flags } from '@oclif/command';
|
|
2
1
|
import MuxBase from '../command-bases/base';
|
|
3
2
|
export default class Sign extends MuxBase {
|
|
4
3
|
static description: string;
|
|
@@ -7,9 +6,6 @@ export default class Sign extends MuxBase {
|
|
|
7
6
|
description: string;
|
|
8
7
|
required: boolean;
|
|
9
8
|
}[];
|
|
10
|
-
static flags:
|
|
11
|
-
expiresIn: flags.IOptionFlag<string>;
|
|
12
|
-
type: flags.IOptionFlag<string>;
|
|
13
|
-
};
|
|
9
|
+
static flags: any;
|
|
14
10
|
run(): Promise<void>;
|
|
15
11
|
}
|
package/lib/commands/sign.js
CHANGED
|
@@ -6,24 +6,36 @@ const clipboard = require("clipboardy");
|
|
|
6
6
|
const base_1 = require("../command-bases/base");
|
|
7
7
|
class Sign extends base_1.default {
|
|
8
8
|
async run() {
|
|
9
|
-
const
|
|
9
|
+
const parsed = this.parse(Sign);
|
|
10
|
+
const args = parsed.args;
|
|
11
|
+
const flags = parsed.flags;
|
|
10
12
|
const playbackId = args['playback-id'];
|
|
11
|
-
const options = {
|
|
13
|
+
const options = {
|
|
14
|
+
expiration: flags.expiresIn,
|
|
15
|
+
type: flags.type,
|
|
16
|
+
keyId: this.MuxConfig.signingKeyId,
|
|
17
|
+
keySecret: this.MuxConfig.signingKeySecret,
|
|
18
|
+
};
|
|
12
19
|
const key = this.JWT.sign(playbackId, options);
|
|
13
20
|
const url = `https://stream.mux.com/${playbackId}.m3u8?token=${key}`;
|
|
14
|
-
|
|
21
|
+
if (flags.raw) {
|
|
22
|
+
console.log(url);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
this.log(chalk `
|
|
15
26
|
🔑 {bold.underline Your Mux Signed Token}
|
|
16
27
|
{blue ${key}}
|
|
17
28
|
|
|
18
29
|
🌏 {bold.underline Full URL}
|
|
19
30
|
{green ${url}}
|
|
20
|
-
`);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
31
|
+
`);
|
|
32
|
+
try {
|
|
33
|
+
await clipboard.write(url);
|
|
34
|
+
this.log(`👉 Copied Full URL to your system clipboard`);
|
|
35
|
+
}
|
|
36
|
+
catch (_a) {
|
|
37
|
+
this.error('Unable to copy full url automatically');
|
|
38
|
+
}
|
|
27
39
|
}
|
|
28
40
|
}
|
|
29
41
|
}
|
|
@@ -47,5 +59,10 @@ Sign.flags = {
|
|
|
47
59
|
description: 'What type of token this signature is for.',
|
|
48
60
|
default: 'video',
|
|
49
61
|
options: ['video', 'thumbnail', 'gif', 'storyboard'],
|
|
50
|
-
})
|
|
62
|
+
}),
|
|
63
|
+
raw: command_1.flags.boolean({
|
|
64
|
+
char: 'r',
|
|
65
|
+
description: 'If set, emits only the URL+JWT. Defaults to true for non-TTY.',
|
|
66
|
+
default: !process.stdin.isTTY,
|
|
67
|
+
}),
|
|
51
68
|
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import MuxBase from '../../command-bases/base';
|
|
2
|
+
export default class SignSpace extends MuxBase {
|
|
3
|
+
static description: string;
|
|
4
|
+
static args: {
|
|
5
|
+
name: string;
|
|
6
|
+
description: string;
|
|
7
|
+
required: boolean;
|
|
8
|
+
}[];
|
|
9
|
+
static flags: any;
|
|
10
|
+
run(): Promise<void>;
|
|
11
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const command_1 = require("@oclif/command");
|
|
4
|
+
const JWT = require("jsonwebtoken");
|
|
5
|
+
const chalk = require("chalk");
|
|
6
|
+
const clipboard = require("clipboardy");
|
|
7
|
+
const base_1 = require("../../command-bases/base");
|
|
8
|
+
class SignSpace extends base_1.default {
|
|
9
|
+
async run() {
|
|
10
|
+
const parsed = this.parse(SignSpace);
|
|
11
|
+
const args = parsed.args;
|
|
12
|
+
const flags = parsed.flags;
|
|
13
|
+
const signingKeySecret = this.MuxConfig.signingKeySecret;
|
|
14
|
+
if (!signingKeySecret) {
|
|
15
|
+
throw new Error("No signing key found. Re-run `mux init` and generate one!");
|
|
16
|
+
}
|
|
17
|
+
// TODO: replace with mux-node-sdk signing when available
|
|
18
|
+
const payload = {
|
|
19
|
+
role: flags.role,
|
|
20
|
+
participant_id: flags.participantId,
|
|
21
|
+
kid: this.MuxConfig.signingKeyId,
|
|
22
|
+
};
|
|
23
|
+
const jwtOptions = {
|
|
24
|
+
audience: 'rt',
|
|
25
|
+
subject: args['space-id'],
|
|
26
|
+
algorithm: 'RS256',
|
|
27
|
+
noTimestamp: true,
|
|
28
|
+
expiresIn: flags.expiresIn,
|
|
29
|
+
};
|
|
30
|
+
const key = Buffer.from(signingKeySecret, 'base64');
|
|
31
|
+
const jwt = JWT.sign(payload, key, jwtOptions);
|
|
32
|
+
if (flags.raw) {
|
|
33
|
+
console.log(jwt);
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
this.log(chalk `
|
|
37
|
+
🔑 Your JWT for Mux Spaces
|
|
38
|
+
{cyan ${jwt}}
|
|
39
|
+
`);
|
|
40
|
+
try {
|
|
41
|
+
await clipboard.write(jwt);
|
|
42
|
+
this.log(`👉 Copied your JWT to your system clipboard`);
|
|
43
|
+
}
|
|
44
|
+
catch (_a) {
|
|
45
|
+
this.error('Unable to copy JWT automatically');
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
exports.default = SignSpace;
|
|
51
|
+
SignSpace.description = 'Creates a new signed token for a Mux Space';
|
|
52
|
+
SignSpace.args = [
|
|
53
|
+
{
|
|
54
|
+
name: 'space-id',
|
|
55
|
+
description: 'Space ID for which a token shall be generated.',
|
|
56
|
+
required: true,
|
|
57
|
+
},
|
|
58
|
+
];
|
|
59
|
+
SignSpace.flags = {
|
|
60
|
+
raw: command_1.flags.boolean({
|
|
61
|
+
char: 'r',
|
|
62
|
+
description: "prints a raw JWT to stdout (default if not tty)",
|
|
63
|
+
default: !process.stdin.isTTY,
|
|
64
|
+
}),
|
|
65
|
+
participantId: command_1.flags.string({
|
|
66
|
+
char: 'p',
|
|
67
|
+
description: 'Optional, user-specified participant ID.',
|
|
68
|
+
}),
|
|
69
|
+
role: command_1.flags.string({
|
|
70
|
+
char: 'R',
|
|
71
|
+
description: 'One of \'publisher\' or \'subscriber\'.',
|
|
72
|
+
default: 'publisher',
|
|
73
|
+
}),
|
|
74
|
+
expiresIn: command_1.flags.string({
|
|
75
|
+
char: 'e',
|
|
76
|
+
description: 'How long the signature is valid for. If no unit is specified, milliseconds is assumed.',
|
|
77
|
+
default: '7d',
|
|
78
|
+
}),
|
|
79
|
+
};
|
package/oclif.manifest.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":"0.
|
|
1
|
+
{"version":"0.8.0","commands":{"init":{"id":"init","description":"set up a user-level config","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"force":{"name":"force","type":"boolean","char":"f","description":"Will initialize a new file even if one already exists.","allowNo":false}},"args":[{"name":"envFile","description":"path to a Mux access token .env file","required":false}]},"sign":{"id":"sign","description":"Creates a new signed URL token for a playback ID","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"expiresIn":{"name":"expiresIn","type":"option","char":"e","description":"How long the signature is valid for. If no unit is specified, milliseconds is assumed.","default":"7d"},"type":{"name":"type","type":"option","char":"t","description":"What type of token this signature is for.","options":["video","thumbnail","gif","storyboard"],"default":"video"},"raw":{"name":"raw","type":"boolean","char":"r","description":"If set, emits only the URL+JWT. Defaults to true for non-TTY.","allowNo":false}},"args":[{"name":"playback-id","description":"Playback ID to create a signed URL token for.","required":true}]},"assets:create":{"id":"assets:create","description":"Create a new asset in Mux using a file that's already available online","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","description":"add a private playback policy to the created asset","allowNo":false}},"args":[{"name":"input","description":"input URL for the file you'd like to create this asset from","required":true}]},"assets:upload":{"id":"assets:upload","description":"Create a new asset in Mux via a local file","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"private":{"name":"private","type":"boolean","char":"p","allowNo":false},"filter":{"name":"filter","type":"option","char":"f","description":"regex that filters the selected destination if the provided path is a folder"},"concurrent":{"name":"concurrent","type":"option","char":"c","description":"max number of files to upload at once","default":3}},"args":[{"name":"path","description":"local path for the file (or folder) you'd like to upload","required":true}]},"live:complete":{"id":"live:complete","description":"Signal to Mux that a live stream has concluded and should be closed.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"},"disableAfterCompletion":{"name":"disableAfterCompletion","type":"boolean","char":"d","description":"If set, disables the stream upon completion.","allowNo":false}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:disable":{"id":"live:disable","description":"Disables a live stream and prevents encoders from streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"live:enable":{"id":"live:enable","description":"Enables a live stream, allowing encoders to streaming to it.","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"streamId":{"name":"streamId","type":"option","char":"t","description":"the type of the provided reference name","options":["stream-id"],"default":"stream-id"}},"args":[{"name":"streamName","description":"the name (coupled with --reference-type) to look up in Mux to yield this livestream","required":true}]},"spaces:sign":{"id":"spaces:sign","description":"Creates a new signed token for a Mux Space","pluginName":"@mux/cli","pluginType":"core","aliases":[],"flags":{"raw":{"name":"raw","type":"boolean","char":"r","description":"prints a raw JWT to stdout (default if not tty)","allowNo":false},"participantId":{"name":"participantId","type":"option","char":"p","description":"Optional, user-specified participant ID."},"role":{"name":"role","type":"option","char":"R","description":"One of 'publisher' or 'subscriber'.","default":"publisher"},"expiresIn":{"name":"expiresIn","type":"option","char":"e","description":"How long the signature is valid for. If no unit is specified, milliseconds is assumed.","default":"7d"}},"args":[{"name":"space-id","description":"Space ID for which a token shall be generated.","required":true}]}}}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mux/cli",
|
|
3
3
|
"description": "Your friendly neighborhood Mux CLI tool!",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.8.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Mux",
|
|
7
7
|
"email": "devex@mux.com",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"dotenv": "^8.2.0",
|
|
32
32
|
"fs-extra": "^10.0.0",
|
|
33
33
|
"inquirer": "^8.2.0",
|
|
34
|
+
"jsonwebtoken": "^8.5.1",
|
|
34
35
|
"listr": "^0.14.3",
|
|
35
36
|
"request": "^2.88.2",
|
|
36
37
|
"runtypes": "^6.5.0",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"@types/chai": "^4.3.0",
|
|
44
45
|
"@types/fs-extra": "^9.0.13",
|
|
45
46
|
"@types/inquirer": "^8.1.3",
|
|
47
|
+
"@types/jsonwebtoken": "^8.5.8",
|
|
46
48
|
"@types/listr": "^0.14.4",
|
|
47
49
|
"@types/mocha": "^9.1.0",
|
|
48
50
|
"@types/node": "^17.0.12",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Mux, { Video as MuxVideo, Data as MuxData } from '@mux/mux-node';
|
|
1
|
+
import Mux, { Video as MuxVideo, Data as MuxData, JWT as MuxJWT } from '@mux/mux-node';
|
|
2
2
|
import Command from '@oclif/command';
|
|
3
3
|
import * as chalk from 'chalk';
|
|
4
4
|
import * as fs from 'fs-extra';
|
|
@@ -15,9 +15,9 @@ export default abstract class CommandBase extends Command {
|
|
|
15
15
|
Mux!: Mux;
|
|
16
16
|
Video!: MuxVideo;
|
|
17
17
|
Data!: MuxData;
|
|
18
|
-
JWT
|
|
18
|
+
JWT!: typeof MuxJWT;
|
|
19
19
|
|
|
20
|
-
async readConfigV1(): Promise<MuxCliConfigV1
|
|
20
|
+
async readConfigV1(): Promise<MuxCliConfigV1> {
|
|
21
21
|
const configAlreadyExists = await fs.pathExists(this.configFile);
|
|
22
22
|
try {
|
|
23
23
|
const configRaw =
|
|
@@ -64,6 +64,7 @@ export default abstract class CommandBase extends Command {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
this.Mux = mux;
|
|
67
|
+
this.MuxConfig = config;
|
|
67
68
|
this.Video = this.Mux.Video;
|
|
68
69
|
this.Data = this.Mux.Data;
|
|
69
70
|
this.JWT = Mux.JWT;
|
package/src/commands/sign.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { flags } from '@oclif/command';
|
|
2
|
+
// this is a load-bearing unused import due to oclif type issues
|
|
3
|
+
import { IOptionFlag, IBooleanFlag } from '@oclif/parser/lib/flags';
|
|
2
4
|
import * as chalk from 'chalk';
|
|
3
5
|
import * as clipboard from 'clipboardy';
|
|
4
6
|
|
|
@@ -15,7 +17,7 @@ export default class Sign extends MuxBase {
|
|
|
15
17
|
},
|
|
16
18
|
];
|
|
17
19
|
|
|
18
|
-
static flags = {
|
|
20
|
+
static flags: any = {
|
|
19
21
|
expiresIn: flags.string({
|
|
20
22
|
char: 'e',
|
|
21
23
|
description: 'How long the signature is valid for. If no unit is specified, milliseconds is assumed.',
|
|
@@ -26,32 +28,49 @@ export default class Sign extends MuxBase {
|
|
|
26
28
|
description: 'What type of token this signature is for.',
|
|
27
29
|
default: 'video',
|
|
28
30
|
options: ['video', 'thumbnail', 'gif', 'storyboard'],
|
|
29
|
-
})
|
|
31
|
+
}),
|
|
32
|
+
raw: flags.boolean({
|
|
33
|
+
char: 'r',
|
|
34
|
+
description: 'If set, emits only the URL+JWT. Defaults to true for non-TTY.',
|
|
35
|
+
default: !process.stdin.isTTY,
|
|
36
|
+
}),
|
|
30
37
|
};
|
|
31
38
|
|
|
32
39
|
async run() {
|
|
33
|
-
const
|
|
40
|
+
const parsed = this.parse(Sign);
|
|
41
|
+
const args = parsed.args;
|
|
42
|
+
const flags = parsed.flags as any;
|
|
43
|
+
|
|
34
44
|
const playbackId = args['playback-id'];
|
|
35
45
|
|
|
36
|
-
const options = {
|
|
46
|
+
const options = {
|
|
47
|
+
expiration: flags.expiresIn,
|
|
48
|
+
type: flags.type as any, // TODO: is better checked in SDK, but this is ugly.
|
|
49
|
+
keyId: this.MuxConfig.signingKeyId,
|
|
50
|
+
keySecret: this.MuxConfig.signingKeySecret,
|
|
51
|
+
};
|
|
37
52
|
const key = this.JWT.sign(playbackId, options);
|
|
38
53
|
const url = `https://stream.mux.com/${playbackId}.m3u8?token=${key}`;
|
|
39
54
|
|
|
40
|
-
|
|
41
|
-
|
|
55
|
+
if (flags.raw) {
|
|
56
|
+
console.log(url);
|
|
57
|
+
} else {
|
|
58
|
+
this.log(
|
|
59
|
+
chalk`
|
|
42
60
|
🔑 {bold.underline Your Mux Signed Token}
|
|
43
61
|
{blue ${key}}
|
|
44
62
|
|
|
45
63
|
🌏 {bold.underline Full URL}
|
|
46
64
|
{green ${url}}
|
|
47
|
-
`
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
65
|
+
`
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await clipboard.write(url);
|
|
70
|
+
this.log(`👉 Copied Full URL to your system clipboard`);
|
|
71
|
+
} catch {
|
|
72
|
+
this.error('Unable to copy full url automatically');
|
|
73
|
+
}
|
|
55
74
|
}
|
|
56
75
|
}
|
|
57
76
|
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { flags } from '@oclif/command';
|
|
2
|
+
// this is a load-bearing unused import due to oclif type issues
|
|
3
|
+
import { IOptionFlag, IBooleanFlag } from '@oclif/parser/lib/flags';
|
|
4
|
+
import * as JWT from 'jsonwebtoken';
|
|
5
|
+
import * as chalk from 'chalk';
|
|
6
|
+
import * as clipboard from 'clipboardy';
|
|
7
|
+
|
|
8
|
+
import MuxBase from '../../command-bases/base';
|
|
9
|
+
|
|
10
|
+
export default class SignSpace extends MuxBase {
|
|
11
|
+
static description = 'Creates a new signed token for a Mux Space';
|
|
12
|
+
|
|
13
|
+
static args = [
|
|
14
|
+
{
|
|
15
|
+
name: 'space-id',
|
|
16
|
+
description: 'Space ID for which a token shall be generated.',
|
|
17
|
+
required: true,
|
|
18
|
+
},
|
|
19
|
+
];
|
|
20
|
+
|
|
21
|
+
static flags: any = {
|
|
22
|
+
raw: flags.boolean({
|
|
23
|
+
char: 'r',
|
|
24
|
+
description: "prints a raw JWT to stdout (default if not tty)",
|
|
25
|
+
default: !process.stdin.isTTY,
|
|
26
|
+
}),
|
|
27
|
+
participantId: flags.string({
|
|
28
|
+
char: 'p',
|
|
29
|
+
description: 'Optional, user-specified participant ID.',
|
|
30
|
+
}),
|
|
31
|
+
role: flags.string({
|
|
32
|
+
char: 'R',
|
|
33
|
+
description: 'One of \'publisher\' or \'subscriber\'.',
|
|
34
|
+
default: 'publisher',
|
|
35
|
+
}),
|
|
36
|
+
expiresIn: flags.string({
|
|
37
|
+
char: 'e',
|
|
38
|
+
description: 'How long the signature is valid for. If no unit is specified, milliseconds is assumed.',
|
|
39
|
+
default: '7d',
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
async run() {
|
|
44
|
+
const parsed = this.parse(SignSpace);
|
|
45
|
+
const args = parsed.args;
|
|
46
|
+
const flags = parsed.flags as any;
|
|
47
|
+
|
|
48
|
+
const signingKeySecret = this.MuxConfig.signingKeySecret;
|
|
49
|
+
if (!signingKeySecret) {
|
|
50
|
+
throw new Error("No signing key found. Re-run `mux init` and generate one!");
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// TODO: replace with mux-node-sdk signing when available
|
|
54
|
+
const payload = {
|
|
55
|
+
role: flags.role,
|
|
56
|
+
participant_id: flags.participantId,
|
|
57
|
+
kid: this.MuxConfig.signingKeyId,
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const jwtOptions: JWT.SignOptions = {
|
|
61
|
+
audience: 'rt',
|
|
62
|
+
subject: args['space-id'],
|
|
63
|
+
algorithm: 'RS256',
|
|
64
|
+
noTimestamp: true,
|
|
65
|
+
expiresIn: flags.expiresIn,
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const key = Buffer.from(signingKeySecret, 'base64');
|
|
69
|
+
const jwt = JWT.sign(payload, key, jwtOptions);
|
|
70
|
+
|
|
71
|
+
if (flags.raw) {
|
|
72
|
+
console.log(jwt);
|
|
73
|
+
} else {
|
|
74
|
+
|
|
75
|
+
this.log(
|
|
76
|
+
chalk`
|
|
77
|
+
🔑 Your JWT for Mux Spaces
|
|
78
|
+
{cyan ${jwt}}
|
|
79
|
+
`
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
try {
|
|
83
|
+
await clipboard.write(jwt);
|
|
84
|
+
this.log(`👉 Copied your JWT to your system clipboard`);
|
|
85
|
+
} catch {
|
|
86
|
+
this.error('Unable to copy JWT automatically');
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
package/yarn.lock
CHANGED
|
@@ -899,6 +899,13 @@
|
|
|
899
899
|
"@types/through" "*"
|
|
900
900
|
rxjs "^7.2.0"
|
|
901
901
|
|
|
902
|
+
"@types/jsonwebtoken@^8.5.8":
|
|
903
|
+
version "8.5.8"
|
|
904
|
+
resolved "https://registry.yarnpkg.com/@types/jsonwebtoken/-/jsonwebtoken-8.5.8.tgz#01b39711eb844777b7af1d1f2b4cf22fda1c0c44"
|
|
905
|
+
integrity sha512-zm6xBQpFDIDM6o9r6HSgDeIcLy82TKWctCXEPbJJcXb5AKmi5BNNdLXneixK4lplX3PqIVcwLBCGE/kAGnlD4A==
|
|
906
|
+
dependencies:
|
|
907
|
+
"@types/node" "*"
|
|
908
|
+
|
|
902
909
|
"@types/listr@^0.14.4":
|
|
903
910
|
version "0.14.4"
|
|
904
911
|
resolved "https://registry.yarnpkg.com/@types/listr/-/listr-0.14.4.tgz#6ba2a4206615cf80d79d10f9ba9701c303cd57b6"
|