1
2
3
4
5
6
7
8
9
10
11 package com.jsql.view.swing.terminal.util;
12
13 import com.jsql.util.LogLevelUtil;
14 import com.jsql.view.swing.terminal.AbstractExploit;
15 import org.apache.commons.lang3.StringUtils;
16 import org.apache.logging.log4j.LogManager;
17 import org.apache.logging.log4j.Logger;
18
19 import javax.swing.*;
20 import javax.swing.text.BadLocationException;
21 import javax.swing.text.Element;
22 import java.awt.event.InputEvent;
23 import java.awt.event.KeyAdapter;
24 import java.awt.event.KeyEvent;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.concurrent.atomic.AtomicReference;
28
29
30
31
32 public class KeyAdapterTerminal extends KeyAdapter {
33
34
35
36
37 private static final Logger LOGGER = LogManager.getRootLogger();
38
39
40
41
42 private final AbstractExploit terminal;
43
44
45
46
47 private final List<String> commandsHistory = new ArrayList<>();
48
49
50
51
52 private int indexCommandsHistory = 0;
53
54
55
56
57
58 public KeyAdapterTerminal(AbstractExploit terminal) {
59 this.terminal = terminal;
60 }
61
62 @Override
63 public void keyPressed(KeyEvent keyEvent) {
64 try {
65 var root = this.terminal.getDocument().getDefaultRootElement();
66 int caretPosition = this.terminal.getCaretPosition();
67 int lineNumber = this.terminal.getLineOfOffset(caretPosition);
68
69 if (this.terminal.getIsEdited().get()) {
70 keyEvent.consume();
71 return;
72 }
73
74
75 var command = new AtomicReference<>(StringUtils.EMPTY);
76 command.set(
77 this.terminal.getText(
78 root.getElement(lineNumber).getStartOffset(),
79 root.getElement(lineNumber).getEndOffset() - root.getElement(lineNumber).getStartOffset()
80 )
81 .replace(this.terminal.getPrompt(), StringUtils.EMPTY)
82 .trim()
83 );
84
85 if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) {
86 this.runCommand(keyEvent, command);
87 } else if (keyEvent.getKeyCode() == KeyEvent.VK_UP) {
88 this.appendPreviousCommand(keyEvent, root, lineNumber, command);
89 } else if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN) {
90 this.appendNextCommand(keyEvent, root, lineNumber, command);
91 } else if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT || keyEvent.getKeyCode() == KeyEvent.VK_BACK_SPACE) {
92 this.moveCaretLeft(keyEvent, caretPosition, lineNumber);
93 } else if (keyEvent.getKeyCode() == KeyEvent.VK_HOME) {
94 this.moveCaretHome(keyEvent, lineNumber);
95 } else if (this.isKeyNotAllowed(keyEvent, caretPosition)) {
96 keyEvent.consume();
97 } else if (keyEvent.getKeyCode() == KeyEvent.VK_C && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) {
98 this.cancelCommand(keyEvent);
99 }
100 } catch (BadLocationException e) {
101 LOGGER.log(LogLevelUtil.CONSOLE_JAVA, e, e);
102 }
103 }
104
105 private boolean isKeyNotAllowed(KeyEvent keyEvent, int caretPosition) {
106 return
107
108 keyEvent.getKeyCode() == KeyEvent.VK_A && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0
109
110 || keyEvent.getKeyCode() == KeyEvent.VK_DELETE && caretPosition == this.terminal.getDocument().getLength()
111 || (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0 && (keyEvent.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0
112 || keyEvent.getKeyCode() == KeyEvent.VK_PAGE_UP
113 || keyEvent.getKeyCode() == KeyEvent.VK_PAGE_DOWN
114 || keyEvent.getKeyCode() == KeyEvent.VK_TAB;
115 }
116
117 private void cancelCommand(KeyEvent keyEvent) {
118 keyEvent.consume();
119 this.terminal.append("\n");
120 this.terminal.reset();
121 }
122
123 private void moveCaretHome(KeyEvent keyEvent, int lineNumber) throws BadLocationException {
124 keyEvent.consume();
125 this.terminal.setCaretPosition(this.terminal.getLineStartOffset(lineNumber) + this.terminal.getPrompt().length());
126 }
127
128 private void moveCaretLeft(KeyEvent keyEvent, int caretPosition, int lineNumber) throws BadLocationException {
129 int newCaretPosition = caretPosition - this.terminal.getLineStartOffset(lineNumber);
130 if (newCaretPosition <= this.terminal.getPrompt().length()) {
131 keyEvent.consume();
132 }
133 }
134
135 private void appendNextCommand(
136 KeyEvent keyEvent,
137 Element root,
138 int lineNumber,
139 AtomicReference<String> command
140 ) throws BadLocationException {
141 keyEvent.consume();
142
143 if (this.indexCommandsHistory < this.commandsHistory.size()) {
144 this.indexCommandsHistory++;
145 }
146
147 if (!this.commandsHistory.isEmpty() && this.indexCommandsHistory < this.commandsHistory.size()) {
148 this.terminal.getDocument().remove(
149 root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(),
150 command.get().length() - 1
151 );
152
153 this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory));
154 this.terminal.setCaretPosition(this.terminal.getDocument().getLength());
155 }
156 }
157
158 private void appendPreviousCommand(
159 KeyEvent keyEvent,
160 Element root,
161 int lineNumber,
162 AtomicReference<String> command
163 ) throws BadLocationException {
164 keyEvent.consume();
165
166 if (this.indexCommandsHistory > 0) {
167 this.indexCommandsHistory--;
168 }
169
170 if (!this.commandsHistory.isEmpty()) {
171 if (
172 this.commandsHistory.size() > 1
173 && this.indexCommandsHistory == this.commandsHistory.size() - 1
174 && StringUtils.isNotEmpty(command.get())
175 ) {
176 this.indexCommandsHistory--;
177 }
178
179 this.terminal.getDocument().remove(
180 root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(),
181 command.get().length() - 1
182 );
183
184 this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory));
185 this.terminal.setCaretPosition(this.terminal.getDocument().getLength());
186 }
187 }
188
189 private void runCommand(KeyEvent keyEvent, AtomicReference<String> command) {
190 this.terminal.getIsEdited().set(true);
191 keyEvent.consume();
192 this.terminal.setEditable(false);
193
194
195 if (StringUtils.isNotEmpty(command.get())) {
196 this.commandsHistory.add(command.get());
197 this.indexCommandsHistory = this.commandsHistory.size();
198 }
199
200 new SwingWorker<>() {
201 @Override
202 protected Object doInBackground() {
203
204 Thread.currentThread().setName("SwingWorkerKeyAdapterTerminal");
205
206 AbstractExploit terminalCommand = KeyAdapterTerminal.this.terminal;
207 terminalCommand.append("\n");
208
209 if (StringUtils.isNotEmpty(command.get())) {
210 terminalCommand.setCaretPosition(terminalCommand.getDocument().getLength());
211 terminalCommand.action(
212 command.get(),
213 terminalCommand.getUuidShell(),
214 terminalCommand.getUrlShell(),
215 terminalCommand.getLoginPassword()
216 );
217 } else {
218 terminalCommand.reset();
219 }
220 return null;
221 }
222 }.execute();
223 }
224 }