mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-11-05 01:23:24 -08:00
[DeckSync] Match server rows by identity and hash the whole deck
Sync keyed local files to server rows by path, but the server names a row
after the deck, not after the file, so any deck whose file name and deck name
differ uploaded again on every run. A second pass then brought the server copy
back as an extra local file.
- Match by the sidecar's row id, then guid, then content, and only then by the
server path, so renaming either side no longer duplicates a deck.
- Key the server tree by row id: the server allows several rows with the same
name in one folder, and keying by path silently dropped all but one.
- Stop discarding rows whose name contains '/' ("U/W Control"). They stay
matchable, and only the download file name is sanitised.
- Build the download path from the folder plus a sanitised row name, including
every folder segment, so a hostile server name cannot escape the deck folder.
- Download a colliding server row under a unique name and count it, instead of
skipping it without a trace.
- Hash the whole deck instead of the card hash: SHA-1 over the native deck
string covers name, printings, banner, tokens and sideboard plans. The client
and the server hash the exact bytes they exchange, so both agree.
Adds deck_content_hash_test for the client/server hashing invariant and for the
name-only change the card hash cannot see.
This commit is contained in:
parent
ad0da98a86
commit
2916fa45af
7 changed files with 215 additions and 81 deletions
|
|
@ -9,6 +9,7 @@
|
|||
#include "tree/inner_deck_list_node.h"
|
||||
|
||||
#include <QAnyStringView>
|
||||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QSet>
|
||||
#include <QSharedPointer>
|
||||
|
|
@ -453,6 +454,16 @@ void DeckList::refreshDeckHash()
|
|||
cachedDeckHash = QString();
|
||||
}
|
||||
|
||||
QString DeckList::contentHash(const QString &nativeDeck)
|
||||
{
|
||||
return QString::fromLatin1(QCryptographicHash::hash(nativeDeck.toUtf8(), QCryptographicHash::Sha1).toHex());
|
||||
}
|
||||
|
||||
QString DeckList::getContentHash() const
|
||||
{
|
||||
return contentHash(writeToString_Native());
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a given function on each card in the deck.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -289,6 +289,16 @@ public:
|
|||
/** @name Deck identity */
|
||||
///@{
|
||||
QString getDeckHash() const;
|
||||
/**
|
||||
* @brief SHA-1 of a native deck string, covering everything the card hash
|
||||
* ignores (name, printings, banner, tokens, comments, sideboard plans).
|
||||
*
|
||||
* Deck-collection sync hashes the exact string it sends or receives, so both
|
||||
* peers compare the same bytes.
|
||||
*/
|
||||
static QString contentHash(const QString &nativeDeck);
|
||||
/** @brief contentHash() of this deck's native serialisation. */
|
||||
QString getContentHash() const;
|
||||
void refreshDeckHash();
|
||||
///@}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue