mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 09:33:25 -08:00
[DeckShare] Open shared decks via links with a gated preview flow (#7244)
* [DeckShare] Open shared decks via links with a gated preview flow - Serialized url-chain dispatcher in IntentUrlParser; queue-drained urlChainFinished(bool) drives the startup auto-connect fallback - Open-shared-deck intent with sequential download state machine, 15s per-item timeout, partial-success offer, livable Cancel via ApplicationModal dlg_login_prompt interactive fallback - Preview dialog: download progress label, share vocab sweep, palette-highlight selection frame, Space/Enter keyboard toggle, NoFocus checkbox, double-click tile opens immediately - Confirm-before-server-migration with one-shot restore to the previous server on failed/cancelled chains (statusChanged settle deferral), hostname-only identity comparisons - Skip credential link when already connected; arrow-key navigation in FlowWidget; card glows use palette highlight - Address code-review M1-M4 and UI/UX QA blockers 1-2 * [DeckShare] End the open-shared-deck files with a trailing newline * [DeckShare] Forward a dependency's cancellation as the owner's own * [DeckShare] Let intent chains opt into the link sign-in dialog * [DeckShare] Track link-intent chains per-run so each can restore its own session * [Settings] Match a server on the exact host and port when adding it * [DeckShare] Confirm the share link's target server before opening a deck * [DeckShare] Reformat the link sign-in intent constructor * [DeckShare] Time the share-list round trip and backstop silently-destroyed intent chains * [Client] Drain a single-instance payload before its handlers read the socket again * [Client] Treat a busy single-instance primary as alive instead of stealing its socket * [DeckShare] Keep arrow-key navigation between flow items inside a scroll area * [Client] Skip the startup connection when a macOS URL launch owns the connection * [Client] Redact share secrets from activation URL logs * [Client] Make the link-connection gates port-aware and keyboard-safe Second-pass review notes for the shared-deck link flow (Cockatrice#7244): - FlowWidget arrow-key navigation is opt-in via addNavigableWidget, so combo/spin controls on the analytics flows keep their own arrow keys - isConnectedTo and the open-deck/join-game preconditions compare the configured server port alongside the host, so a same-host/different-port link cannot resolve its share token or game id on the wrong instance - the link sign-in dialog reuses an existing server entry's saved name instead of renaming it to the raw hostname - skipStartupAutoConnect is cleared once the launch chain connects, so a later mid-session declined link cannot fire the startup fallback - the plain-launch path of SingleInstanceManager no longer blocks on the primary's ACK - link- and server-supplied text is html-escaped in the confirm prompts and shared-deck preview so markup cannot spoof the shown messages --------- Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
ba2900dcb9
commit
8ca749c07d
29 changed files with 1666 additions and 86 deletions
|
|
@ -26,7 +26,6 @@
|
|||
#include "client/url_scheme_event_filter.h"
|
||||
#include "database/interface/settings_card_preference_provider.h"
|
||||
#include "interface/intents/intent_open_local_deck.h"
|
||||
#include "interface/intents/url_parser.h"
|
||||
#include "interface/logger.h"
|
||||
#include "interface/pixel_map_generator.h"
|
||||
#include "interface/theme_manager.h"
|
||||
|
|
@ -45,6 +44,8 @@
|
|||
#include <QMessageBox>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QTranslator>
|
||||
#include <QUrl>
|
||||
#include <algorithm>
|
||||
#include <libcockatrice/card/database/card_database_manager.h>
|
||||
#include <libcockatrice/rng/rng_sfmt.h>
|
||||
#include <libcockatrice/settings/appearance_settings.h>
|
||||
|
|
@ -177,6 +178,18 @@ QString const generateClientID()
|
|||
return strClientID;
|
||||
}
|
||||
|
||||
static QString redactActivationUrl(const QString &url)
|
||||
{
|
||||
// Activation URLs carry secrets in their query string (e.g. the deck share
|
||||
// token); log only the scheme and the action (cockatrice://opendeck), never
|
||||
// the parameters.
|
||||
if (!url.startsWith(QStringLiteral("cockatrice://"))) {
|
||||
return url;
|
||||
}
|
||||
const QUrl parsed(url);
|
||||
return parsed.scheme() + "://" + parsed.host();
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
#ifdef Q_OS_WIN
|
||||
|
|
@ -273,10 +286,17 @@ int main(int argc, char *argv[])
|
|||
SingleInstanceManager instance;
|
||||
|
||||
if (hasActivationFiles) {
|
||||
QStringList redactedFiles;
|
||||
redactedFiles.reserve(startupFiles.size());
|
||||
for (const QString &file : startupFiles) {
|
||||
redactedFiles.append(redactActivationUrl(file));
|
||||
}
|
||||
qCInfo(MainLog) << "Activation launch, files:" << redactedFiles;
|
||||
// Activation launch: hand off to the primary instance if one is
|
||||
// running, otherwise become the primary ourselves. Do this before
|
||||
// constructing the main window so a hand-off exits cheaply.
|
||||
if (!instance.tryRun(startupFiles)) {
|
||||
qInfo() << "Handed off to a running instance, exiting";
|
||||
// Sent successfully → exit
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -325,10 +345,30 @@ int main(int argc, char *argv[])
|
|||
|
||||
MainWindow ui;
|
||||
|
||||
// A URL launch must own the connection: the intent chain triggered by the
|
||||
// URL connects to the server named in the URL, so the window's own startup
|
||||
// auto-connect must not race against it (two connectToServer calls tear
|
||||
// each other down via doDisconnectFromServer).
|
||||
bool hasUrlActivation = std::any_of(startupFiles.begin(), startupFiles.end(), [](const QString &file) {
|
||||
return file.startsWith(QStringLiteral("cockatrice://"));
|
||||
});
|
||||
#ifdef Q_OS_MAC
|
||||
// On macOS the launch can arrive through the URL scheme instead of as a
|
||||
// positional argument (captured in pendingMacUrls); count those too or the
|
||||
// window would auto-connect into the link's own connection attempt.
|
||||
hasUrlActivation = hasUrlActivation ||
|
||||
std::any_of(pendingMacUrls.cbegin(), pendingMacUrls.cend(),
|
||||
[](const QString &url) { return url.startsWith(QStringLiteral("cockatrice://")); });
|
||||
#endif
|
||||
ui.setSkipStartupAutoConnect(hasUrlActivation);
|
||||
|
||||
auto handleActivation = [&ui](const QString &file) {
|
||||
if (file.startsWith("cockatrice://")) {
|
||||
auto urlParser = new IntentUrlParser(&ui, &ui);
|
||||
urlParser->handle(file);
|
||||
qCInfo(MainLog) << "Handling URL activation:" << redactActivationUrl(file);
|
||||
// Route through the window's persistent url parser: it serializes
|
||||
// link chains so activations handed over while another chain is
|
||||
// still connecting do not connect concurrently.
|
||||
ui.handleCockatriceLink(file);
|
||||
} else if (QFileInfo(file).exists()) {
|
||||
auto openDeckIntent = new IntentOpenLocalDeck(ui.getTabSupervisor(), file);
|
||||
QObject::connect(openDeckIntent, &Intent::failed, &ui, [&ui](const QString &reason) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue