clever-tools 3.12.0 → 3.13.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/bin/clever.js +280 -6
- package/package.json +1 -1
- package/src/clever-client/auth-bridge.js +1 -1
- package/src/clever-client/operators.js +121 -0
- package/src/commands/addon.js +12 -7
- package/src/commands/cancel-deploy.js +3 -4
- package/src/commands/config.js +16 -20
- package/src/commands/console.js +4 -10
- package/src/commands/create.js +76 -9
- package/src/commands/delete.js +11 -10
- package/src/commands/deploy.js +35 -21
- package/src/commands/emails.js +174 -0
- package/src/commands/keycloak.js +138 -0
- package/src/commands/link.js +3 -1
- package/src/commands/makeDefault.js +2 -1
- package/src/commands/matomo.js +85 -0
- package/src/commands/metabase.js +112 -0
- package/src/commands/open.js +2 -5
- package/src/commands/otoroshi.js +138 -0
- package/src/commands/profile.js +2 -4
- package/src/commands/restart.js +1 -1
- package/src/commands/ssh-keys.js +159 -0
- package/src/commands/stop.js +1 -1
- package/src/commands/tcp-redirs.js +3 -3
- package/src/commands/tokens.js +16 -7
- package/src/commands/unlink.js +2 -1
- package/src/experimental-features.js +16 -15
- package/src/lib/operator-commands.js +281 -0
- package/src/lib/prompts.js +30 -0
- package/src/lib/slugify.js +10 -0
- package/src/models/addon.js +5 -2
- package/src/models/app_configuration.js +12 -9
- package/src/models/application.js +24 -12
- package/src/models/application_configuration.js +72 -72
- package/src/models/git.js +29 -1
- package/src/models/ids-resolver.js +37 -1
- package/src/models/interact.js +0 -24
- package/src/models/log-v4.js +13 -4
- package/src/models/operator.js +48 -0
- package/src/models/utils.js +21 -0
- package/src/parsers.js +14 -0
- package/src/prompt-password.js +0 -10
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import {
|
|
2
|
+
operatorList,
|
|
3
|
+
operatorOpen,
|
|
4
|
+
operatorOpenLogs,
|
|
5
|
+
operatorOpenWebUi,
|
|
6
|
+
operatorPrint,
|
|
7
|
+
operatorReboot,
|
|
8
|
+
operatorRebuild,
|
|
9
|
+
} from '../lib/operator-commands.js';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Get the details of a Matomo operator
|
|
13
|
+
* @param {object} params The command's parameters
|
|
14
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
15
|
+
* @param {string} params.options.format The output format
|
|
16
|
+
* @returns {Promise<void>}
|
|
17
|
+
*/
|
|
18
|
+
export async function get (params) {
|
|
19
|
+
const [addonIdOrName] = params.args;
|
|
20
|
+
const { format } = params.options;
|
|
21
|
+
await operatorPrint('matomo', addonIdOrName, format);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* List all Matomo operators
|
|
26
|
+
* @returns {Promise<void>}
|
|
27
|
+
*/
|
|
28
|
+
export async function list (params) {
|
|
29
|
+
await operatorList('addon-matomo', params.options.format);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Open a Matomo operator dashboard in the Clever Cloud Console
|
|
34
|
+
* @param {object} params The command's parameters
|
|
35
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
36
|
+
* @returns {Promise<void>}
|
|
37
|
+
*/
|
|
38
|
+
export async function open (params) {
|
|
39
|
+
const [addonIdOrName] = params.args;
|
|
40
|
+
await operatorOpen('matomo', addonIdOrName);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Open the Logs section of a Matomo Operator application in the Clever Cloud Console
|
|
45
|
+
* @param {object} params The command's parameters
|
|
46
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
47
|
+
* @returns {Promise<void>}
|
|
48
|
+
*/
|
|
49
|
+
export async function openLogs (params) {
|
|
50
|
+
const [addonIdOrName] = params.args;
|
|
51
|
+
await operatorOpenLogs('matomo', addonIdOrName);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Open the Web UI of a Matomo Operator application in the Clever Cloud Console
|
|
56
|
+
* @param {object} params The command's parameters
|
|
57
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
export async function openWebUi (params) {
|
|
61
|
+
const [addonIdOrName] = params.args;
|
|
62
|
+
await operatorOpenWebUi('matomo', addonIdOrName);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Reboot a Matomo operator
|
|
67
|
+
* @param {object} params The command's parameters
|
|
68
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
69
|
+
* @returns {Promise<void>}
|
|
70
|
+
*/
|
|
71
|
+
export async function reboot (params) {
|
|
72
|
+
const [addonIdOrName] = params.args;
|
|
73
|
+
await operatorReboot('matomo', addonIdOrName);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Rebuild a Matomo operator
|
|
78
|
+
* @param {object} params The command's parameters
|
|
79
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
80
|
+
* @returns {Promise<void>}
|
|
81
|
+
*/
|
|
82
|
+
export async function rebuild (params) {
|
|
83
|
+
const [addonIdOrName] = params.args;
|
|
84
|
+
await operatorRebuild('matomo', addonIdOrName);
|
|
85
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import {
|
|
2
|
+
operatorCheckVersion,
|
|
3
|
+
operatorList,
|
|
4
|
+
operatorOpen,
|
|
5
|
+
operatorOpenLogs,
|
|
6
|
+
operatorOpenWebUi,
|
|
7
|
+
operatorPrint,
|
|
8
|
+
operatorReboot,
|
|
9
|
+
operatorRebuild,
|
|
10
|
+
operatorUpdateVersion,
|
|
11
|
+
} from '../lib/operator-commands.js';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Check the version of a Metabase operator
|
|
15
|
+
* @param {object} params The command's parameters
|
|
16
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
17
|
+
* @param {string} params.options.format The output format
|
|
18
|
+
* @returns {Promise<void>}
|
|
19
|
+
*/
|
|
20
|
+
export async function checkVersion (params) {
|
|
21
|
+
const [addonIdOrName] = params.args;
|
|
22
|
+
const { format } = params.options;
|
|
23
|
+
await operatorCheckVersion('metabase', addonIdOrName, format);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Update the version of a Metabase operator
|
|
28
|
+
* @param {object} params The command's parameters
|
|
29
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
export async function updateVersion (params) {
|
|
33
|
+
const [addonIdOrName] = params.args;
|
|
34
|
+
const { target } = params.options;
|
|
35
|
+
await operatorUpdateVersion('metabase', target, addonIdOrName);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get the details of a Metabase operator
|
|
40
|
+
* @param {object} params The command's parameters
|
|
41
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
42
|
+
* @param {string} params.options.format The output format
|
|
43
|
+
* @returns {Promise<void>}
|
|
44
|
+
*/
|
|
45
|
+
export async function get (params) {
|
|
46
|
+
const [addonIdOrName] = params.args;
|
|
47
|
+
const { format } = params.options;
|
|
48
|
+
await operatorPrint('metabase', addonIdOrName, format);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* List all Metabase operators
|
|
53
|
+
* @returns {Promise<void>}
|
|
54
|
+
*/
|
|
55
|
+
export async function list (params) {
|
|
56
|
+
await operatorList('metabase', params.options.format);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Open a Metabase operator dashboard in the Clever Cloud Console
|
|
61
|
+
* @param {object} params The command's parameters
|
|
62
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
63
|
+
* @returns {Promise<void>}
|
|
64
|
+
*/
|
|
65
|
+
export async function open (params) {
|
|
66
|
+
const [addonIdOrName] = params.args;
|
|
67
|
+
await operatorOpen('metabase', addonIdOrName);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Open the Logs section of a Metabase Operator application in the Clever Cloud Console
|
|
72
|
+
* @param {object} params The command's parameters
|
|
73
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
74
|
+
* @returns {Promise<void>}
|
|
75
|
+
*/
|
|
76
|
+
export async function openLogs (params) {
|
|
77
|
+
const [addonIdOrName] = params.args;
|
|
78
|
+
await operatorOpenLogs('metabase', addonIdOrName);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Open the Web UI of a Metabase Operator application in the Clever Cloud Console
|
|
83
|
+
* @param {object} params The command's parameters
|
|
84
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
85
|
+
* @returns {Promise<void>}
|
|
86
|
+
*/
|
|
87
|
+
export async function openWebUi (params) {
|
|
88
|
+
const [addonIdOrName] = params.args;
|
|
89
|
+
await operatorOpenWebUi('metabase', addonIdOrName);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Reboot a Metabase operator
|
|
94
|
+
* @param {object} params The command's parameters
|
|
95
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
96
|
+
* @returns {Promise<void>}
|
|
97
|
+
*/
|
|
98
|
+
export async function reboot (params) {
|
|
99
|
+
const [addonIdOrName] = params.args;
|
|
100
|
+
await operatorReboot('metabase', addonIdOrName);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Rebuild a Metabase operator
|
|
105
|
+
* @param {object} params The command's parameters
|
|
106
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
107
|
+
* @returns {Promise<void>}
|
|
108
|
+
*/
|
|
109
|
+
export async function rebuild (params) {
|
|
110
|
+
const [addonIdOrName] = params.args;
|
|
111
|
+
await operatorRebuild('metabase', addonIdOrName);
|
|
112
|
+
}
|
package/src/commands/open.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
import openPage from 'open';
|
|
2
|
-
|
|
3
1
|
import * as Application from '../models/application.js';
|
|
4
2
|
import * as Domain from '../models/domain.js';
|
|
5
|
-
import {
|
|
3
|
+
import { openBrowser } from '../models/utils.js';
|
|
6
4
|
|
|
7
5
|
export async function open (params) {
|
|
8
6
|
const { alias, app: appIdOrName } = params.options;
|
|
@@ -11,6 +9,5 @@ export async function open (params) {
|
|
|
11
9
|
const vhost = await Domain.getBest(appId, ownerId);
|
|
12
10
|
const url = 'https://' + vhost.fqdn;
|
|
13
11
|
|
|
14
|
-
|
|
15
|
-
await openPage(url, { wait: false });
|
|
12
|
+
await openBrowser(url, 'Opening the application in your browser');
|
|
16
13
|
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import {
|
|
2
|
+
operatorCheckVersion,
|
|
3
|
+
operatorList,
|
|
4
|
+
operatorNgDisable,
|
|
5
|
+
operatorNgEnable,
|
|
6
|
+
operatorOpen,
|
|
7
|
+
operatorOpenLogs,
|
|
8
|
+
operatorOpenWebUi,
|
|
9
|
+
operatorPrint,
|
|
10
|
+
operatorReboot,
|
|
11
|
+
operatorRebuild,
|
|
12
|
+
operatorUpdateVersion,
|
|
13
|
+
} from '../lib/operator-commands.js';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Check the version of an Otoroshi operator
|
|
17
|
+
* @param {object} params The command's parameters
|
|
18
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
19
|
+
* @param {string} params.options.format The output format
|
|
20
|
+
* @returns {Promise<void>}
|
|
21
|
+
*/
|
|
22
|
+
export async function checkVersion (params) {
|
|
23
|
+
const [addonIdOrName] = params.args;
|
|
24
|
+
const { format } = params.options;
|
|
25
|
+
await operatorCheckVersion('otoroshi', addonIdOrName, format);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Update the version of an Otoroshi operator
|
|
30
|
+
* @param {object} params The command's parameters
|
|
31
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
32
|
+
* @returns {Promise<void>}
|
|
33
|
+
*/
|
|
34
|
+
export async function updateVersion (params) {
|
|
35
|
+
const [addonIdOrName] = params.args;
|
|
36
|
+
const { target } = params.options;
|
|
37
|
+
await operatorUpdateVersion('otoroshi', target, addonIdOrName);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Get the details of an Otoroshi operator
|
|
42
|
+
* @param {object} params The command's parameters
|
|
43
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
44
|
+
* @param {string} params.options.format The output format
|
|
45
|
+
* @returns {Promise<void>}
|
|
46
|
+
*/
|
|
47
|
+
export async function get (params) {
|
|
48
|
+
const [addonIdOrName] = params.args;
|
|
49
|
+
const { format } = params.options;
|
|
50
|
+
await operatorPrint('otoroshi', addonIdOrName, format);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* List all Otoroshi operators
|
|
55
|
+
* @returns {Promise<void>}
|
|
56
|
+
*/
|
|
57
|
+
export async function list (params) {
|
|
58
|
+
await operatorList('otoroshi', params.options.format);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Unlink a Operator from a Network Group
|
|
63
|
+
* @param {object} params The command's parameters
|
|
64
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
65
|
+
* @returns {Promise<void>}
|
|
66
|
+
* @throws {Error} If the Network Group feature is already disabled
|
|
67
|
+
*/
|
|
68
|
+
export async function ngDisable (params) {
|
|
69
|
+
const [addonIdOrName] = params.args;
|
|
70
|
+
await operatorNgDisable('otoroshi', addonIdOrName);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Link a Operator to a Network Group
|
|
75
|
+
* @param {object} params The command's parameters
|
|
76
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
77
|
+
* @returns {Promise<void>}
|
|
78
|
+
* @throws {Error} If the Network Group feature is already enabled
|
|
79
|
+
*/
|
|
80
|
+
export async function ngEnable (params) {
|
|
81
|
+
const [addonIdOrName] = params.args;
|
|
82
|
+
await operatorNgEnable('otoroshi', addonIdOrName);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Open an Otoroshi operator dashboard in the Clever Cloud Console
|
|
87
|
+
* @param {object} params The command's parameters
|
|
88
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
89
|
+
* @returns {Promise<void>}
|
|
90
|
+
*/
|
|
91
|
+
export async function open (params) {
|
|
92
|
+
const [addonIdOrName] = params.args;
|
|
93
|
+
await operatorOpen('otoroshi', addonIdOrName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Open the Logs section of an Otoroshi Operator application in the Clever Cloud Console
|
|
98
|
+
* @param {object} params The command's parameters
|
|
99
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
export async function openLogs (params) {
|
|
103
|
+
const [addonIdOrName] = params.args;
|
|
104
|
+
await operatorOpenLogs('otoroshi', addonIdOrName);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Open the Web UI of an Otoroshi Operator application in the Clever Cloud Console
|
|
109
|
+
* @param {object} params The command's parameters
|
|
110
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
111
|
+
* @returns {Promise<void>}
|
|
112
|
+
*/
|
|
113
|
+
export async function openWebUi (params) {
|
|
114
|
+
const [addonIdOrName] = params.args;
|
|
115
|
+
await operatorOpenWebUi('otoroshi', addonIdOrName);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Reboot an Otoroshi operator
|
|
120
|
+
* @param {object} params The command's parameters
|
|
121
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
122
|
+
* @returns {Promise<void>}
|
|
123
|
+
*/
|
|
124
|
+
export async function reboot (params) {
|
|
125
|
+
const [addonIdOrName] = params.args;
|
|
126
|
+
await operatorReboot('otoroshi', addonIdOrName);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Rebuild an Otoroshi operator
|
|
131
|
+
* @param {object} params The command's parameters
|
|
132
|
+
* @param {string} params.args[0] The operator's name or ID
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
export async function rebuild (params) {
|
|
136
|
+
const [addonIdOrName] = params.args;
|
|
137
|
+
await operatorRebuild('otoroshi', addonIdOrName);
|
|
138
|
+
}
|
package/src/commands/profile.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import colors from 'colors/safe.js';
|
|
2
|
-
import
|
|
2
|
+
import { openBrowser } from '../models/utils.js';
|
|
3
3
|
import { Logger } from '../logger.js';
|
|
4
4
|
import * as User from '../models/user.js';
|
|
5
5
|
import dedent from 'dedent';
|
|
@@ -51,7 +51,5 @@ export async function profile (params) {
|
|
|
51
51
|
};
|
|
52
52
|
|
|
53
53
|
export async function openProfile () {
|
|
54
|
-
|
|
55
|
-
Logger.debug('Opening the profile page in your browser');
|
|
56
|
-
await openPage(URL, { wait: false });
|
|
54
|
+
await openBrowser('/users/me/information', 'Opening the profile page in your browser');
|
|
57
55
|
}
|
package/src/commands/restart.js
CHANGED
|
@@ -26,7 +26,7 @@ export async function restart (params) {
|
|
|
26
26
|
const commitId = fullCommitId || remoteCommitId;
|
|
27
27
|
if (commitId != null) {
|
|
28
28
|
const cacheSuffix = withoutCache ? ' without using cache' : '';
|
|
29
|
-
Logger.println(
|
|
29
|
+
Logger.println(`🔄 Restarting ${colors.bold(app.name)}${cacheSuffix} ${colors.grey(`(${commitId})`)}`);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
// This should be handled by the API when a deployment ID is set but we'll do this for now
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { confirm } from '../lib/prompts.js';
|
|
2
|
+
import colors from 'colors/safe.js';
|
|
3
|
+
import { Logger } from '../logger.js';
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import { sendToApi } from '../models/send-to-api.js';
|
|
6
|
+
import { openBrowser } from '../models/utils.js';
|
|
7
|
+
import dedent from 'dedent';
|
|
8
|
+
import {
|
|
9
|
+
todo_addSshKey as addSshKey,
|
|
10
|
+
todo_getSshKeys as getSshKeys,
|
|
11
|
+
todo_removeSshKey as removeSshKey,
|
|
12
|
+
} from '@clevercloud/client/esm/api/v2/user.js';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* List SSH keys of the current user
|
|
16
|
+
* @param {object} params The command parameters
|
|
17
|
+
* @param {string} params.options.format The output format
|
|
18
|
+
*/
|
|
19
|
+
export async function list (params) {
|
|
20
|
+
const { format } = params.options;
|
|
21
|
+
|
|
22
|
+
const keys = await getUserSshKeys();
|
|
23
|
+
|
|
24
|
+
switch (format) {
|
|
25
|
+
case 'json': {
|
|
26
|
+
Logger.printJson(keys);
|
|
27
|
+
break;
|
|
28
|
+
}
|
|
29
|
+
case 'human':
|
|
30
|
+
default: {
|
|
31
|
+
if (keys.length === 0) {
|
|
32
|
+
Logger.println(dedent`
|
|
33
|
+
${colors.blue('🔐 No SSH keys')}
|
|
34
|
+
|
|
35
|
+
To list the SSH keys on your local system, use the following command:
|
|
36
|
+
${colors.grey('ssh-add -l -E sha256')}
|
|
37
|
+
|
|
38
|
+
To create a new key pair, use the following command:
|
|
39
|
+
${colors.grey('ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519_clever -C "An optional comment"')}
|
|
40
|
+
|
|
41
|
+
Then add the public key to your Clever Cloud account:
|
|
42
|
+
${colors.grey('clever ssh-keys add myNewKey ~/.ssh/id_ed25519_clever.pub')}
|
|
43
|
+
`);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
Logger.println(`🔐 ${keys.length} SSH key(s):`);
|
|
48
|
+
keys.forEach((key) => {
|
|
49
|
+
Logger.println(` • ${colors.blue(key.name)}`, colors.grey(`(${key.fingerprint})`));
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Add a SSH key to the current user
|
|
57
|
+
* @param {object} params The command parameters
|
|
58
|
+
* @param {Array<string>} params.args
|
|
59
|
+
*/
|
|
60
|
+
export async function add (params) {
|
|
61
|
+
const [keyName, filePath] = params.args;
|
|
62
|
+
|
|
63
|
+
if (!fs.existsSync(filePath)) {
|
|
64
|
+
throw new Error(`File ${filePath} does not exist`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const pubKeyContent = fs.readFileSync(filePath, 'utf8').trim();
|
|
68
|
+
Logger.debug(`SSH key file content: ${pubKeyContent}`);
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
await addSshKey({ key: encodeURIComponent(keyName) }, JSON.stringify(pubKeyContent)).then(sendToApi);
|
|
72
|
+
}
|
|
73
|
+
catch (e) {
|
|
74
|
+
console.log(e?.responseBody?.id);
|
|
75
|
+
if (e?.responseBody?.id === 505) {
|
|
76
|
+
throw new Error('This SSH key is not valid, please make sure you\'re pointing to the public key file');
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
Logger.printSuccess(`SSH key ${keyName} added successfully`);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Remove a SSH key from the current user
|
|
85
|
+
* @param {object} params The command parameters
|
|
86
|
+
* @param {Array<string>} params.args
|
|
87
|
+
*/
|
|
88
|
+
export async function remove (params) {
|
|
89
|
+
const [keyName] = params.args;
|
|
90
|
+
|
|
91
|
+
const keys = await getUserSshKeys();
|
|
92
|
+
|
|
93
|
+
if (keys.find((key) => key.name === keyName) == null) {
|
|
94
|
+
throw new Error(`SSH key ${colors.red(keyName)} not found`);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const keyNameEncoded = encodeURIComponent(keyName);
|
|
98
|
+
await removeSshKey({ key: keyNameEncoded }).then(sendToApi);
|
|
99
|
+
|
|
100
|
+
Logger.printSuccess(`SSH key ${keyName} removed successfully`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Remove all SSH keys from the current user
|
|
105
|
+
* @param {object} params The command parameters
|
|
106
|
+
* @param {object} params.options The command options
|
|
107
|
+
* @param {boolean} params.options.yes The user confirmation
|
|
108
|
+
*/
|
|
109
|
+
export async function removeAll (params) {
|
|
110
|
+
if (!params.options.yes) {
|
|
111
|
+
await confirm(
|
|
112
|
+
'Are you sure you want to remove all your SSH keys?',
|
|
113
|
+
'No SSH keys removed',
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const keys = await getUserSshKeys();
|
|
118
|
+
|
|
119
|
+
if (keys.length === 0) {
|
|
120
|
+
Logger.println('No SSH keys to remove');
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const results = await Promise.all(
|
|
125
|
+
keys.map((key) => {
|
|
126
|
+
const keyNameEncoded = encodeURIComponent(key.name);
|
|
127
|
+
return removeSshKey({ key: keyNameEncoded }).then(sendToApi)
|
|
128
|
+
.then(() => [true, key.name])
|
|
129
|
+
.catch(() => [false, key.name]);
|
|
130
|
+
}),
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
if (results.every(([isRemoved]) => isRemoved)) {
|
|
134
|
+
Logger.printSuccess('All SSH keys were removed successfully');
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
const keyNamesWithErrors = results
|
|
138
|
+
.filter(([isRemoved]) => !isRemoved)
|
|
139
|
+
.map(([_, keyName]) => keyName)
|
|
140
|
+
.join(', ');
|
|
141
|
+
throw new Error(`Some errors occured while removing these SSH keys: ${keyNamesWithErrors}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Open the SSH keys management page of the Console in your browser
|
|
147
|
+
* @returns {Promise<void>} A promise that resolves when the page is opened
|
|
148
|
+
*/
|
|
149
|
+
export function openConsole () {
|
|
150
|
+
return openBrowser('/users/me/ssh-keys', 'Opening the SSH keys management page of the Console in your browser');
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* @return {Promise<Array<{ name: string, key: string, fingerprint: string }>>}
|
|
155
|
+
*/
|
|
156
|
+
async function getUserSshKeys () {
|
|
157
|
+
const rawKeys = await getSshKeys().then(sendToApi);
|
|
158
|
+
return rawKeys.sort((a, b) => a.name.localeCompare(b.name));
|
|
159
|
+
}
|
package/src/commands/stop.js
CHANGED
|
@@ -8,5 +8,5 @@ export async function stop (params) {
|
|
|
8
8
|
const { ownerId, appId } = await Application.resolveId(appIdOrName, alias);
|
|
9
9
|
|
|
10
10
|
await stopApplication({ id: ownerId, appId }).then(sendToApi);
|
|
11
|
-
Logger.
|
|
11
|
+
Logger.printSuccess('Application successfully stopped!');
|
|
12
12
|
}
|
|
@@ -2,7 +2,7 @@ import colors from 'colors/safe.js';
|
|
|
2
2
|
|
|
3
3
|
import * as Namespaces from '../models/namespaces.js';
|
|
4
4
|
import { sendToApi } from '../models/send-to-api.js';
|
|
5
|
-
import
|
|
5
|
+
import { confirm } from '../lib/prompts.js';
|
|
6
6
|
import { Logger } from '../logger.js';
|
|
7
7
|
import * as Application from '../models/application.js';
|
|
8
8
|
import { addTcpRedir, getTcpRedirs, removeTcpRedir } from '@clevercloud/client/esm/api/v2/application.js';
|
|
@@ -72,8 +72,8 @@ async function acceptPayment (result, skipConfirmation) {
|
|
|
72
72
|
Logger.println(`Total (without taxes): ${result.totalHT}€`);
|
|
73
73
|
Logger.println(colors.bold(`Total (with taxes): ${result.totalTTC}€`));
|
|
74
74
|
|
|
75
|
-
await
|
|
76
|
-
`You're about to pay ${result.totalTTC}€, confirm
|
|
75
|
+
await confirm(
|
|
76
|
+
`You're about to pay ${result.totalTTC}€, confirm?`,
|
|
77
77
|
'No confirmation, aborting TCP redirection creation',
|
|
78
78
|
);
|
|
79
79
|
}
|
package/src/commands/tokens.js
CHANGED
|
@@ -5,7 +5,7 @@ import { sendToAuthBridge } from '../models/send-to-api.js';
|
|
|
5
5
|
import { getCurrent as getCurrentUser } from '../models/user.js';
|
|
6
6
|
import { conf } from '../models/configuration.js';
|
|
7
7
|
import dedent from 'dedent';
|
|
8
|
-
import {
|
|
8
|
+
import { promptSecret } from '../lib/prompts.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Create a new API token
|
|
@@ -13,10 +13,20 @@ import { promptPassword } from '../prompt-password.js';
|
|
|
13
13
|
* @param {[string]} params.args - Command line args
|
|
14
14
|
* @param {Object} params.options - Command line options
|
|
15
15
|
* @param {'json'|'human'} params.options.format - Output format
|
|
16
|
+
* @param {number} params.options.expiration - Expiration date as timestamp
|
|
16
17
|
*/
|
|
17
18
|
export async function create (params) {
|
|
18
19
|
const [apiTokenName] = params.args;
|
|
19
20
|
const { expiration, format } = params.options;
|
|
21
|
+
const user = await getCurrentUser();
|
|
22
|
+
|
|
23
|
+
if (!user.hasPassword) {
|
|
24
|
+
const apiTokenListHref = new URL('/users/me/api-tokens', conf.CONSOLE_URL).href;
|
|
25
|
+
throw new Error(dedent`
|
|
26
|
+
${colors.yellow('!')} Your Clever Cloud account is linked via GitHub and has no password. Setting one is required to create API tokens.
|
|
27
|
+
${colors.blue('→')} To do so, go to the following URL: ${colors.blue(apiTokenListHref)}
|
|
28
|
+
`);
|
|
29
|
+
}
|
|
20
30
|
|
|
21
31
|
// Expire in 1 year
|
|
22
32
|
const dateObject = new Date();
|
|
@@ -25,22 +35,20 @@ export async function create (params) {
|
|
|
25
35
|
|
|
26
36
|
let expirationDate;
|
|
27
37
|
if (expiration != null) {
|
|
28
|
-
if (expiration > maxExpirationDate) {
|
|
38
|
+
if (expiration > maxExpirationDate.getTime()) {
|
|
29
39
|
throw new Error('You cannot set an expiration date greater than 1 year');
|
|
30
40
|
}
|
|
31
|
-
expirationDate = expiration;
|
|
41
|
+
expirationDate = new Date(expiration);
|
|
32
42
|
}
|
|
33
43
|
else {
|
|
34
44
|
expirationDate = maxExpirationDate;
|
|
35
45
|
}
|
|
36
46
|
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
const password = await promptPassword('Enter your password:');
|
|
47
|
+
const password = await promptSecret('Enter your password:');
|
|
40
48
|
|
|
41
49
|
let mfaCode;
|
|
42
50
|
if (user.preferredMFA === 'TOTP') {
|
|
43
|
-
mfaCode = await
|
|
51
|
+
mfaCode = await promptSecret('Enter your 2FA code:');
|
|
44
52
|
}
|
|
45
53
|
|
|
46
54
|
const tokenData = {
|
|
@@ -112,6 +120,7 @@ export async function list (params) {
|
|
|
112
120
|
'Creation IP address': token.ip,
|
|
113
121
|
Creation: formatDate(token.creationDate),
|
|
114
122
|
Expiration: formatDate(token.expirationDate),
|
|
123
|
+
State: token.state,
|
|
115
124
|
};
|
|
116
125
|
}));
|
|
117
126
|
}
|
package/src/commands/unlink.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import * as AppConfig from '../models/app_configuration.js';
|
|
2
2
|
import * as Application from '../models/application.js';
|
|
3
3
|
import { Logger } from '../logger.js';
|
|
4
|
+
import colors from 'colors/safe.js';
|
|
4
5
|
|
|
5
6
|
export async function unlink (params) {
|
|
6
7
|
const [alias] = params.args;
|
|
7
8
|
const app = await AppConfig.getAppDetails({ alias });
|
|
8
9
|
|
|
9
10
|
await Application.unlinkRepo(app.alias);
|
|
10
|
-
Logger.
|
|
11
|
+
Logger.printSuccess(`Application ${colors.green(app.appId)} has been successfully unlinked from local alias ${colors.green(app.alias)}!`);
|
|
11
12
|
};
|