1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.maven.cling.invoker.mvnenc.goals;
20
21 import javax.inject.Inject;
22 import javax.inject.Named;
23 import javax.inject.Singleton;
24
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Objects;
28
29 import org.apache.maven.api.services.MessageBuilderFactory;
30 import org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker;
31 import org.codehaus.plexus.components.secdispatcher.DispatcherMeta;
32 import org.codehaus.plexus.components.secdispatcher.SecDispatcher;
33 import org.codehaus.plexus.components.secdispatcher.model.Config;
34 import org.codehaus.plexus.components.secdispatcher.model.ConfigProperty;
35 import org.codehaus.plexus.components.secdispatcher.model.SettingsSecurity;
36 import org.jline.consoleui.elements.ConfirmChoice;
37 import org.jline.consoleui.prompt.ConfirmResult;
38 import org.jline.consoleui.prompt.ConsolePrompt;
39 import org.jline.consoleui.prompt.PromptResultItemIF;
40 import org.jline.consoleui.prompt.builder.ListPromptBuilder;
41 import org.jline.consoleui.prompt.builder.PromptBuilder;
42 import org.jline.reader.Candidate;
43 import org.jline.reader.Completer;
44 import org.jline.reader.LineReader;
45 import org.jline.reader.ParsedLine;
46 import org.jline.utils.Colors;
47
48 import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.BAD_OPERATION;
49 import static org.apache.maven.cling.invoker.mvnenc.DefaultEncryptInvoker.OK;
50
51
52
53
54 @Singleton
55 @Named("init")
56 public class Init extends GoalSupport {
57 private static final String NONE = "__none__";
58
59 @Inject
60 public Init(MessageBuilderFactory messageBuilderFactory, SecDispatcher secDispatcher) {
61 super(messageBuilderFactory, secDispatcher);
62 }
63
64 @Override
65 public int execute(DefaultEncryptInvoker.LocalContext context) throws Exception {
66 context.addInHeader(context.style.italic().bold().foreground(Colors.rgbColor("yellow")), "goal: init");
67 context.addInHeader("");
68
69 ConsolePrompt prompt = context.prompt;
70 boolean force = context.invokerRequest.options().force().orElse(false);
71 boolean yes = context.invokerRequest.options().yes().orElse(false);
72
73 if (configExists() && !force) {
74 context.terminal
75 .writer()
76 .println(
77 messageBuilderFactory
78 .builder()
79 .error(
80 "Error: configuration exist. Use --force if you want to reset existing configuration."));
81 return BAD_OPERATION;
82 }
83
84 SettingsSecurity config = secDispatcher.readConfiguration(true);
85
86
87 config.setDefaultDispatcher(null);
88 config.getConfigurations().clear();
89
90 Map<String, PromptResultItemIF> result = prompt.prompt(
91 context.header, dispatcherPrompt(prompt.getPromptBuilder()).build());
92 if (result == null) {
93 throw new InterruptedException();
94 }
95 if (NONE.equals(result.get("defaultDispatcher").getResult())) {
96 context.terminal
97 .writer()
98 .println(messageBuilderFactory
99 .builder()
100 .warning(
101 "Maven4 SecDispatcher disabled; Maven3 fallback may still work, use `mvnenc diag` to check")
102 .build());
103 secDispatcher.writeConfiguration(config);
104 return OK;
105 }
106 config.setDefaultDispatcher(result.get("defaultDispatcher").getResult());
107
108 DispatcherMeta meta = secDispatcher.availableDispatchers().stream()
109 .filter(d -> Objects.equals(config.getDefaultDispatcher(), d.name()))
110 .findFirst()
111 .orElseThrow();
112 if (!meta.fields().isEmpty()) {
113 result = prompt.prompt(
114 context.header,
115 configureDispatcher(context, meta, prompt.getPromptBuilder())
116 .build());
117 if (result == null) {
118 throw new InterruptedException();
119 }
120
121 List<Map.Entry<String, PromptResultItemIF>> editables = result.entrySet().stream()
122 .filter(e -> e.getValue().getResult().contains("$"))
123 .toList();
124 if (!editables.isEmpty()) {
125 context.addInHeader("");
126 context.addInHeader("Please customize the editable value:");
127 Map<String, PromptResultItemIF> editMap;
128 for (Map.Entry<String, PromptResultItemIF> editable : editables) {
129 String template = editable.getValue().getResult();
130 String prefix = template.substring(0, template.indexOf("$"));
131 editMap = prompt.prompt(
132 context.header,
133 prompt.getPromptBuilder()
134 .createInputPrompt()
135 .name("edit")
136 .message(template)
137 .addCompleter(new Completer() {
138 @Override
139 public void complete(
140 LineReader reader, ParsedLine line, List<Candidate> candidates) {
141 if (!line.line().startsWith(prefix)) {
142 candidates.add(
143 new Candidate(prefix, prefix, null, null, null, null, false));
144 }
145 }
146 })
147 .addPrompt()
148 .build());
149 if (editMap == null) {
150 throw new InterruptedException();
151 }
152 result.put(editable.getKey(), editMap.get("edit"));
153 }
154 }
155
156 Config dispatcherConfig = new Config();
157 dispatcherConfig.setName(meta.name());
158 for (DispatcherMeta.Field field : meta.fields()) {
159 ConfigProperty property = new ConfigProperty();
160 property.setName(field.getKey());
161 property.setValue(result.get(field.getKey()).getResult());
162 dispatcherConfig.addProperty(property);
163 }
164 if (!dispatcherConfig.getProperties().isEmpty()) {
165 config.addConfiguration(dispatcherConfig);
166 }
167 }
168
169 if (yes) {
170 secDispatcher.writeConfiguration(config);
171 } else {
172 context.addInHeader("");
173 context.addInHeader("Values set:");
174 context.addInHeader("defaultDispatcher=" + config.getDefaultDispatcher());
175 for (Config c : config.getConfigurations()) {
176 context.addInHeader(" dispatcherName=" + c.getName());
177 for (ConfigProperty cp : c.getProperties()) {
178 context.addInHeader(" " + cp.getName() + "=" + cp.getValue());
179 }
180 }
181
182 result = prompt.prompt(
183 context.header, confirmPrompt(prompt.getPromptBuilder()).build());
184 ConfirmResult confirm = (ConfirmResult) result.get("confirm");
185 if (confirm.getConfirmed() == ConfirmChoice.ConfirmationValue.YES) {
186 context.terminal
187 .writer()
188 .println(messageBuilderFactory
189 .builder()
190 .info("Writing out the configuration...")
191 .build());
192 secDispatcher.writeConfiguration(config);
193 } else {
194 context.terminal
195 .writer()
196 .println(messageBuilderFactory
197 .builder()
198 .warning("Values not accepted; not saving configuration.")
199 .build());
200 return BAD_OPERATION;
201 }
202 }
203
204 return OK;
205 }
206
207 protected PromptBuilder confirmPrompt(PromptBuilder promptBuilder) {
208 promptBuilder
209 .createConfirmPromp()
210 .name("confirm")
211 .message("Are values above correct?")
212 .defaultValue(ConfirmChoice.ConfirmationValue.YES)
213 .addPrompt();
214 return promptBuilder;
215 }
216
217 protected PromptBuilder dispatcherPrompt(PromptBuilder promptBuilder) {
218 ListPromptBuilder listPromptBuilder = promptBuilder
219 .createListPrompt()
220 .name("defaultDispatcher")
221 .message("Which dispatcher you want to use as default?");
222 listPromptBuilder
223 .newItem()
224 .name(NONE)
225 .text("None (disable MavenSecDispatcher)")
226 .add();
227 for (DispatcherMeta meta : secDispatcher.availableDispatchers()) {
228 if (!meta.isHidden()) {
229 listPromptBuilder
230 .newItem()
231 .name(meta.name())
232 .text(meta.displayName())
233 .add();
234 }
235 }
236 listPromptBuilder.addPrompt();
237 return promptBuilder;
238 }
239
240 private PromptBuilder configureDispatcher(
241 DefaultEncryptInvoker.LocalContext context, DispatcherMeta dispatcherMeta, PromptBuilder promptBuilder)
242 throws Exception {
243 context.addInHeader(
244 context.style.italic().bold().foreground(Colors.rgbColor("yellow")),
245 "Configure " + dispatcherMeta.displayName());
246 context.addInHeader("");
247
248 for (DispatcherMeta.Field field : dispatcherMeta.fields()) {
249 String fieldKey = field.getKey();
250 String fieldDescription = "Configure " + fieldKey + ": " + field.getDescription();
251 if (field.getOptions().isPresent()) {
252
253 ListPromptBuilder listPromptBuilder =
254 promptBuilder.createListPrompt().name(fieldKey).message(fieldDescription);
255 for (DispatcherMeta.Field option : field.getOptions().get()) {
256 listPromptBuilder
257 .newItem()
258 .name(
259 option.getDefaultValue().isPresent()
260 ? option.getDefaultValue().get()
261 : option.getKey())
262 .text(option.getDescription())
263 .add();
264 }
265 listPromptBuilder.addPrompt();
266 } else if (field.getDefaultValue().isPresent()) {
267
268 promptBuilder
269 .createInputPrompt()
270 .name(fieldKey)
271 .message(fieldDescription)
272 .defaultValue(field.getDefaultValue().get())
273 .addPrompt();
274 } else {
275
276 promptBuilder
277 .createInputPrompt()
278 .name(fieldKey)
279 .message(fieldDescription)
280 .addPrompt();
281 }
282 }
283 return promptBuilder;
284 }
285 }