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