-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathconfigure.ts
193 lines (150 loc) · 7.22 KB
/
configure.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import Command from '../command';
import Config from '../config';
import ConfigEntries from '../constants/configEntries';
import Encrypter from '../encrypter';
import * as setFlag from '../flags';
import Insurer from '../insurer';
import IConfig from '../interfaces/iConfig';
import IConfigEntry from '../interfaces/iConfigEntry';
import ora = require('ora');
export default class ConfigureCommand extends Command {
public static description = 'Allows to modify the existing configuration file. In interactive mode all flags will be ignored (except Steam Guard).';
public static aliases = ['config'];
public static examples = [
'magma configure',
'magma configure --steamCmd "/var/steamcmd"',
'magma configure -n -u UserName',
];
public static flags = {
batchScript: setFlag.batchScript,
linuxGsmInstanceConfig: setFlag.linuxGsmInstanceConfig,
nonInteractive: setFlag.nonInteractive,
password: setFlag.password,
server: setFlag.server,
steamCmd: setFlag.steamCmd,
steamGuard: setFlag.steamGuard,
username: setFlag.username,
webhookUrl: setFlag.webhookUrl,
};
public async init(): Promise<void> {
Config.ensureIsInitialized();
Config.ensureIsLatestVersion();
}
private insurer?: Insurer;
private spinner?: ora.Ora;
private steamCmdPath?: string;
private steamGuard?: string;
public async run(): Promise<void> {
const { flags } = this.parse(ConfigureCommand);
this.spinner = ora({ discardStdin: true, text: 'Validating Steam credentials' });
this.insurer = new Insurer(flags.nonInteractive, this.spinner);
this.steamGuard = flags.steamGuard;
// If any other flags were passed (--nonInteractive is always present)
if (Object.keys(flags).length > 1) {
// See Prompt.forConfigEntries() comment
if (flags.steamCmd) {
this.steamCmdPath = await this.validateEntry(this.convertFlagToEntry('steamCmdPath') as any, flags.steamCmd);
Config.set('steamCmdPath', this.steamCmdPath as string);
} else {
for (const key of Object.keys(flags)) {
if (key === 'steamCmd' || key === 'steamGuard' || key === 'nonInteractive') { continue; }
let configKey: keyof IConfig;
let value;
switch (key) {
case 'batchScript':
configKey = 'batchScript';
value = await this.validateEntry(
this.convertFlagToEntry('batchScript'), flags.batchScript
);
break;
case 'linuxGsmInstanceConfig':
configKey = 'linuxGsm';
value = await this.validateEntry(
this.convertFlagToEntry('linuxGsm'), flags.linuxGsmInstanceConfig
);
break;
case 'password':
configKey = 'credentials';
if (!flags.username) { throw new Error('The --password flag requires the --username flag.'); }
value = await this.validateEntry(
this.convertFlagToEntry('credentials'), flags.username, flags.password
);
break;
case 'server':
configKey = 'serverPath';
value = await this.validateEntry(
this.convertFlagToEntry('serverPath'), flags.server
);
break;
case 'username':
configKey = 'credentials';
if (!flags.password) { throw new Error('The --username flag requires the --password flag.'); }
break;
case 'webhookUrl':
configKey = 'webhookUrl';
value = await this.validateEntry(
this.convertFlagToEntry('webhookUrl'), flags.webhookUrl
);
break;
default:
throw new Error(`Encountered an undefined flag: ${key}`);
}
Config.set(configKey, value as any);
}
}
} else {
if (flags.nonInteractive) {
throw new Error('No flags were specified that indicate which properties should be updated.');
}
const configEntries = await this.insurer.prompt.forConfigEntries();
for (const entry of configEntries) {
const data = await this.validateEntry(entry, []);
Config.set(entry.config, data);
}
}
}
/**
* This could return **undefined**! But if used with safe, existant keys that are defined in the ConfigEntry constants then it should be fine.
*/
private convertFlagToEntry(type: keyof IConfig): IConfigEntry {
return ConfigEntries.find(e => e.config === type) as IConfigEntry;
}
private async validateEntry<T extends IConfigEntry, K extends IConfig[T['config']]>(entry: T, ...values: any): Promise<K | never> {
if (!this.insurer) { throw new Error('Something went wrong, the insurer class is undefined.'); }
let output: K | undefined;
switch (entry.config) {
case 'credentials':
let credentials = await this.insurer.ensureValidLogin(...values);
this.spinner?.start();
while (await this.insurer.validate.credentials(
credentials, Config.get('key'), this.steamCmdPath ?? Config.get('steamCmdPath'), this.steamGuard) === false) {
this.spinner?.fail('Failed to login');
credentials = await this.insurer.prompt.forCredentials();
this.spinner?.start();
}
this.spinner?.succeed('Logged in');
credentials.password = new Encrypter(Config.get('key')).encrypt(credentials.password);
output = credentials as K;
break;
case 'batchScript':
output = await this.insurer.ensureValidBatchScript(...values) as K;
break;
case 'linuxGsm':
output = await this.insurer.ensureValidLinuxGsm(...values) as K;
break;
case 'serverPath':
output = await this.insurer.ensureValidServer(...values) as K;
break;
case 'steamCmdPath':
output = await this.insurer.ensureValidSteamCmd(...values) as K;
this.steamCmdPath = output as string;
break;
case 'webhookUrl':
output = await this.insurer.ensureValidWebhookUrl(...values) as K;
break;
default:
throw new Error('Property is not supported.');
}
return output;
}
}