mirror of
https://github.com/iDescriptor/iDescriptor.git
synced 2026-06-21 19:35:49 +08:00
WIP: implement JailbrokenWidget
This commit is contained in:
+7
-2
@@ -26,8 +26,11 @@ endif()
|
||||
include_directories(${CUSTOM_INCLUDE_PATH})
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Svg SvgWidgets Multimedia Network)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg SvgWidgets Multimedia Network)
|
||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Svg SvgWidgets Multimedia Network QuickControls2)
|
||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Svg SvgWidgets Multimedia Network QuickControls2)
|
||||
|
||||
# Add QTermWidget
|
||||
pkg_check_modules(QTERMWIDGET REQUIRED IMPORTED_TARGET qtermwidget6)
|
||||
|
||||
# Link directly to libraries in /usr/local/lib instead of using pkg-config
|
||||
# Force NO_DEFAULT_PATH to only search in /usr/local/lib
|
||||
@@ -177,6 +180,7 @@ target_link_libraries(iDescriptor PRIVATE
|
||||
Qt${QT_VERSION_MAJOR}::Location
|
||||
Qt${QT_VERSION_MAJOR}::Positioning
|
||||
Qt${QT_VERSION_MAJOR}::QuickWidgets
|
||||
Qt${QT_VERSION_MAJOR}::QuickControls2
|
||||
${IMOBILEDEVICE_LIBRARY}
|
||||
${IMOBILEDEVICE_GLUE_LIBRARY}
|
||||
# ${PLIST_LIBRARY}
|
||||
@@ -191,6 +195,7 @@ target_link_libraries(iDescriptor PRIVATE
|
||||
PkgConfig::USB
|
||||
PkgConfig::PLIST
|
||||
PkgConfig::QRENCODE
|
||||
PkgConfig::QTERMWIDGET
|
||||
airplay
|
||||
ipatool-go
|
||||
)
|
||||
|
||||
+280
-3
@@ -1,8 +1,285 @@
|
||||
#include "jailbrokenwidget.h"
|
||||
|
||||
|
||||
#include "appcontext.h"
|
||||
#include "iDescriptor-ui.h"
|
||||
#include "iDescriptor.h"
|
||||
#include <QDebug>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QGraphicsView>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWidget>
|
||||
#include <qtermwidget6/qtermwidget.h>
|
||||
#include <unistd.h>
|
||||
|
||||
JailbrokenWidget::JailbrokenWidget(QWidget *parent) : QWidget{parent}
|
||||
{
|
||||
// TODO: implement
|
||||
QHBoxLayout *mainLayout = new QHBoxLayout(this);
|
||||
mainLayout->setContentsMargins(2, 2, 2, 2);
|
||||
mainLayout->setSpacing(2);
|
||||
|
||||
QGraphicsScene *scene = new QGraphicsScene(this);
|
||||
QGraphicsPixmapItem *pixmapItem =
|
||||
new QGraphicsPixmapItem(QPixmap(":/resources/iphone.png"));
|
||||
scene->addItem(pixmapItem);
|
||||
|
||||
QGraphicsView *graphicsView = new ResponsiveGraphicsView(scene, this);
|
||||
graphicsView->setRenderHint(QPainter::Antialiasing);
|
||||
graphicsView->setMinimumWidth(200);
|
||||
graphicsView->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Expanding);
|
||||
graphicsView->setStyleSheet("background: transparent; border: none;");
|
||||
|
||||
mainLayout->addWidget(graphicsView, 1); // Stretch factor 1
|
||||
|
||||
connect(AppContext::sharedInstance(), &AppContext::deviceAdded, this,
|
||||
[this](iDescriptorDevice *device) { deviceConnected(device); });
|
||||
|
||||
// Right side: Info and Terminal
|
||||
QWidget *rightContainer = new QWidget();
|
||||
rightContainer->setSizePolicy(QSizePolicy::Expanding,
|
||||
QSizePolicy::Expanding);
|
||||
rightContainer->setMinimumWidth(400);
|
||||
QVBoxLayout *rightLayout = new QVBoxLayout(rightContainer);
|
||||
rightLayout->setContentsMargins(15, 15, 15, 15);
|
||||
rightLayout->setSpacing(10);
|
||||
|
||||
m_infoLabel = new QLabel("Connect a jailbroken device");
|
||||
rightLayout->addWidget(m_infoLabel);
|
||||
|
||||
m_connectButton = new QPushButton("Connect SSH Terminal");
|
||||
m_connectButton->setEnabled(false);
|
||||
connect(m_connectButton, &QPushButton::clicked, this,
|
||||
&JailbrokenWidget::onConnectSSH);
|
||||
rightLayout->addWidget(m_connectButton);
|
||||
|
||||
setupTerminal();
|
||||
rightLayout->addWidget(m_terminal, 1); // Give terminal most of the space
|
||||
|
||||
mainLayout->addWidget(rightContainer, 3); // Stretch factor 3
|
||||
}
|
||||
|
||||
void JailbrokenWidget::setupTerminal()
|
||||
{
|
||||
m_terminal = new QTermWidget(0, this); // 0 = use default shell
|
||||
m_terminal->setMinimumHeight(400);
|
||||
m_terminal->setScrollBarPosition(QTermWidget::ScrollBarRight);
|
||||
|
||||
// Set terminal colors and font
|
||||
m_terminal->setColorScheme("DarkPastels");
|
||||
|
||||
// Initially hide the terminal
|
||||
m_terminal->hide();
|
||||
}
|
||||
|
||||
void JailbrokenWidget::connectTerminalToProcess()
|
||||
{
|
||||
if (!m_terminal || !sshProcess)
|
||||
return;
|
||||
|
||||
// Connect terminal input to SSH process stdin
|
||||
connect(m_terminal, &QTermWidget::sendData, this,
|
||||
[this](const char *data, int size) {
|
||||
if (sshProcess && sshProcess->state() == QProcess::Running) {
|
||||
sshProcess->write(data, size);
|
||||
}
|
||||
});
|
||||
|
||||
// Connect SSH process stdout/stderr to terminal
|
||||
connect(sshProcess, &QProcess::readyReadStandardOutput, this, [this]() {
|
||||
QByteArray data = sshProcess->readAllStandardOutput();
|
||||
if (m_terminal && !data.isEmpty()) {
|
||||
// Write directly to the terminal's PTY
|
||||
write(m_terminal->getPtySlaveFd(), data.data(), data.size());
|
||||
}
|
||||
});
|
||||
|
||||
connect(sshProcess, &QProcess::readyReadStandardError, this, [this]() {
|
||||
QByteArray data = sshProcess->readAllStandardError();
|
||||
if (m_terminal && !data.isEmpty()) {
|
||||
// Write directly to the terminal's PTY
|
||||
write(m_terminal->getPtySlaveFd(), data.data(), data.size());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void JailbrokenWidget::deviceConnected(iDescriptorDevice *device)
|
||||
{
|
||||
if (device->deviceInfo.jailbroken) {
|
||||
m_device = device;
|
||||
m_infoLabel->setText("Jailbroken device connected");
|
||||
m_connectButton->setEnabled(true);
|
||||
m_connectButton->setText("Connect SSH Terminal");
|
||||
}
|
||||
}
|
||||
|
||||
void JailbrokenWidget::onConnectSSH()
|
||||
{
|
||||
if (m_sshConnected) {
|
||||
// Disconnect SSH
|
||||
if (sshProcess) {
|
||||
sshProcess->terminate();
|
||||
sshProcess->waitForFinished(3000);
|
||||
sshProcess = nullptr;
|
||||
}
|
||||
if (iproxyProcess) {
|
||||
iproxyProcess->terminate();
|
||||
iproxyProcess->waitForFinished(3000);
|
||||
iproxyProcess = nullptr;
|
||||
}
|
||||
m_terminal->hide();
|
||||
m_connectButton->setText("Connect SSH Terminal");
|
||||
m_infoLabel->setText("SSH disconnected");
|
||||
m_sshConnected = false;
|
||||
m_isInitialized = false;
|
||||
return;
|
||||
}
|
||||
|
||||
initWidget();
|
||||
}
|
||||
|
||||
void JailbrokenWidget::initWidget()
|
||||
{
|
||||
if (m_isInitialized)
|
||||
return;
|
||||
m_isInitialized = true;
|
||||
|
||||
if (!m_device) {
|
||||
m_infoLabel->setText("Device is not jailbroken");
|
||||
return;
|
||||
}
|
||||
|
||||
m_connectButton->setEnabled(false);
|
||||
m_infoLabel->setText("Setting up SSH tunnel...");
|
||||
|
||||
// Start iproxy first
|
||||
iproxyProcess = new QProcess(this);
|
||||
iproxyProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
connect(iproxyProcess, &QProcess::errorOccurred, this,
|
||||
[this](QProcess::ProcessError error) {
|
||||
m_infoLabel->setText("Error: " + iproxyProcess->errorString());
|
||||
m_connectButton->setEnabled(true);
|
||||
qDebug() << "iproxy error:" << error;
|
||||
});
|
||||
|
||||
// connect(iproxyProcess, &QProcess::readyReadStandardOutput, this, [this]()
|
||||
// {
|
||||
// QByteArray output = iproxyProcess->readAllStandardOutput();
|
||||
// qDebug() << "iproxy output:" << output;
|
||||
|
||||
// // Once iproxy is running, start SSH terminal after a short delay
|
||||
// if (!m_sshConnected) {
|
||||
// QTimer::singleShot(2000, this, &JailbrokenWidget::startSSH);
|
||||
// }
|
||||
// });
|
||||
|
||||
QTimer::singleShot(2000, this, &JailbrokenWidget::startSSH);
|
||||
|
||||
iproxyProcess->start("iproxy", QStringList()
|
||||
<< "-u" << m_device->udid.c_str()
|
||||
<< "3333" << "22");
|
||||
}
|
||||
|
||||
void JailbrokenWidget::startSSH()
|
||||
{
|
||||
if (m_sshConnected)
|
||||
return;
|
||||
|
||||
m_infoLabel->setText("Starting SSH terminal...");
|
||||
|
||||
// Show the terminal and start SSH session
|
||||
m_terminal->show();
|
||||
|
||||
// Start the terminal with an empty shell first
|
||||
m_terminal->startTerminalTeletype();
|
||||
|
||||
// Create SSH process
|
||||
sshProcess = new QProcess(this);
|
||||
sshProcess->setProcessChannelMode(QProcess::MergedChannels);
|
||||
|
||||
// Check if sshpass is available for automatic password entry
|
||||
QProcess *checkSshpass = new QProcess(this);
|
||||
checkSshpass->start("which", QStringList() << "sshpass");
|
||||
checkSshpass->waitForFinished(1000);
|
||||
|
||||
QStringList sshArgs;
|
||||
QString sshProgram;
|
||||
|
||||
if (checkSshpass->exitCode() == 0) {
|
||||
// Use sshpass for automatic login
|
||||
sshProgram = "sshpass";
|
||||
sshArgs << "-p" << "alpine"
|
||||
<< "ssh"
|
||||
<< "-t" // Force pseudo-terminal allocation
|
||||
<< "-o" << "StrictHostKeyChecking=no"
|
||||
<< "-o" << "UserKnownHostsFile=/dev/null"
|
||||
<< "-p" << "3333"
|
||||
<< "root@localhost";
|
||||
m_infoLabel->setText(
|
||||
"SSH terminal connected on port 3333 (using sshpass)");
|
||||
} else {
|
||||
// Use regular SSH (user will need to enter password manually)
|
||||
sshProgram = "ssh";
|
||||
sshArgs << "-t" // Force pseudo-terminal allocation
|
||||
<< "-o" << "StrictHostKeyChecking=no"
|
||||
<< "-o" << "UserKnownHostsFile=/dev/null"
|
||||
<< "-p" << "3333"
|
||||
<< "root@localhost";
|
||||
m_infoLabel->setText("SSH terminal connected on port 3333 (enter "
|
||||
"'alpine' when prompted)");
|
||||
}
|
||||
|
||||
checkSshpass->deleteLater();
|
||||
|
||||
// Connect terminal to SSH process
|
||||
connectTerminalToProcess();
|
||||
|
||||
// Handle SSH process finish
|
||||
connect(sshProcess,
|
||||
QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this,
|
||||
&JailbrokenWidget::onSshProcessFinished);
|
||||
|
||||
// Start SSH process
|
||||
sshProcess->start(sshProgram, sshArgs);
|
||||
|
||||
if (!sshProcess->waitForStarted(3000)) {
|
||||
m_infoLabel->setText("Failed to start SSH process");
|
||||
m_terminal->hide();
|
||||
return;
|
||||
}
|
||||
|
||||
m_sshConnected = true;
|
||||
m_connectButton->setEnabled(true);
|
||||
m_connectButton->setText("Disconnect SSH");
|
||||
|
||||
// Set focus to terminal so user can type immediately
|
||||
m_terminal->setFocus();
|
||||
}
|
||||
|
||||
void JailbrokenWidget::onSshProcessFinished(int exitCode,
|
||||
QProcess::ExitStatus exitStatus)
|
||||
{
|
||||
Q_UNUSED(exitCode)
|
||||
Q_UNUSED(exitStatus)
|
||||
|
||||
m_infoLabel->setText("SSH connection closed");
|
||||
m_sshConnected = false;
|
||||
m_connectButton->setText("Connect SSH Terminal");
|
||||
m_terminal->hide();
|
||||
|
||||
if (sshProcess) {
|
||||
sshProcess->deleteLater();
|
||||
sshProcess = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
JailbrokenWidget::~JailbrokenWidget()
|
||||
{
|
||||
if (iproxyProcess) {
|
||||
iproxyProcess->terminate();
|
||||
iproxyProcess->waitForFinished(3000);
|
||||
}
|
||||
}
|
||||
+30
-2
@@ -1,15 +1,43 @@
|
||||
#ifndef JAILBROKENWIDGET_H
|
||||
#define JAILBROKENWIDGET_H
|
||||
|
||||
#include "iDescriptor.h"
|
||||
#include <QLabel>
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
#include <qtermwidget6/qtermwidget.h>
|
||||
|
||||
class JailbrokenWidget : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit JailbrokenWidget(QWidget *parent = nullptr);
|
||||
~JailbrokenWidget();
|
||||
void initWidget();
|
||||
|
||||
signals:
|
||||
private slots:
|
||||
void deviceConnected(iDescriptorDevice *device);
|
||||
void onConnectSSH();
|
||||
void startSSH();
|
||||
void onSshProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
||||
private:
|
||||
void setupTerminal();
|
||||
void connectTerminalToProcess();
|
||||
|
||||
QLabel *m_infoLabel;
|
||||
iDescriptorDevice *m_device = nullptr;
|
||||
QProcess *iproxyProcess = nullptr;
|
||||
QProcess *sshProcess = nullptr;
|
||||
|
||||
// Terminal widgets
|
||||
QTermWidget *m_terminal;
|
||||
QPushButton *m_connectButton;
|
||||
|
||||
bool m_isInitialized = false;
|
||||
bool m_sshConnected = false;
|
||||
};
|
||||
|
||||
#endif // JAILBROKENWIDGET_H
|
||||
#endif // JAILBROKENWIDGET_H
|
||||
+12
-2
@@ -144,8 +144,18 @@ MainWindow::MainWindow(QWidget *parent)
|
||||
// ui->centralwidget->layout()->addWidget(settingsButton);
|
||||
ui->mainTabWidget->widget(1)->layout()->addWidget(new AppsWidget(this));
|
||||
ui->mainTabWidget->widget(2)->layout()->addWidget(new ToolboxWidget(this));
|
||||
ui->mainTabWidget->widget(3)->layout()->addWidget(
|
||||
new JailbrokenWidget(this));
|
||||
auto *jailbrokenWidget = new JailbrokenWidget(this);
|
||||
ui->mainTabWidget->widget(3)->layout()->addWidget(jailbrokenWidget);
|
||||
|
||||
// TODO: is this a good idea?
|
||||
auto connection = std::make_shared<QMetaObject::Connection>();
|
||||
*connection = connect(ui->mainTabWidget, &QTabWidget::currentChanged, this,
|
||||
[this, jailbrokenWidget, connection](int index) {
|
||||
if (index == 3) { // Jailbroken tab
|
||||
jailbrokenWidget->initWidget();
|
||||
QObject::disconnect(*connection);
|
||||
}
|
||||
});
|
||||
|
||||
ui->statusbar->addPermanentWidget(settingsButton);
|
||||
irecv_error_t res_recovery =
|
||||
|
||||
@@ -138,9 +138,6 @@
|
||||
<layout class="QVBoxLayout" name="jailbrokenTabLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="jailbrokenLabel">
|
||||
<property name="text">
|
||||
<string>This is jailbroken tab</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
|
||||
Reference in New Issue
Block a user