| 1 | /******************************************************************************* | |
| 2 | * Copyhacked (H) 2012-2025. | |
| 3 | * This program and the accompanying materials | |
| 4 | * are made available under no term at all, use it like | |
| 5 | * you want, but share and discuss it | |
| 6 | * every time possible with every body. | |
| 7 | * | |
| 8 | * Contributors: | |
| 9 | * ron190 at ymail dot com - initial implementation | |
| 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 | * Keyboard key processing for terminal. | |
| 31 | */ | |
| 32 | public class KeyAdapterTerminal extends KeyAdapter { | |
| 33 | | |
| 34 | private static final Logger LOGGER = LogManager.getRootLogger(); | |
| 35 | ||
| 36 | /** | |
| 37 | * Terminal where keys are processed. | |
| 38 | */ | |
| 39 | private final AbstractExploit terminal; | |
| 40 | ||
| 41 | /** | |
| 42 | * Past commands entered by user. | |
| 43 | */ | |
| 44 | private final List<String> commandsHistory = new ArrayList<>(); | |
| 45 | ||
| 46 | /** | |
| 47 | * Current position in array of past commands. | |
| 48 | */ | |
| 49 | private int indexCommandsHistory = 0; | |
| 50 | ||
| 51 | /** | |
| 52 | * Create a keyboard processor for a terminal. | |
| 53 | * @param terminal Terminal where keys are processed | |
| 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); // Get current line | |
| 65 | ||
| 66 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
if (this.terminal.getIsEdited().get()) { // Cancel every user keyboard input if another command has just been sent |
| 67 |
1
1. keyPressed : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 68 | return; | |
| 69 | } | |
| 70 | | |
| 71 | // Get user input | |
| 72 | var command = new AtomicReference<>(StringUtils.EMPTY); | |
| 73 |
1
1. keyPressed : removed call to java/util/concurrent/atomic/AtomicReference::set → NO_COVERAGE |
command.set( |
| 74 | this.terminal.getText( | |
| 75 | root.getElement(lineNumber).getStartOffset(), | |
| 76 |
1
1. keyPressed : Replaced integer subtraction with addition → NO_COVERAGE |
root.getElement(lineNumber).getEndOffset() - root.getElement(lineNumber).getStartOffset() |
| 77 | ) | |
| 78 | .replace(this.terminal.getPrompt(), StringUtils.EMPTY) | |
| 79 | .trim() | |
| 80 | ); | |
| 81 | | |
| 82 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
if (keyEvent.getKeyCode() == KeyEvent.VK_ENTER) { // Validate user input ; disable text editing |
| 83 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::runCommand → NO_COVERAGE |
this.runCommand(keyEvent, command); |
| 84 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_UP) { // Get previous command |
| 85 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::appendPreviousCommand → NO_COVERAGE |
this.appendPreviousCommand(keyEvent, root, lineNumber, command); |
| 86 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_DOWN) { // Get next command |
| 87 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::appendNextCommand → NO_COVERAGE |
this.appendNextCommand(keyEvent, root, lineNumber, command); |
| 88 |
2
1. keyPressed : negated conditional → NO_COVERAGE 2. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_LEFT || keyEvent.getKeyCode() == KeyEvent.VK_BACK_SPACE) { // Go to the left until prompt |
| 89 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::moveCaretLeft → NO_COVERAGE |
this.moveCaretLeft(keyEvent, caretPosition, lineNumber); |
| 90 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_HOME) { // Get to the beginning of the line |
| 91 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::moveCaretHome → NO_COVERAGE |
this.moveCaretHome(keyEvent, lineNumber); |
| 92 |
1
1. keyPressed : negated conditional → NO_COVERAGE |
} else if (this.isKeyNotAllowed(keyEvent, caretPosition)) { |
| 93 |
1
1. keyPressed : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 94 |
3
1. keyPressed : negated conditional → NO_COVERAGE 2. keyPressed : Replaced bitwise AND with OR → NO_COVERAGE 3. keyPressed : negated conditional → NO_COVERAGE |
} else if (keyEvent.getKeyCode() == KeyEvent.VK_C && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0) { |
| 95 |
1
1. keyPressed : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal::cancelCommand → NO_COVERAGE |
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 |
1
1. isKeyNotAllowed : replaced boolean return with true for com/jsql/view/swing/terminal/util/KeyAdapterTerminal::isKeyNotAllowed → NO_COVERAGE |
return |
| 104 | // Cancel the select all shortcut Ctrl+A | |
| 105 |
3
1. isKeyNotAllowed : negated conditional → NO_COVERAGE 2. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE 3. isKeyNotAllowed : negated conditional → NO_COVERAGE |
keyEvent.getKeyCode() == KeyEvent.VK_A && (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0 |
| 106 | // Cancel the *beep* sound if deleting while at the end of line | |
| 107 |
2
1. isKeyNotAllowed : negated conditional → NO_COVERAGE 2. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_DELETE && caretPosition == this.terminal.getDocument().getLength() |
| 108 |
4
1. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE 2. isKeyNotAllowed : negated conditional → NO_COVERAGE 3. isKeyNotAllowed : Replaced bitwise AND with OR → NO_COVERAGE 4. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| (keyEvent.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0 && (keyEvent.getModifiersEx() & InputEvent.SHIFT_DOWN_MASK) != 0 |
| 109 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_PAGE_UP |
| 110 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_PAGE_DOWN |
| 111 |
1
1. isKeyNotAllowed : negated conditional → NO_COVERAGE |
|| keyEvent.getKeyCode() == KeyEvent.VK_TAB; |
| 112 | } | |
| 113 | ||
| 114 | private void cancelCommand(KeyEvent keyEvent) { | |
| 115 |
1
1. cancelCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 116 |
1
1. cancelCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::append → NO_COVERAGE |
this.terminal.append("\n"); |
| 117 |
1
1. cancelCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::reset → NO_COVERAGE |
this.terminal.reset(); |
| 118 | } | |
| 119 | ||
| 120 | private void moveCaretHome(KeyEvent keyEvent, int lineNumber) throws BadLocationException { | |
| 121 |
1
1. moveCaretHome : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 122 |
2
1. moveCaretHome : Replaced integer addition with subtraction → NO_COVERAGE 2. moveCaretHome : removed call to com/jsql/view/swing/terminal/AbstractExploit::setCaretPosition → NO_COVERAGE |
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 |
1
1. moveCaretLeft : Replaced integer subtraction with addition → NO_COVERAGE |
int newCaretPosition = caretPosition - this.terminal.getLineStartOffset(lineNumber); |
| 127 |
2
1. moveCaretLeft : changed conditional boundary → NO_COVERAGE 2. moveCaretLeft : negated conditional → NO_COVERAGE |
if (newCaretPosition <= this.terminal.getPrompt().length()) { |
| 128 |
1
1. moveCaretLeft : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
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 |
1
1. appendNextCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 139 | | |
| 140 |
2
1. appendNextCommand : changed conditional boundary → NO_COVERAGE 2. appendNextCommand : negated conditional → NO_COVERAGE |
if (this.indexCommandsHistory < this.commandsHistory.size()) { |
| 141 |
1
1. appendNextCommand : Replaced integer addition with subtraction → NO_COVERAGE |
this.indexCommandsHistory++; |
| 142 | } | |
| 143 | | |
| 144 |
3
1. appendNextCommand : negated conditional → NO_COVERAGE 2. appendNextCommand : negated conditional → NO_COVERAGE 3. appendNextCommand : changed conditional boundary → NO_COVERAGE |
if (!this.commandsHistory.isEmpty() && this.indexCommandsHistory < this.commandsHistory.size()) { |
| 145 |
1
1. appendNextCommand : removed call to javax/swing/text/Document::remove → NO_COVERAGE |
this.terminal.getDocument().remove( |
| 146 |
1
1. appendNextCommand : Replaced integer addition with subtraction → NO_COVERAGE |
root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(), |
| 147 |
1
1. appendNextCommand : Replaced integer subtraction with addition → NO_COVERAGE |
command.get().length() - 1 |
| 148 | ); | |
| 149 | | |
| 150 |
1
1. appendNextCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::append → NO_COVERAGE |
this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory)); |
| 151 |
1
1. appendNextCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::setCaretPosition → NO_COVERAGE |
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 |
1
1. appendPreviousCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 162 | | |
| 163 |
2
1. appendPreviousCommand : changed conditional boundary → NO_COVERAGE 2. appendPreviousCommand : negated conditional → NO_COVERAGE |
if (this.indexCommandsHistory > 0) { |
| 164 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
this.indexCommandsHistory--; |
| 165 | } | |
| 166 | | |
| 167 |
1
1. appendPreviousCommand : negated conditional → NO_COVERAGE |
if (!this.commandsHistory.isEmpty()) { |
| 168 | if ( | |
| 169 |
2
1. appendPreviousCommand : negated conditional → NO_COVERAGE 2. appendPreviousCommand : changed conditional boundary → NO_COVERAGE |
this.commandsHistory.size() > 1 |
| 170 |
2
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE 2. appendPreviousCommand : negated conditional → NO_COVERAGE |
&& this.indexCommandsHistory == this.commandsHistory.size() - 1 |
| 171 |
1
1. appendPreviousCommand : negated conditional → NO_COVERAGE |
&& StringUtils.isNotEmpty(command.get()) |
| 172 | ) { | |
| 173 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
this.indexCommandsHistory--; |
| 174 | } | |
| 175 | | |
| 176 |
1
1. appendPreviousCommand : removed call to javax/swing/text/Document::remove → NO_COVERAGE |
this.terminal.getDocument().remove( |
| 177 |
1
1. appendPreviousCommand : Replaced integer addition with subtraction → NO_COVERAGE |
root.getElement(lineNumber).getStartOffset() + this.terminal.getPrompt().length(), |
| 178 |
1
1. appendPreviousCommand : Replaced integer subtraction with addition → NO_COVERAGE |
command.get().length() - 1 |
| 179 | ); | |
| 180 | | |
| 181 |
1
1. appendPreviousCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::append → NO_COVERAGE |
this.terminal.append(this.commandsHistory.get(this.indexCommandsHistory)); |
| 182 |
1
1. appendPreviousCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::setCaretPosition → NO_COVERAGE |
this.terminal.setCaretPosition(this.terminal.getDocument().getLength()); |
| 183 | } | |
| 184 | } | |
| 185 | ||
| 186 | private void runCommand(KeyEvent keyEvent, AtomicReference<String> command) { | |
| 187 |
1
1. runCommand : removed call to java/util/concurrent/atomic/AtomicBoolean::set → NO_COVERAGE |
this.terminal.getIsEdited().set(true); |
| 188 |
1
1. runCommand : removed call to java/awt/event/KeyEvent::consume → NO_COVERAGE |
keyEvent.consume(); |
| 189 |
1
1. runCommand : removed call to com/jsql/view/swing/terminal/AbstractExploit::setEditable → NO_COVERAGE |
this.terminal.setEditable(false); |
| 190 | | |
| 191 | // Populate cmd list for key up/down | |
| 192 |
1
1. runCommand : negated conditional → NO_COVERAGE |
if (StringUtils.isNotEmpty(command.get())) { |
| 193 | this.commandsHistory.add(command.get()); | |
| 194 | this.indexCommandsHistory = this.commandsHistory.size(); | |
| 195 | } | |
| 196 | ||
| 197 | new SwingWorker<>() { // Thread to give back control to user (SwingUtilities does not) | |
| 198 | @Override | |
| 199 | protected Object doInBackground() { | |
| 200 | // Inside Swing thread to avoid flickering | |
| 201 |
1
1. doInBackground : removed call to java/lang/Thread::setName → NO_COVERAGE |
Thread.currentThread().setName("SwingWorkerKeyAdapterTerminal"); |
| 202 | ||
| 203 | AbstractExploit terminalCommand = KeyAdapterTerminal.this.terminal; | |
| 204 |
1
1. doInBackground : removed call to com/jsql/view/swing/terminal/AbstractExploit::append → NO_COVERAGE |
terminalCommand.append("\n"); |
| 205 | | |
| 206 |
1
1. doInBackground : negated conditional → NO_COVERAGE |
if (StringUtils.isNotEmpty(command.get())) { |
| 207 |
1
1. doInBackground : removed call to com/jsql/view/swing/terminal/AbstractExploit::setCaretPosition → NO_COVERAGE |
terminalCommand.setCaretPosition(terminalCommand.getDocument().getLength()); |
| 208 |
1
1. doInBackground : removed call to com/jsql/view/swing/terminal/AbstractExploit::action → NO_COVERAGE |
terminalCommand.action( |
| 209 | command.get(), | |
| 210 | terminalCommand.getUuidShell(), | |
| 211 | terminalCommand.getUrlShell(), | |
| 212 | terminalCommand.getLoginPassword() | |
| 213 | ); | |
| 214 | } else { | |
| 215 |
1
1. doInBackground : removed call to com/jsql/view/swing/terminal/AbstractExploit::reset → NO_COVERAGE |
terminalCommand.reset(); |
| 216 | } | |
| 217 | return null; | |
| 218 | } | |
| 219 |
1
1. runCommand : removed call to com/jsql/view/swing/terminal/util/KeyAdapterTerminal$1::execute → NO_COVERAGE |
}.execute(); |
| 220 | } | |
| 221 | } | |
Mutations | ||
| 66 |
1.1 |
|
| 67 |
1.1 |
|
| 73 |
1.1 |
|
| 76 |
1.1 |
|
| 82 |
1.1 |
|
| 83 |
1.1 |
|
| 84 |
1.1 |
|
| 85 |
1.1 |
|
| 86 |
1.1 |
|
| 87 |
1.1 |
|
| 88 |
1.1 2.2 |
|
| 89 |
1.1 |
|
| 90 |
1.1 |
|
| 91 |
1.1 |
|
| 92 |
1.1 |
|
| 93 |
1.1 |
|
| 94 |
1.1 2.2 3.3 |
|
| 95 |
1.1 |
|
| 103 |
1.1 |
|
| 105 |
1.1 2.2 3.3 |
|
| 107 |
1.1 2.2 |
|
| 108 |
1.1 2.2 3.3 4.4 |
|
| 109 |
1.1 |
|
| 110 |
1.1 |
|
| 111 |
1.1 |
|
| 115 |
1.1 |
|
| 116 |
1.1 |
|
| 117 |
1.1 |
|
| 121 |
1.1 |
|
| 122 |
1.1 2.2 |
|
| 126 |
1.1 |
|
| 127 |
1.1 2.2 |
|
| 128 |
1.1 |
|
| 138 |
1.1 |
|
| 140 |
1.1 2.2 |
|
| 141 |
1.1 |
|
| 144 |
1.1 2.2 3.3 |
|
| 145 |
1.1 |
|
| 146 |
1.1 |
|
| 147 |
1.1 |
|
| 150 |
1.1 |
|
| 151 |
1.1 |
|
| 161 |
1.1 |
|
| 163 |
1.1 2.2 |
|
| 164 |
1.1 |
|
| 167 |
1.1 |
|
| 169 |
1.1 2.2 |
|
| 170 |
1.1 2.2 |
|
| 171 |
1.1 |
|
| 173 |
1.1 |
|
| 176 |
1.1 |
|
| 177 |
1.1 |
|
| 178 |
1.1 |
|
| 181 |
1.1 |
|
| 182 |
1.1 |
|
| 187 |
1.1 |
|
| 188 |
1.1 |
|
| 189 |
1.1 |
|
| 192 |
1.1 |
|
| 201 |
1.1 |
|
| 204 |
1.1 |
|
| 206 |
1.1 |
|
| 207 |
1.1 |
|
| 208 |
1.1 |
|
| 215 |
1.1 |
|
| 219 |
1.1 |