@knocklabs/cli 0.1.23 → 0.2.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 +128 -102
- package/bin/dev.js +4 -4
- package/dist/commands/knock.js +3 -0
- package/dist/commands/login.js +50 -0
- package/dist/commands/logout.js +48 -0
- package/dist/commands/whoami.js +6 -2
- package/dist/lib/api-v1.js +13 -4
- package/dist/lib/auth.js +256 -0
- package/dist/lib/base-command.js +85 -12
- package/dist/lib/helpers/browser.js +25 -0
- package/dist/lib/types.js +4 -0
- package/dist/lib/urls.js +32 -0
- package/dist/lib/user-config.js +69 -31
- package/oclif.manifest.json +220 -146
- package/package.json +7 -6
package/bin/dev.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node_modules/.bin/ts-node
|
|
2
2
|
// eslint-disable-next-line node/shebang, unicorn/prefer-top-level-await
|
|
3
|
-
|
|
4
|
-
const oclif = await import(
|
|
5
|
-
await oclif.execute({development: true, dir: __dirname})
|
|
6
|
-
})()
|
|
3
|
+
(async () => {
|
|
4
|
+
const oclif = await import("@oclif/core");
|
|
5
|
+
await oclif.execute({ development: true, dir: __dirname });
|
|
6
|
+
})();
|
package/dist/commands/knock.js
CHANGED
|
@@ -112,6 +112,9 @@ class Knock extends _basecommand.default {
|
|
|
112
112
|
this.log("");
|
|
113
113
|
this.log("Thank you for using Knock, and have a nice day! 🙂");
|
|
114
114
|
}
|
|
115
|
+
constructor(...args){
|
|
116
|
+
super(...args), _define_property(this, "requiresAuth", false);
|
|
117
|
+
}
|
|
115
118
|
}
|
|
116
119
|
// Because, it's a secret :)
|
|
117
120
|
_define_property(Knock, "hidden", true);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Login;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _auth = /*#__PURE__*/ _interop_require_default(require("../lib/auth"));
|
|
12
|
+
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
|
|
13
|
+
const _ux = require("../lib/helpers/ux");
|
|
14
|
+
function _define_property(obj, key, value) {
|
|
15
|
+
if (key in obj) {
|
|
16
|
+
Object.defineProperty(obj, key, {
|
|
17
|
+
value: value,
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true
|
|
21
|
+
});
|
|
22
|
+
} else {
|
|
23
|
+
obj[key] = value;
|
|
24
|
+
}
|
|
25
|
+
return obj;
|
|
26
|
+
}
|
|
27
|
+
function _interop_require_default(obj) {
|
|
28
|
+
return obj && obj.__esModule ? obj : {
|
|
29
|
+
default: obj
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
class Login extends _basecommand.default {
|
|
33
|
+
async run() {
|
|
34
|
+
const { flags } = this.props;
|
|
35
|
+
if (flags["service-token"]) {
|
|
36
|
+
this.log("Service token provided, skipping login.");
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
_ux.spinner.start("‣ Authenticating with Knock...");
|
|
40
|
+
const resp = await _auth.default.waitForAccessToken(this.sessionContext.dashboardOrigin, this.sessionContext.authOrigin);
|
|
41
|
+
_ux.spinner.stop();
|
|
42
|
+
await this.configStore.set({
|
|
43
|
+
userSession: resp
|
|
44
|
+
});
|
|
45
|
+
this.log("‣ Successfully authenticated with Knock.");
|
|
46
|
+
}
|
|
47
|
+
constructor(...args){
|
|
48
|
+
super(...args), _define_property(this, "requiresAuth", false);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "default", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return Logout;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _basecommand = /*#__PURE__*/ _interop_require_default(require("../lib/base-command"));
|
|
12
|
+
const _ux = require("../lib/helpers/ux");
|
|
13
|
+
function _define_property(obj, key, value) {
|
|
14
|
+
if (key in obj) {
|
|
15
|
+
Object.defineProperty(obj, key, {
|
|
16
|
+
value: value,
|
|
17
|
+
enumerable: true,
|
|
18
|
+
configurable: true,
|
|
19
|
+
writable: true
|
|
20
|
+
});
|
|
21
|
+
} else {
|
|
22
|
+
obj[key] = value;
|
|
23
|
+
}
|
|
24
|
+
return obj;
|
|
25
|
+
}
|
|
26
|
+
function _interop_require_default(obj) {
|
|
27
|
+
return obj && obj.__esModule ? obj : {
|
|
28
|
+
default: obj
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
class Logout extends _basecommand.default {
|
|
32
|
+
async run() {
|
|
33
|
+
const { flags } = this.props;
|
|
34
|
+
if (flags["service-token"]) {
|
|
35
|
+
this.log("Service token provided, skipping logout.");
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
_ux.spinner.start("‣ Logging out of Knock...");
|
|
39
|
+
await this.configStore.set({
|
|
40
|
+
userSession: undefined
|
|
41
|
+
});
|
|
42
|
+
_ux.spinner.stop();
|
|
43
|
+
this.log("‣ Successfully logged out of Knock. See you around.");
|
|
44
|
+
}
|
|
45
|
+
constructor(...args){
|
|
46
|
+
super(...args), _define_property(this, "requiresAuth", false);
|
|
47
|
+
}
|
|
48
|
+
}
|
package/dist/commands/whoami.js
CHANGED
|
@@ -34,10 +34,14 @@ class Whoami extends _basecommand.default {
|
|
|
34
34
|
const resp = await (0, _request.withSpinner)(()=>this.apiV1.whoami());
|
|
35
35
|
const { flags } = this.props;
|
|
36
36
|
if (flags.json) return resp.data;
|
|
37
|
-
this.log(`‣ Successfully
|
|
38
|
-
|
|
37
|
+
this.log(`‣ Successfully authenticated:`);
|
|
38
|
+
let info = [];
|
|
39
|
+
info = resp.data.service_token_name ? [
|
|
39
40
|
`Account name: ${resp.data.account_name}`,
|
|
40
41
|
`Service token name: ${resp.data.service_token_name}`
|
|
42
|
+
] : [
|
|
43
|
+
`Account name: ${resp.data.account_name}`,
|
|
44
|
+
`User ID: ${resp.data.user_id}`
|
|
41
45
|
];
|
|
42
46
|
this.log((0, _string.indentString)(info.join("\n"), 4));
|
|
43
47
|
}
|
package/dist/lib/api-v1.js
CHANGED
|
@@ -29,9 +29,11 @@ function _interop_require_default(obj) {
|
|
|
29
29
|
default: obj
|
|
30
30
|
};
|
|
31
31
|
}
|
|
32
|
-
const DEFAULT_ORIGIN = "https://control.knock.app";
|
|
33
32
|
const API_VERSION = "v1";
|
|
34
33
|
class ApiV1 {
|
|
34
|
+
getToken(sessionContext) {
|
|
35
|
+
return sessionContext.session ? sessionContext.session.accessToken : sessionContext.token;
|
|
36
|
+
}
|
|
35
37
|
async ping() {
|
|
36
38
|
return this.get("/ping");
|
|
37
39
|
}
|
|
@@ -401,13 +403,20 @@ class ApiV1 {
|
|
|
401
403
|
async put(subpath, data, config) {
|
|
402
404
|
return this.client.put(`/${API_VERSION}` + subpath, data, config);
|
|
403
405
|
}
|
|
404
|
-
constructor(
|
|
406
|
+
constructor(sessionContext, config){
|
|
407
|
+
var _sessionContext_session;
|
|
405
408
|
_define_property(this, "client", void 0);
|
|
406
|
-
const baseURL =
|
|
409
|
+
const baseURL = sessionContext.apiOrigin;
|
|
410
|
+
const token = this.getToken(sessionContext);
|
|
411
|
+
var _sessionContext_session_clientId;
|
|
407
412
|
this.client = _axios.default.create({
|
|
408
413
|
baseURL,
|
|
409
414
|
headers: {
|
|
410
|
-
|
|
415
|
+
// Used to authenticate the request to the API.
|
|
416
|
+
Authorization: `Bearer ${token}`,
|
|
417
|
+
// Used in conjunction with the JWT access token, to allow the OAuth server to
|
|
418
|
+
// verify the client ID of the OAuth client that issued the access token.
|
|
419
|
+
"x-knock-client-id": (_sessionContext_session_clientId = (_sessionContext_session = sessionContext.session) === null || _sessionContext_session === void 0 ? void 0 : _sessionContext_session.clientId) !== null && _sessionContext_session_clientId !== void 0 ? _sessionContext_session_clientId : undefined,
|
|
411
420
|
"User-Agent": `${config.userAgent}`
|
|
412
421
|
},
|
|
413
422
|
// Don't reject the promise based on a response status code.
|
package/dist/lib/auth.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get default () {
|
|
13
|
+
return _default;
|
|
14
|
+
},
|
|
15
|
+
get exchangeCodeForToken () {
|
|
16
|
+
return exchangeCodeForToken;
|
|
17
|
+
},
|
|
18
|
+
get getOAuthServerUrls () {
|
|
19
|
+
return getOAuthServerUrls;
|
|
20
|
+
},
|
|
21
|
+
get refreshAccessToken () {
|
|
22
|
+
return refreshAccessToken;
|
|
23
|
+
},
|
|
24
|
+
get registerClient () {
|
|
25
|
+
return registerClient;
|
|
26
|
+
},
|
|
27
|
+
get waitForAccessToken () {
|
|
28
|
+
return waitForAccessToken;
|
|
29
|
+
}
|
|
30
|
+
});
|
|
31
|
+
const _nodecrypto = /*#__PURE__*/ _interop_require_default(require("node:crypto"));
|
|
32
|
+
const _nodehttp = /*#__PURE__*/ _interop_require_default(require("node:http"));
|
|
33
|
+
const _browser = require("./helpers/browser");
|
|
34
|
+
const _urls = require("./urls");
|
|
35
|
+
function _interop_require_default(obj) {
|
|
36
|
+
return obj && obj.__esModule ? obj : {
|
|
37
|
+
default: obj
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const DEFAULT_TIMEOUT = 5000;
|
|
41
|
+
function createChallenge() {
|
|
42
|
+
// PKCE code verifier and challenge
|
|
43
|
+
const codeVerifier = _nodecrypto.default.randomBytes(32).toString("base64url");
|
|
44
|
+
const codeChallenge = _nodecrypto.default.createHash("sha256").update(codeVerifier).digest("base64").replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
|
|
45
|
+
const state = _nodecrypto.default.randomUUID();
|
|
46
|
+
return {
|
|
47
|
+
codeVerifier,
|
|
48
|
+
codeChallenge,
|
|
49
|
+
state
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
async function getOAuthServerUrls(apiUrl) {
|
|
53
|
+
const { protocol, host } = new URL(apiUrl);
|
|
54
|
+
const wellKnownUrl = `${protocol}//${host}/.well-known/oauth-authorization-server`;
|
|
55
|
+
const response = await fetch(wellKnownUrl, {
|
|
56
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT)
|
|
57
|
+
});
|
|
58
|
+
if (response.ok) {
|
|
59
|
+
const data = await response.json();
|
|
60
|
+
return {
|
|
61
|
+
registrationEndpoint: data.registration_endpoint,
|
|
62
|
+
authorizationEndpoint: data.authorization_endpoint,
|
|
63
|
+
tokenEndpoint: data.token_endpoint,
|
|
64
|
+
issuer: data.issuer
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
throw new Error("Failed to fetch OAuth server metadata");
|
|
68
|
+
}
|
|
69
|
+
async function registerClient(registrationEndpoint, redirectUri) {
|
|
70
|
+
const registrationResponse = await fetch(registrationEndpoint, {
|
|
71
|
+
method: "POST",
|
|
72
|
+
headers: {
|
|
73
|
+
"Content-Type": "application/json"
|
|
74
|
+
},
|
|
75
|
+
body: JSON.stringify({
|
|
76
|
+
client_name: "Knock CLI",
|
|
77
|
+
token_endpoint_auth_method: "none",
|
|
78
|
+
grant_types: [
|
|
79
|
+
"authorization_code"
|
|
80
|
+
],
|
|
81
|
+
response_types: [
|
|
82
|
+
"code"
|
|
83
|
+
],
|
|
84
|
+
redirect_uris: [
|
|
85
|
+
redirectUri
|
|
86
|
+
]
|
|
87
|
+
}),
|
|
88
|
+
signal: AbortSignal.timeout(DEFAULT_TIMEOUT)
|
|
89
|
+
});
|
|
90
|
+
if (!registrationResponse.ok) {
|
|
91
|
+
console.log(await registrationResponse.json());
|
|
92
|
+
throw new Error(`Could not register client with OAuth server`);
|
|
93
|
+
}
|
|
94
|
+
const registrationData = await registrationResponse.json();
|
|
95
|
+
return registrationData.client_id;
|
|
96
|
+
}
|
|
97
|
+
async function parseTokenResponse(response) {
|
|
98
|
+
const data = await response.json();
|
|
99
|
+
return {
|
|
100
|
+
accessToken: data.access_token,
|
|
101
|
+
refreshToken: data.refresh_token,
|
|
102
|
+
idToken: data.id_token,
|
|
103
|
+
expiresAt: new Date(Date.now() + data.expires_in * 1000)
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
async function exchangeCodeForToken(params) {
|
|
107
|
+
const response = await fetch(params.tokenEndpoint, {
|
|
108
|
+
method: "POST",
|
|
109
|
+
headers: {
|
|
110
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
111
|
+
},
|
|
112
|
+
body: new URLSearchParams({
|
|
113
|
+
grant_type: "authorization_code",
|
|
114
|
+
client_id: params.clientId,
|
|
115
|
+
code: params.code,
|
|
116
|
+
code_verifier: params.codeVerifier,
|
|
117
|
+
redirect_uri: params.redirectUri
|
|
118
|
+
}),
|
|
119
|
+
signal: AbortSignal.timeout(5000)
|
|
120
|
+
});
|
|
121
|
+
if (!response.ok) {
|
|
122
|
+
let errorDescription;
|
|
123
|
+
try {
|
|
124
|
+
const errorResponse = await response.json();
|
|
125
|
+
errorDescription = errorResponse.error_description || errorResponse.error;
|
|
126
|
+
} catch {
|
|
127
|
+
// ignore
|
|
128
|
+
}
|
|
129
|
+
return {
|
|
130
|
+
error: errorDescription !== null && errorDescription !== void 0 ? errorDescription : "unknown error"
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
...await parseTokenResponse(response),
|
|
135
|
+
clientId: params.clientId
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function refreshAccessToken(params) {
|
|
139
|
+
const { tokenEndpoint } = await getOAuthServerUrls(params.authUrl);
|
|
140
|
+
const response = await fetch(tokenEndpoint, {
|
|
141
|
+
method: "POST",
|
|
142
|
+
headers: {
|
|
143
|
+
"Content-Type": "application/x-www-form-urlencoded"
|
|
144
|
+
},
|
|
145
|
+
body: new URLSearchParams({
|
|
146
|
+
grant_type: "refresh_token",
|
|
147
|
+
client_id: params.clientId,
|
|
148
|
+
refresh_token: params.refreshToken
|
|
149
|
+
}),
|
|
150
|
+
signal: AbortSignal.timeout(5000)
|
|
151
|
+
});
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
throw new Error("Failed to refresh access token");
|
|
154
|
+
}
|
|
155
|
+
return {
|
|
156
|
+
...await parseTokenResponse(response),
|
|
157
|
+
clientId: params.clientId
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
async function waitForAccessToken(dashboardUrl, authUrl) {
|
|
161
|
+
const { authorizationEndpoint, tokenEndpoint, registrationEndpoint } = await getOAuthServerUrls(authUrl);
|
|
162
|
+
let resolve;
|
|
163
|
+
let reject;
|
|
164
|
+
const promise = new Promise((res, rej)=>{
|
|
165
|
+
resolve = res;
|
|
166
|
+
reject = rej;
|
|
167
|
+
});
|
|
168
|
+
const { codeVerifier, codeChallenge, state } = createChallenge();
|
|
169
|
+
const timeout = setTimeout(()=>{
|
|
170
|
+
cleanupAndReject(`authentication timed out after ${DEFAULT_TIMEOUT / 1000} seconds`);
|
|
171
|
+
}, 60000);
|
|
172
|
+
function cleanupAndReject(message) {
|
|
173
|
+
cleanup();
|
|
174
|
+
reject(new Error(`Could not authenticate: ${message}`));
|
|
175
|
+
}
|
|
176
|
+
function cleanup() {
|
|
177
|
+
clearTimeout(timeout);
|
|
178
|
+
server.close();
|
|
179
|
+
server.closeAllConnections();
|
|
180
|
+
}
|
|
181
|
+
const server = _nodehttp.default.createServer();
|
|
182
|
+
server.listen();
|
|
183
|
+
const address = server.address();
|
|
184
|
+
if (address === null || typeof address !== "object") {
|
|
185
|
+
throw new Error("Could not start server");
|
|
186
|
+
}
|
|
187
|
+
const callbackPath = "/oauth_callback";
|
|
188
|
+
const redirectUri = `http://localhost:${address.port}${callbackPath}`;
|
|
189
|
+
const clientId = await registerClient(registrationEndpoint, redirectUri);
|
|
190
|
+
const params = {
|
|
191
|
+
response_type: "code",
|
|
192
|
+
client_id: clientId,
|
|
193
|
+
redirect_uri: redirectUri,
|
|
194
|
+
state,
|
|
195
|
+
code_challenge: codeChallenge,
|
|
196
|
+
code_challenge_method: "S256",
|
|
197
|
+
scope: "openid email offline_access"
|
|
198
|
+
};
|
|
199
|
+
const browserUrl = `${authorizationEndpoint}?${new URLSearchParams(params).toString()}`;
|
|
200
|
+
server.on("request", async (req, res)=>{
|
|
201
|
+
if (!clientId || !redirectUri) {
|
|
202
|
+
res.writeHead(500).end("Something went wrong");
|
|
203
|
+
cleanupAndReject("something went wrong");
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
var _req_url;
|
|
207
|
+
const url = new URL((_req_url = req.url) !== null && _req_url !== void 0 ? _req_url : "/", "http://127.0.0.1");
|
|
208
|
+
if (url.pathname !== callbackPath) {
|
|
209
|
+
res.writeHead(404).end("Invalid path");
|
|
210
|
+
cleanupAndReject("invalid path");
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const error = url.searchParams.get("error");
|
|
214
|
+
if (error) {
|
|
215
|
+
res.writeHead(400).end("Could not authenticate");
|
|
216
|
+
const errorDescription = url.searchParams.get("error_description");
|
|
217
|
+
cleanupAndReject(`${errorDescription || error} `);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
const code = url.searchParams.get("code");
|
|
221
|
+
if (!code) {
|
|
222
|
+
res.writeHead(400).end("Could not authenticate");
|
|
223
|
+
cleanupAndReject("no code provided");
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
const response = await exchangeCodeForToken({
|
|
227
|
+
tokenEndpoint,
|
|
228
|
+
clientId,
|
|
229
|
+
code,
|
|
230
|
+
codeVerifier,
|
|
231
|
+
redirectUri
|
|
232
|
+
});
|
|
233
|
+
if ("error" in response) {
|
|
234
|
+
res.writeHead(302, {
|
|
235
|
+
location: (0, _urls.authErrorUrl)(dashboardUrl, "Could not authenticate: unable to fetch access token")
|
|
236
|
+
}).end("Could not authenticate");
|
|
237
|
+
cleanupAndReject(JSON.stringify(response.error));
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
res.writeHead(302, {
|
|
241
|
+
location: (0, _urls.authSuccessUrl)(dashboardUrl)
|
|
242
|
+
}).end("Authentication successful");
|
|
243
|
+
cleanup();
|
|
244
|
+
resolve({
|
|
245
|
+
...response,
|
|
246
|
+
clientId
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
console.log(`Opened web browser to facilitate auth: ${browserUrl}`);
|
|
250
|
+
_browser.browser.openUrl(browserUrl);
|
|
251
|
+
return promise;
|
|
252
|
+
}
|
|
253
|
+
const _default = {
|
|
254
|
+
waitForAccessToken,
|
|
255
|
+
refreshAccessToken
|
|
256
|
+
};
|
package/dist/lib/base-command.js
CHANGED
|
@@ -10,8 +10,10 @@ Object.defineProperty(exports, "default", {
|
|
|
10
10
|
});
|
|
11
11
|
const _core = require("@oclif/core");
|
|
12
12
|
const _apiv1 = /*#__PURE__*/ _interop_require_default(require("./api-v1"));
|
|
13
|
+
const _auth = /*#__PURE__*/ _interop_require_default(require("./auth"));
|
|
13
14
|
const _runcontext = /*#__PURE__*/ _interop_require_wildcard(require("./run-context"));
|
|
14
|
-
const
|
|
15
|
+
const _urls = require("./urls");
|
|
16
|
+
const _userconfig = require("./user-config");
|
|
15
17
|
function _define_property(obj, key, value) {
|
|
16
18
|
if (key in obj) {
|
|
17
19
|
Object.defineProperty(obj, key, {
|
|
@@ -71,24 +73,97 @@ function _interop_require_wildcard(obj, nodeInterop) {
|
|
|
71
73
|
}
|
|
72
74
|
return newObj;
|
|
73
75
|
}
|
|
76
|
+
function sessionWithDefaultOrigins(sessionContext) {
|
|
77
|
+
var _sessionContext_apiOrigin, _sessionContext_dashboardOrigin, _sessionContext_authOrigin;
|
|
78
|
+
return {
|
|
79
|
+
...sessionContext,
|
|
80
|
+
apiOrigin: (_sessionContext_apiOrigin = sessionContext.apiOrigin) !== null && _sessionContext_apiOrigin !== void 0 ? _sessionContext_apiOrigin : _urls.DEFAULT_API_URL,
|
|
81
|
+
dashboardOrigin: (_sessionContext_dashboardOrigin = sessionContext.dashboardOrigin) !== null && _sessionContext_dashboardOrigin !== void 0 ? _sessionContext_dashboardOrigin : _urls.DEFAULT_DASHBOARD_URL,
|
|
82
|
+
authOrigin: (_sessionContext_authOrigin = sessionContext.authOrigin) !== null && _sessionContext_authOrigin !== void 0 ? _sessionContext_authOrigin : _urls.DEFAULT_AUTH_URL
|
|
83
|
+
};
|
|
84
|
+
}
|
|
74
85
|
class BaseCommand extends _core.Command {
|
|
75
86
|
async init() {
|
|
76
87
|
await super.init();
|
|
88
|
+
this.configStore = new _userconfig.UserConfigStore(this.config.configDir);
|
|
77
89
|
// 1. Load user's config from the config dir, as available.
|
|
78
|
-
await
|
|
90
|
+
await this.configStore.load();
|
|
79
91
|
// 2. Parse flags and args, must come after the user config load.
|
|
80
92
|
const { args, flags } = await this.parse(this.ctor);
|
|
81
93
|
this.props = {
|
|
82
94
|
args: args,
|
|
83
95
|
flags: flags
|
|
84
96
|
};
|
|
85
|
-
// 3.
|
|
86
|
-
this.
|
|
87
|
-
// 4.
|
|
97
|
+
// 3. Build the initial session context.
|
|
98
|
+
this.sessionContext = this.buildSessionContext();
|
|
99
|
+
// 4. If the command requires authentication, ensure the session is authenticated.
|
|
100
|
+
if (this.requiresAuth) {
|
|
101
|
+
this.ensureAuthenticated();
|
|
102
|
+
}
|
|
103
|
+
// 5. If the session context is an OAuth session, refresh the access token.
|
|
104
|
+
if (this.sessionContext.type === "oauth") {
|
|
105
|
+
await this.refreshAccessTokenForSession();
|
|
106
|
+
}
|
|
107
|
+
// 6. Instantiate a knock api client.
|
|
108
|
+
this.apiV1 = new _apiv1.default(this.sessionContext, this.config);
|
|
109
|
+
// 7. Load the run context of the invoked command.
|
|
88
110
|
this.runContext = await _runcontext.load(this.id);
|
|
89
111
|
}
|
|
112
|
+
buildSessionContext() {
|
|
113
|
+
const userConfig = this.configStore.get();
|
|
114
|
+
const session = userConfig.userSession;
|
|
115
|
+
// If the user has a session and a service token is not provided, use the session.
|
|
116
|
+
if (session && !this.props.flags["service-token"]) {
|
|
117
|
+
var _this_props_flags_apiorigin;
|
|
118
|
+
return sessionWithDefaultOrigins({
|
|
119
|
+
type: "oauth",
|
|
120
|
+
session,
|
|
121
|
+
apiOrigin: (_this_props_flags_apiorigin = this.props.flags["api-origin"]) !== null && _this_props_flags_apiorigin !== void 0 ? _this_props_flags_apiorigin : userConfig.apiOrigin,
|
|
122
|
+
dashboardOrigin: userConfig.dashboardOrigin,
|
|
123
|
+
authOrigin: userConfig.authOrigin
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
var _this_props_flags_servicetoken, _this_props_flags_apiorigin1;
|
|
127
|
+
// Otherwise, default to this being a service token session.
|
|
128
|
+
return sessionWithDefaultOrigins({
|
|
129
|
+
type: "service",
|
|
130
|
+
token: (_this_props_flags_servicetoken = this.props.flags["service-token"]) !== null && _this_props_flags_servicetoken !== void 0 ? _this_props_flags_servicetoken : userConfig.serviceToken,
|
|
131
|
+
apiOrigin: (_this_props_flags_apiorigin1 = this.props.flags["api-origin"]) !== null && _this_props_flags_apiorigin1 !== void 0 ? _this_props_flags_apiorigin1 : userConfig.apiOrigin,
|
|
132
|
+
dashboardOrigin: userConfig.dashboardOrigin,
|
|
133
|
+
authOrigin: userConfig.authOrigin
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
ensureAuthenticated() {
|
|
137
|
+
if (this.sessionContext.type === "service" && !this.sessionContext.token || this.sessionContext.type === "oauth" && !this.sessionContext.session) {
|
|
138
|
+
this.error("No token found. Refusing to run command.");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
async refreshAccessTokenForSession() {
|
|
142
|
+
// Maybe refresh the access token?
|
|
143
|
+
try {
|
|
144
|
+
var _this_sessionContext_session, _this_sessionContext_session1;
|
|
145
|
+
var _this_sessionContext_session_clientId, _this_sessionContext_session_refreshToken;
|
|
146
|
+
const refreshedSession = await _auth.default.refreshAccessToken({
|
|
147
|
+
authUrl: this.sessionContext.authOrigin,
|
|
148
|
+
clientId: (_this_sessionContext_session_clientId = (_this_sessionContext_session = this.sessionContext.session) === null || _this_sessionContext_session === void 0 ? void 0 : _this_sessionContext_session.clientId) !== null && _this_sessionContext_session_clientId !== void 0 ? _this_sessionContext_session_clientId : "",
|
|
149
|
+
refreshToken: (_this_sessionContext_session_refreshToken = (_this_sessionContext_session1 = this.sessionContext.session) === null || _this_sessionContext_session1 === void 0 ? void 0 : _this_sessionContext_session1.refreshToken) !== null && _this_sessionContext_session_refreshToken !== void 0 ? _this_sessionContext_session_refreshToken : ""
|
|
150
|
+
});
|
|
151
|
+
this.debug("Successfully refreshed access token.");
|
|
152
|
+
// Update the user config to use the new session.
|
|
153
|
+
await this.configStore.set({
|
|
154
|
+
userSession: refreshedSession
|
|
155
|
+
});
|
|
156
|
+
// Update the session context to use the new session.
|
|
157
|
+
this.sessionContext = this.buildSessionContext();
|
|
158
|
+
} catch {
|
|
159
|
+
this.debug("Failed to refresh access token, clearing session.");
|
|
160
|
+
await this.configStore.set({
|
|
161
|
+
userSession: undefined
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
}
|
|
90
165
|
constructor(...args){
|
|
91
|
-
super(...args), _define_property(this, "props", void 0), _define_property(this, "apiV1", void 0), _define_property(this, "runContext", void 0);
|
|
166
|
+
super(...args), _define_property(this, "props", void 0), _define_property(this, "apiV1", void 0), _define_property(this, "runContext", void 0), _define_property(this, "sessionContext", void 0), _define_property(this, "configStore", void 0), _define_property(this, "requiresAuth", true);
|
|
92
167
|
}
|
|
93
168
|
}
|
|
94
169
|
// Base flags are inherited by any command that extends BaseCommand.
|
|
@@ -99,17 +174,15 @@ _define_property(BaseCommand, "baseFlags", {
|
|
|
99
174
|
// - if not available, fall back to user config
|
|
100
175
|
"service-token": _core.Flags.string({
|
|
101
176
|
summary: "The service token to authenticate with.",
|
|
102
|
-
required:
|
|
177
|
+
required: false,
|
|
103
178
|
multiple: false,
|
|
104
|
-
env: "KNOCK_SERVICE_TOKEN"
|
|
105
|
-
default: async ()=>_userconfig.default.get().serviceToken
|
|
179
|
+
env: "KNOCK_SERVICE_TOKEN"
|
|
106
180
|
}),
|
|
107
|
-
// Hidden
|
|
181
|
+
// Hidden flags to use a different api url for development purposes.
|
|
108
182
|
"api-origin": _core.Flags.string({
|
|
109
183
|
hidden: true,
|
|
110
184
|
required: false,
|
|
111
|
-
multiple: false
|
|
112
|
-
default: async ()=>_userconfig.default.get().apiOrigin
|
|
185
|
+
multiple: false
|
|
113
186
|
})
|
|
114
187
|
});
|
|
115
188
|
const _default = BaseCommand;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
Object.defineProperty(exports, "browser", {
|
|
6
|
+
enumerable: true,
|
|
7
|
+
get: function() {
|
|
8
|
+
return browser;
|
|
9
|
+
}
|
|
10
|
+
});
|
|
11
|
+
const _open = /*#__PURE__*/ _interop_require_default(require("open"));
|
|
12
|
+
function _interop_require_default(obj) {
|
|
13
|
+
return obj && obj.__esModule ? obj : {
|
|
14
|
+
default: obj
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
const browser = {
|
|
18
|
+
/**
|
|
19
|
+
* Opens a URL in the default browser
|
|
20
|
+
* @param url The URL to open
|
|
21
|
+
* @returns A promise that resolves when the URL is opened
|
|
22
|
+
*/ async openUrl (url) {
|
|
23
|
+
await (0, _open.default)(url);
|
|
24
|
+
}
|
|
25
|
+
};
|
package/dist/lib/urls.js
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", {
|
|
3
|
+
value: true
|
|
4
|
+
});
|
|
5
|
+
function _export(target, all) {
|
|
6
|
+
for(var name in all)Object.defineProperty(target, name, {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: Object.getOwnPropertyDescriptor(all, name).get
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
_export(exports, {
|
|
12
|
+
get DEFAULT_API_URL () {
|
|
13
|
+
return DEFAULT_API_URL;
|
|
14
|
+
},
|
|
15
|
+
get DEFAULT_AUTH_URL () {
|
|
16
|
+
return DEFAULT_AUTH_URL;
|
|
17
|
+
},
|
|
18
|
+
get DEFAULT_DASHBOARD_URL () {
|
|
19
|
+
return DEFAULT_DASHBOARD_URL;
|
|
20
|
+
},
|
|
21
|
+
get authErrorUrl () {
|
|
22
|
+
return authErrorUrl;
|
|
23
|
+
},
|
|
24
|
+
get authSuccessUrl () {
|
|
25
|
+
return authSuccessUrl;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
const DEFAULT_DASHBOARD_URL = "https://dashboard.knock.app";
|
|
29
|
+
const DEFAULT_AUTH_URL = "https://signin.knock.app";
|
|
30
|
+
const DEFAULT_API_URL = "https://control.knock.app";
|
|
31
|
+
const authSuccessUrl = (dashboardUrl)=>`${dashboardUrl}/auth/oauth/cli`;
|
|
32
|
+
const authErrorUrl = (dashboardUrl, error)=>`${dashboardUrl}/auth/oauth/cli?error=${error}`;
|