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