mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-25 11:56:11 -07:00
* [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>
75 lines
2.7 KiB
C++
75 lines
2.7 KiB
C++
#ifndef COCKATRICE_URL_PARSER_H
|
|
#define COCKATRICE_URL_PARSER_H
|
|
|
|
#include <QList>
|
|
#include <QObject>
|
|
#include <QUrlQuery>
|
|
|
|
class Intent;
|
|
class MainWindow;
|
|
struct ContextJoinGame;
|
|
|
|
/**
|
|
* @brief One queued intent chain with the session-migration bookkeeping for it.
|
|
*
|
|
* The restore fields are per-chain on purpose: chains are parsed while earlier
|
|
* ones are still queued, so parser-wide state would let one chain's failure
|
|
* consume the restore data another chain recorded.
|
|
*/
|
|
struct PendingIntentChain
|
|
{
|
|
QList<Intent *> intents;
|
|
|
|
// Snapshot of the session in place when this chain started running, so a
|
|
// queued chain follows whichever server the chain before it settled on.
|
|
QString previousServerHost;
|
|
QString previousServerPort;
|
|
|
|
// Recorded at parse time when the user confirmed migrating away from a live
|
|
// session to the host/port named by the link.
|
|
QString migrationTargetHost;
|
|
QString migrationTargetPort;
|
|
bool pendingRestore = false;
|
|
};
|
|
|
|
/**
|
|
* @brief Parses cockatrice:// links and runs them as serialized intent chains.
|
|
*
|
|
* Links are parsed by action (joingame/opendeck) and translated into an intent
|
|
* chain. Chains are queued and run one at a time: a document can hand multiple
|
|
* links to the window while an earlier chain still connects, and running two
|
|
* connect chains concurrently tears the connection down. urlChainFinished is
|
|
* emitted once the queue has fully drained.
|
|
*/
|
|
class IntentUrlParser : public QObject
|
|
{
|
|
Q_OBJECT
|
|
|
|
public:
|
|
IntentUrlParser(QObject *parent, MainWindow *mainWindow);
|
|
void handle(const QString &urlStr);
|
|
|
|
signals:
|
|
/** @brief Emitted when the last queued chain ended; carries whether the client is logged in. */
|
|
void urlChainFinished(bool connected);
|
|
|
|
private:
|
|
Intent *createJoinGameIntent(const QUrlQuery &query, PendingIntentChain &chain);
|
|
Intent *createOpenDeckIntent(const QUrlQuery &query, PendingIntentChain &chain);
|
|
QString generateJoinGameMessage(const ContextJoinGame &context, const QString &gameDescription);
|
|
[[nodiscard]] bool isConnectedTo(const QString &hostname, const QString &port) const;
|
|
void startNextChain();
|
|
void chainEnded(bool chainSucceeded);
|
|
void onChainIntentDestroyed();
|
|
void restorePreviousServer(const PendingIntentChain &chain);
|
|
void restoreToPreviousServer(const PendingIntentChain &chain);
|
|
|
|
MainWindow *mainWindow;
|
|
QList<PendingIntentChain> pendingChains;
|
|
bool chainRunning = false;
|
|
// Disconnects the destroyed-signal backstop once a chain ends, so an old
|
|
// intent's deferred deletion cannot end the chain that runs after it.
|
|
QMetaObject::Connection chainBackstopConnection;
|
|
};
|
|
|
|
#endif // COCKATRICE_URL_PARSER_H
|