Reported by a user: the passphrase could be set to the username.
This is not the usual weak-password argument, and the usual
reasoning does not reach it. For a relay-local account the KDF salt is
HKDF(lowercased(username)) — a pure function of a name that is public by
design, because it is how people find each other and because a new
device has to derive it offline before it can talk to anything. The
account key is PBKDF2(passphrase, salt), and the address is that key's
public half.
So when the passphrase IS the username, every input is public. Deriving
the identity is one PBKDF2 run rather than a search: the 1.3 million
iterations buy about a second, once, against a guess that is already
correct. Whoever runs it can claim the address and sign as that person
— and the thing they take is the one this product says no server can
take away.
Refused at sign-up, through the same list that already explains why the
button is disabled, so the refusal cannot be silent. It gives the real
reason rather than generic password advice, because the real reason is
what makes it worth retyping.
Near misses are refused too. "sunshine1" against the username
"sunshine" is ten guesses; a search space small enough to run over lunch
is not meaningfully different from none. It stops at 8 added characters,
so a memorable phrase that happens to contain the username is still
allowed — pushing people off passphrases toward worse ones would cost
more than it saves.
Normalisation matches the KDF's exactly. The salt lowercases and
trims the handle, so "Sunshine" derives the same key as "sunshine"; a
check that disagreed would refuse the safe spelling and permit the
unsafe one.
KNOWN GAP, not fixed here: this is a client-side check and therefore
bypassable, and it does nothing for accounts that already exist. The
authoritative gate belongs in the signup handler, which is not in any
local checkout — flamenet-api has no messenger routes and
flamenet-accounts-hosting is deploy-only here. Android needs the same
rule. Both are follow-ups.
Reported by a user: the passphrase could be set to the username.
This is not the usual weak-password argument, and the usual
reasoning does not reach it. For a relay-local account the KDF salt is
HKDF(lowercased(username)) — a pure function of a name that is public by
design, because it is how people find each other and because a new
device has to derive it offline before it can talk to anything. The
account key is PBKDF2(passphrase, salt), and the address is that key's
public half.
So when the passphrase IS the username, every input is public. Deriving
the identity is one PBKDF2 run rather than a search: the 1.3 million
iterations buy about a second, once, against a guess that is already
correct. Whoever runs it can claim the address and sign as that person
— and the thing they take is the one this product says no server can
take away.
Refused at sign-up, through the same list that already explains why the
button is disabled, so the refusal cannot be silent. It gives the real
reason rather than generic password advice, because the real reason is
what makes it worth retyping.
Near misses are refused too. "sunshine1" against the username
"sunshine" is ten guesses; a search space small enough to run over lunch
is not meaningfully different from none. It stops at 8 added characters,
so a memorable phrase that happens to contain the username is still
allowed — pushing people off passphrases toward worse ones would cost
more than it saves.
Normalisation matches the KDF's exactly. The salt lowercases and
trims the handle, so "Sunshine" derives the same key as "sunshine"; a
check that disagreed would refuse the safe spelling and permit the
unsafe one.
KNOWN GAP, not fixed here: this is a client-side check and therefore
bypassable, and it does nothing for accounts that already exist. The
authoritative gate belongs in the signup handler, which is not in any
local checkout — flamenet-api has no messenger routes and
flamenet-accounts-hosting is deploy-only here. Android needs the same
rule. Both are follow-ups.
6 new tests; 764 XCTest + 61 Swift Testing green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Reported by a user: the passphrase could be set to the username.
This is not the usual weak-password argument, and the usual
reasoning does not reach it. For a relay-local account the KDF salt is
HKDF(lowercased(username)) — a pure function of a name that is public by
design, because it is how people find each other and because a new
device has to derive it offline before it can talk to anything. The
account key is PBKDF2(passphrase, salt), and the address is that key's
public half.
So when the passphrase IS the username, every input is public. Deriving
the identity is one PBKDF2 run rather than a search: the 1.3 million
iterations buy about a second, once, against a guess that is already
correct. Whoever runs it can claim the address and sign as that person
— and the thing they take is the one this product says no server can
take away.
Refused at sign-up, through the same list that already explains why the
button is disabled, so the refusal cannot be silent. It gives the real
reason rather than generic password advice, because the real reason is
what makes it worth retyping.
Near misses are refused too. "sunshine1" against the username
"sunshine" is ten guesses; a search space small enough to run over lunch
is not meaningfully different from none. It stops at 8 added characters,
so a memorable phrase that happens to contain the username is still
allowed — pushing people off passphrases toward worse ones would cost
more than it saves.
Normalisation matches the KDF's exactly. The salt lowercases and
trims the handle, so "Sunshine" derives the same key as "sunshine"; a
check that disagreed would refuse the safe spelling and permit the
unsafe one.
KNOWN GAP, not fixed here: this is a client-side check and therefore
bypassable, and it does nothing for accounts that already exist. The
authoritative gate belongs in the signup handler, which is not in any
local checkout — flamenet-api has no messenger routes and
flamenet-accounts-hosting is deploy-only here. Android needs the same
rule. Both are follow-ups.
6 new tests; 764 XCTest + 61 Swift Testing green.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
assigned to @paulhitt
mentioned in commit
9af8e5b1b8changed the description