pin support
This commit is contained in:
@@ -37,6 +37,8 @@ void AppController::initialize()
|
|||||||
emit serverRunningChanged();
|
emit serverRunningChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_server->setReceivePin(m_settings->receivePin());
|
||||||
|
|
||||||
connect(m_discovery, &LocalSend::DiscoveryManager::deviceDiscovered,
|
connect(m_discovery, &LocalSend::DiscoveryManager::deviceDiscovered,
|
||||||
this, &AppController::onDeviceDiscovered);
|
this, &AppController::onDeviceDiscovered);
|
||||||
connect(m_discovery, &LocalSend::DiscoveryManager::deviceLost,
|
connect(m_discovery, &LocalSend::DiscoveryManager::deviceLost,
|
||||||
@@ -60,6 +62,10 @@ void AppController::initialize()
|
|||||||
this, &AppController::onPrepareUploadResponse);
|
this, &AppController::onPrepareUploadResponse);
|
||||||
connect(m_httpClient, &LocalSend::HttpClient::prepareUploadError,
|
connect(m_httpClient, &LocalSend::HttpClient::prepareUploadError,
|
||||||
this, &AppController::onPrepareUploadError);
|
this, &AppController::onPrepareUploadError);
|
||||||
|
connect(m_httpClient, &LocalSend::HttpClient::prepareUploadPinRequired,
|
||||||
|
this, &AppController::onPrepareUploadPinRequired);
|
||||||
|
connect(m_httpClient, &LocalSend::HttpClient::prepareUploadTooManyAttempts,
|
||||||
|
this, &AppController::onPrepareUploadTooManyAttempts);
|
||||||
connect(m_httpClient, &LocalSend::HttpClient::uploadProgress,
|
connect(m_httpClient, &LocalSend::HttpClient::uploadProgress,
|
||||||
this, &AppController::onUploadProgress);
|
this, &AppController::onUploadProgress);
|
||||||
connect(m_httpClient, &LocalSend::HttpClient::uploadCompleted,
|
connect(m_httpClient, &LocalSend::HttpClient::uploadCompleted,
|
||||||
@@ -379,6 +385,20 @@ bool AppController::hasPendingFiles() const
|
|||||||
return !m_pendingFilesList.isEmpty();
|
return !m_pendingFilesList.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString AppController::receivePin() const
|
||||||
|
{
|
||||||
|
return m_settings->receivePin();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppController::setReceivePin(const QString& pin)
|
||||||
|
{
|
||||||
|
if (m_settings->receivePin() != pin) {
|
||||||
|
m_settings->setReceivePin(pin);
|
||||||
|
m_server->setReceivePin(pin);
|
||||||
|
emit receivePinChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppController::addFiles(const QStringList& filePaths)
|
void AppController::addFiles(const QStringList& filePaths)
|
||||||
{
|
{
|
||||||
QMimeDatabase mimeDb;
|
QMimeDatabase mimeDb;
|
||||||
@@ -449,6 +469,7 @@ void AppController::sendFiles(const QString& deviceFingerprint, const QStringLis
|
|||||||
m_pendingSendPaths = filePaths;
|
m_pendingSendPaths = filePaths;
|
||||||
m_currentFileIndex = 0;
|
m_currentFileIndex = 0;
|
||||||
m_sendProgress = 0.0;
|
m_sendProgress = 0.0;
|
||||||
|
m_pinFirstAttempt = true;
|
||||||
emit sendingChanged();
|
emit sendingChanged();
|
||||||
emit sendProgressChanged();
|
emit sendProgressChanged();
|
||||||
|
|
||||||
@@ -552,6 +573,55 @@ void AppController::onPrepareUploadError(const QString& error)
|
|||||||
emit sendingChanged();
|
emit sendingChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppController::onPrepareUploadPinRequired()
|
||||||
|
{
|
||||||
|
qDebug() << "[AppController] onPrepareUploadPinRequired, firstAttempt:" << m_pinFirstAttempt;
|
||||||
|
emit pinRequired(m_pinFirstAttempt);
|
||||||
|
m_pinFirstAttempt = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppController::onPrepareUploadTooManyAttempts()
|
||||||
|
{
|
||||||
|
qWarning() << "[AppController] onPrepareUploadTooManyAttempts";
|
||||||
|
emit sendError(QStringLiteral("Too many PIN attempts"));
|
||||||
|
m_currentSendSessionId.clear();
|
||||||
|
emit sendingChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AppController::retryWithPin(const QString& pin)
|
||||||
|
{
|
||||||
|
if (m_currentSendDeviceFingerprint.isEmpty() || !m_devices.contains(m_currentSendDeviceFingerprint)) {
|
||||||
|
m_currentSendSessionId.clear();
|
||||||
|
emit sendingChanged();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalSend::Device target = m_devices[m_currentSendDeviceFingerprint];
|
||||||
|
|
||||||
|
QMap<QString, LocalSend::FileDto> files;
|
||||||
|
QMimeDatabase mimeDb;
|
||||||
|
|
||||||
|
for (int i = 0; i < m_pendingSendPaths.size(); ++i) {
|
||||||
|
QFileInfo info(m_pendingSendPaths[i]);
|
||||||
|
if (!info.exists()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
LocalSend::FileDto fileDto;
|
||||||
|
fileDto.id = QString::number(i);
|
||||||
|
fileDto.fileName = info.fileName();
|
||||||
|
fileDto.size = info.size();
|
||||||
|
fileDto.fileType = mimeDb.mimeTypeForFile(info).name();
|
||||||
|
files.insert(fileDto.id, fileDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
LocalSend::PrepareUploadRequestDto request;
|
||||||
|
request.info = buildRegisterDto();
|
||||||
|
request.files = files;
|
||||||
|
|
||||||
|
qDebug() << "[AppController] Retrying prepare-upload with PIN to" << target.ip;
|
||||||
|
m_httpClient->prepareUpload(target, request, pin);
|
||||||
|
}
|
||||||
|
|
||||||
void AppController::onUploadProgress(qint64 sent, qint64 total)
|
void AppController::onUploadProgress(qint64 sent, qint64 total)
|
||||||
{
|
{
|
||||||
if (total > 0) {
|
if (total > 0) {
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ class AppController : public QObject
|
|||||||
Q_PROPERTY(double sendProgress READ sendProgress NOTIFY sendProgressChanged)
|
Q_PROPERTY(double sendProgress READ sendProgress NOTIFY sendProgressChanged)
|
||||||
Q_PROPERTY(QVariantList pendingFiles READ pendingFiles NOTIFY pendingFilesChanged)
|
Q_PROPERTY(QVariantList pendingFiles READ pendingFiles NOTIFY pendingFilesChanged)
|
||||||
Q_PROPERTY(bool hasPendingFiles READ hasPendingFiles NOTIFY pendingFilesChanged)
|
Q_PROPERTY(bool hasPendingFiles READ hasPendingFiles NOTIFY pendingFilesChanged)
|
||||||
|
Q_PROPERTY(QString receivePin READ receivePin WRITE setReceivePin NOTIFY receivePinChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit AppController(QObject* parent = nullptr);
|
explicit AppController(QObject* parent = nullptr);
|
||||||
@@ -49,6 +50,8 @@ public:
|
|||||||
double sendProgress() const;
|
double sendProgress() const;
|
||||||
QVariantList pendingFiles() const;
|
QVariantList pendingFiles() const;
|
||||||
bool hasPendingFiles() const;
|
bool hasPendingFiles() const;
|
||||||
|
QString receivePin() const;
|
||||||
|
void setReceivePin(const QString& pin);
|
||||||
|
|
||||||
Q_INVOKABLE void startDiscovery();
|
Q_INVOKABLE void startDiscovery();
|
||||||
Q_INVOKABLE void stopDiscovery();
|
Q_INVOKABLE void stopDiscovery();
|
||||||
@@ -63,6 +66,7 @@ public:
|
|||||||
Q_INVOKABLE void addFiles(const QStringList& filePaths);
|
Q_INVOKABLE void addFiles(const QStringList& filePaths);
|
||||||
Q_INVOKABLE void removePendingFile(int index);
|
Q_INVOKABLE void removePendingFile(int index);
|
||||||
Q_INVOKABLE void clearPendingFiles();
|
Q_INVOKABLE void clearPendingFiles();
|
||||||
|
Q_INVOKABLE void retryWithPin(const QString& pin);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void aliasChanged();
|
void aliasChanged();
|
||||||
@@ -81,6 +85,8 @@ signals:
|
|||||||
void receiveError(const QString& sessionId, const QString& error);
|
void receiveError(const QString& sessionId, const QString& error);
|
||||||
void sendCompleted(const QString& sessionId);
|
void sendCompleted(const QString& sessionId);
|
||||||
void sendError(const QString& error);
|
void sendError(const QString& error);
|
||||||
|
void pinRequired(bool firstAttempt);
|
||||||
|
void receivePinChanged();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onDeviceDiscovered(const LocalSend::Device& device);
|
void onDeviceDiscovered(const LocalSend::Device& device);
|
||||||
@@ -98,6 +104,8 @@ private slots:
|
|||||||
|
|
||||||
void onPrepareUploadResponse(const LocalSend::PrepareUploadResponseDto& response);
|
void onPrepareUploadResponse(const LocalSend::PrepareUploadResponseDto& response);
|
||||||
void onPrepareUploadError(const QString& error);
|
void onPrepareUploadError(const QString& error);
|
||||||
|
void onPrepareUploadPinRequired();
|
||||||
|
void onPrepareUploadTooManyAttempts();
|
||||||
void onUploadProgress(qint64 sent, qint64 total);
|
void onUploadProgress(qint64 sent, qint64 total);
|
||||||
void onUploadCompleted();
|
void onUploadCompleted();
|
||||||
void onUploadError(const QString& error);
|
void onUploadError(const QString& error);
|
||||||
@@ -119,6 +127,7 @@ private:
|
|||||||
QVariantList m_pendingFilesList;
|
QVariantList m_pendingFilesList;
|
||||||
int m_currentFileIndex = 0;
|
int m_currentFileIndex = 0;
|
||||||
double m_sendProgress = 0.0;
|
double m_sendProgress = 0.0;
|
||||||
|
bool m_pinFirstAttempt = true;
|
||||||
|
|
||||||
LocalSend::InfoDto buildInfoDto() const;
|
LocalSend::InfoDto buildInfoDto() const;
|
||||||
QString generateUniqueFilePath(const QString& baseDir, const QString& fileName) const;
|
QString generateUniqueFilePath(const QString& baseDir, const QString& fileName) const;
|
||||||
|
|||||||
@@ -286,9 +286,15 @@ ApplicationWindow {
|
|||||||
|
|
||||||
function onSendError(error) {
|
function onSendError(error) {
|
||||||
sendProgressDialog.close()
|
sendProgressDialog.close()
|
||||||
|
pinDialog.close()
|
||||||
errorDialog.text = error
|
errorDialog.text = error
|
||||||
errorDialog.open()
|
errorDialog.open()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onPinRequired(firstAttempt) {
|
||||||
|
pinDialog.isFirstAttempt = firstAttempt
|
||||||
|
pinDialog.open()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog {
|
Dialog {
|
||||||
@@ -317,6 +323,112 @@ ApplicationWindow {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: pinDialog
|
||||||
|
anchors.centerIn: parent
|
||||||
|
modal: true
|
||||||
|
closePolicy: Popup.NoAutoClose
|
||||||
|
title: qsTr("PIN Required")
|
||||||
|
|
||||||
|
property bool isFirstAttempt: true
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: pinDialog.isFirstAttempt
|
||||||
|
? qsTr("The receiver requires a PIN to accept files.")
|
||||||
|
: qsTr("Invalid PIN. Please try again.")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.fillWidth: true
|
||||||
|
color: pinDialog.isFirstAttempt ? palette.text : "red"
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: pinInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("Enter PIN")
|
||||||
|
echoMode: TextInput.Password
|
||||||
|
focus: true
|
||||||
|
onAccepted: pinDialog.submitPin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: DialogButtonBox {
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("Submit")
|
||||||
|
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
|
||||||
|
enabled: pinInput.text.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: submitPin()
|
||||||
|
onRejected: {
|
||||||
|
appController.cancelSend()
|
||||||
|
close()
|
||||||
|
}
|
||||||
|
|
||||||
|
function submitPin() {
|
||||||
|
if (pinInput.text.length > 0) {
|
||||||
|
appController.retryWithPin(pinInput.text)
|
||||||
|
pinInput.text = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
pinInput.text = ""
|
||||||
|
pinInput.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Dialog {
|
||||||
|
id: setPinDialog
|
||||||
|
anchors.centerIn: parent
|
||||||
|
modal: true
|
||||||
|
title: qsTr("Set Receive PIN")
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
spacing: 12
|
||||||
|
|
||||||
|
Label {
|
||||||
|
text: qsTr("Enter a PIN that senders must provide to transfer files to this device. Leave empty to disable.")
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
Layout.fillWidth: true
|
||||||
|
}
|
||||||
|
|
||||||
|
TextField {
|
||||||
|
id: setPinInput
|
||||||
|
Layout.fillWidth: true
|
||||||
|
placeholderText: qsTr("Enter PIN")
|
||||||
|
onAccepted: setPinDialog.accepted()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
footer: DialogButtonBox {
|
||||||
|
Button {
|
||||||
|
text: qsTr("Cancel")
|
||||||
|
DialogButtonBox.buttonRole: DialogButtonBox.RejectRole
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("OK")
|
||||||
|
DialogButtonBox.buttonRole: DialogButtonBox.AcceptRole
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
onAccepted: {
|
||||||
|
appController.receivePin = setPinInput.text
|
||||||
|
}
|
||||||
|
|
||||||
|
onOpened: {
|
||||||
|
setPinInput.text = appController.receivePin
|
||||||
|
setPinInput.forceActiveFocus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function formatSize(bytes) {
|
function formatSize(bytes) {
|
||||||
if (bytes < 1024) return bytes + " B"
|
if (bytes < 1024) return bytes + " B"
|
||||||
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB"
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB"
|
||||||
@@ -597,6 +709,25 @@ ApplicationWindow {
|
|||||||
checked: appController.quickSave
|
checked: appController.quickSave
|
||||||
onCheckedChanged: appController.quickSave = checked
|
onCheckedChanged: appController.quickSave = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Label { text: qsTr("Receive PIN:") }
|
||||||
|
RowLayout {
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Label {
|
||||||
|
text: appController.receivePin.length > 0 ? qsTr("Enabled") : qsTr("Disabled")
|
||||||
|
color: appController.receivePin.length > 0 ? "green" : palette.mid
|
||||||
|
}
|
||||||
|
Item { Layout.fillWidth: true }
|
||||||
|
Button {
|
||||||
|
text: appController.receivePin.length > 0 ? qsTr("Change") : qsTr("Set PIN")
|
||||||
|
onClicked: setPinDialog.open()
|
||||||
|
}
|
||||||
|
Button {
|
||||||
|
text: qsTr("Remove")
|
||||||
|
visible: appController.receivePin.length > 0
|
||||||
|
onClicked: appController.receivePin = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FolderDialog {
|
FolderDialog {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ public:
|
|||||||
|
|
||||||
void getInfo(const Device& device);
|
void getInfo(const Device& device);
|
||||||
void registerDevice(const Device& device, const RegisterDto& dto);
|
void registerDevice(const Device& device, const RegisterDto& dto);
|
||||||
void prepareUpload(const Device& device, const PrepareUploadRequestDto& dto);
|
void prepareUpload(const Device& device, const PrepareUploadRequestDto& dto, const QString& pin = QString());
|
||||||
void uploadFile(const Device& device, const QString& sessionId, const QString& fileId,
|
void uploadFile(const Device& device, const QString& sessionId, const QString& fileId,
|
||||||
const QString& token, const QString& filePath);
|
const QString& token, const QString& filePath);
|
||||||
void cancel(const Device& device, const QString& sessionId);
|
void cancel(const Device& device, const QString& sessionId);
|
||||||
@@ -34,6 +34,8 @@ signals:
|
|||||||
void registerError(const QString& error);
|
void registerError(const QString& error);
|
||||||
void prepareUploadResponse(const PrepareUploadResponseDto& response);
|
void prepareUploadResponse(const PrepareUploadResponseDto& response);
|
||||||
void prepareUploadError(const QString& error);
|
void prepareUploadError(const QString& error);
|
||||||
|
void prepareUploadPinRequired();
|
||||||
|
void prepareUploadTooManyAttempts();
|
||||||
void uploadProgress(qint64 sent, qint64 total);
|
void uploadProgress(qint64 sent, qint64 total);
|
||||||
void uploadCompleted();
|
void uploadCompleted();
|
||||||
void uploadError(const QString& error);
|
void uploadError(const QString& error);
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
|
|
||||||
void setLocalInfo(const InfoDto& info, const QString& fingerprint);
|
void setLocalInfo(const InfoDto& info, const QString& fingerprint);
|
||||||
|
void setReceivePin(const QString& pin);
|
||||||
#ifdef HAS_QTHTTPSERVER
|
#ifdef HAS_QTHTTPSERVER
|
||||||
void setSslConfiguration(const QSslConfiguration& config);
|
void setSslConfiguration(const QSslConfiguration& config);
|
||||||
#endif
|
#endif
|
||||||
@@ -62,6 +63,8 @@ private:
|
|||||||
|
|
||||||
InfoDto m_localInfo;
|
InfoDto m_localInfo;
|
||||||
QString m_localFingerprint;
|
QString m_localFingerprint;
|
||||||
|
QString m_receivePin;
|
||||||
|
QMap<QString, int> m_pinAttempts;
|
||||||
quint16 m_port = 0;
|
quint16 m_port = 0;
|
||||||
|
|
||||||
#ifdef HAS_QTHTTPSERVER
|
#ifdef HAS_QTHTTPSERVER
|
||||||
@@ -71,6 +74,7 @@ private:
|
|||||||
QFuture<QHttpServerResponse> handlePrepareUploadRequest(const QHttpServerRequest& request);
|
QFuture<QHttpServerResponse> handlePrepareUploadRequest(const QHttpServerRequest& request);
|
||||||
QHttpServerResponse handleUploadRequest(const QHttpServerRequest& request);
|
QHttpServerResponse handleUploadRequest(const QHttpServerRequest& request);
|
||||||
QHttpServerResponse handleCancelRequest(const QHttpServerRequest& request);
|
QHttpServerResponse handleCancelRequest(const QHttpServerRequest& request);
|
||||||
|
bool checkPin(const QHttpServerRequest& request, const QHostAddress& peer);
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ public:
|
|||||||
bool quickSave() const;
|
bool quickSave() const;
|
||||||
void setQuickSave(bool enabled);
|
void setQuickSave(bool enabled);
|
||||||
|
|
||||||
|
QString receivePin() const;
|
||||||
|
void setReceivePin(const QString& pin);
|
||||||
|
|
||||||
QString deviceModel() const;
|
QString deviceModel() const;
|
||||||
void setDeviceModel(const QString& model);
|
void setDeviceModel(const QString& model);
|
||||||
|
|
||||||
|
|||||||
@@ -99,9 +99,14 @@ void HttpClient::registerDevice(const Device& device, const RegisterDto& dto)
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void HttpClient::prepareUpload(const Device& device, const PrepareUploadRequestDto& dto)
|
void HttpClient::prepareUpload(const Device& device, const PrepareUploadRequestDto& dto, const QString& pin)
|
||||||
{
|
{
|
||||||
QUrl url = buildUrl(device, ApiRoute::PREPARE_UPLOAD);
|
QUrl url = buildUrl(device, ApiRoute::PREPARE_UPLOAD);
|
||||||
|
if (!pin.isEmpty()) {
|
||||||
|
QUrlQuery query;
|
||||||
|
query.addQueryItem(QStringLiteral("pin"), pin);
|
||||||
|
url.setQuery(query);
|
||||||
|
}
|
||||||
QByteArray data = QJsonDocument(dto.toJson()).toJson(QJsonDocument::Compact);
|
QByteArray data = QJsonDocument(dto.toJson()).toJson(QJsonDocument::Compact);
|
||||||
|
|
||||||
qDebug() << "[HttpClient] prepareUpload to" << url.toString();
|
qDebug() << "[HttpClient] prepareUpload to" << url.toString();
|
||||||
@@ -112,6 +117,20 @@ void HttpClient::prepareUpload(const Device& device, const PrepareUploadRequestD
|
|||||||
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
connect(reply, &QNetworkReply::finished, this, [this, reply]() {
|
||||||
reply->deleteLater();
|
reply->deleteLater();
|
||||||
|
|
||||||
|
int statusCode = reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();
|
||||||
|
|
||||||
|
if (statusCode == 401) {
|
||||||
|
qDebug() << "[HttpClient] prepareUpload: PIN required (401)";
|
||||||
|
emit prepareUploadPinRequired();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (statusCode == 429) {
|
||||||
|
qWarning() << "[HttpClient] prepareUpload: Too many attempts (429)";
|
||||||
|
emit prepareUploadTooManyAttempts();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (reply->error() != QNetworkReply::NoError) {
|
if (reply->error() != QNetworkReply::NoError) {
|
||||||
qWarning() << "[HttpClient] prepareUpload error:" << reply->errorString();
|
qWarning() << "[HttpClient] prepareUpload error:" << reply->errorString();
|
||||||
emit prepareUploadError(reply->errorString());
|
emit prepareUploadError(reply->errorString());
|
||||||
|
|||||||
@@ -33,6 +33,38 @@ void HttpServer::setSslConfiguration(const QSslConfiguration& config)
|
|||||||
m_sslConfig = config;
|
m_sslConfig = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HttpServer::setReceivePin(const QString& pin)
|
||||||
|
{
|
||||||
|
m_receivePin = pin;
|
||||||
|
m_pinAttempts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HttpServer::checkPin(const QHttpServerRequest& request, const QHostAddress& peer)
|
||||||
|
{
|
||||||
|
if (m_receivePin.isEmpty()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString peerIp = peer.toString();
|
||||||
|
int attempts = m_pinAttempts.value(peerIp, 0);
|
||||||
|
|
||||||
|
if (attempts >= 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrlQuery query(request.url().query());
|
||||||
|
QString requestPin = query.queryItemValue(QStringLiteral("pin"));
|
||||||
|
|
||||||
|
if (requestPin != m_receivePin) {
|
||||||
|
if (!requestPin.isEmpty()) {
|
||||||
|
m_pinAttempts[peerIp] = attempts + 1;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool HttpServer::start(quint16 port, bool https)
|
bool HttpServer::start(quint16 port, bool https)
|
||||||
{
|
{
|
||||||
Q_UNUSED(https)
|
Q_UNUSED(https)
|
||||||
@@ -180,6 +212,41 @@ QHttpServerResponse HttpServer::handleRegisterRequest(const QHttpServerRequest&
|
|||||||
|
|
||||||
QFuture<QHttpServerResponse> HttpServer::handlePrepareUploadRequest(const QHttpServerRequest& request)
|
QFuture<QHttpServerResponse> HttpServer::handlePrepareUploadRequest(const QHttpServerRequest& request)
|
||||||
{
|
{
|
||||||
|
QHostAddress peer = request.remoteAddress();
|
||||||
|
|
||||||
|
if (!m_receivePin.isEmpty()) {
|
||||||
|
QString peerIp = peer.toString();
|
||||||
|
int attempts = m_pinAttempts.value(peerIp, 0);
|
||||||
|
|
||||||
|
if (attempts >= 3) {
|
||||||
|
auto promise = std::make_shared<QPromise<QHttpServerResponse>>();
|
||||||
|
promise->start();
|
||||||
|
QJsonObject errorObj;
|
||||||
|
errorObj[QStringLiteral("message")] = QStringLiteral("Too many attempts.");
|
||||||
|
promise->addResult(QHttpServerResponse(QJsonDocument(errorObj).toJson(QJsonDocument::Compact),
|
||||||
|
QHttpServerResponse::StatusCode::Forbidden));
|
||||||
|
promise->finish();
|
||||||
|
return promise->future();
|
||||||
|
}
|
||||||
|
|
||||||
|
QUrlQuery query(request.url().query());
|
||||||
|
QString requestPin = query.queryItemValue(QStringLiteral("pin"));
|
||||||
|
|
||||||
|
if (requestPin != m_receivePin) {
|
||||||
|
if (!requestPin.isEmpty()) {
|
||||||
|
m_pinAttempts[peerIp] = attempts + 1;
|
||||||
|
}
|
||||||
|
auto promise = std::make_shared<QPromise<QHttpServerResponse>>();
|
||||||
|
promise->start();
|
||||||
|
QJsonObject errorObj;
|
||||||
|
errorObj[QStringLiteral("message")] = QStringLiteral("Invalid pin.");
|
||||||
|
promise->addResult(QHttpServerResponse(QJsonDocument(errorObj).toJson(QJsonDocument::Compact),
|
||||||
|
QHttpServerResponse::StatusCode::Unauthorized));
|
||||||
|
promise->finish();
|
||||||
|
return promise->future();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QJsonParseError error;
|
QJsonParseError error;
|
||||||
QJsonDocument doc = QJsonDocument::fromJson(request.body(), &error);
|
QJsonDocument doc = QJsonDocument::fromJson(request.body(), &error);
|
||||||
|
|
||||||
|
|||||||
@@ -78,6 +78,23 @@ void Settings::setQuickSave(bool enabled)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Settings::receivePin() const
|
||||||
|
{
|
||||||
|
return m_settings.value(QStringLiteral("receivePin")).toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Settings::setReceivePin(const QString& pin)
|
||||||
|
{
|
||||||
|
if (receivePin() != pin) {
|
||||||
|
if (pin.isEmpty()) {
|
||||||
|
m_settings.remove(QStringLiteral("receivePin"));
|
||||||
|
} else {
|
||||||
|
m_settings.setValue(QStringLiteral("receivePin"), pin);
|
||||||
|
}
|
||||||
|
m_settings.sync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
QString Settings::deviceModel() const
|
QString Settings::deviceModel() const
|
||||||
{
|
{
|
||||||
return m_settings.value(QStringLiteral("deviceModel"),
|
return m_settings.value(QStringLiteral("deviceModel"),
|
||||||
|
|||||||
Reference in New Issue
Block a user