Use combined username link API

This commit is contained in:
Fedor Indutny 2023-07-21 01:19:32 +02:00 committed by GitHub
parent 82e058f2b8
commit 13193649d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 42 deletions

View file

@ -89,7 +89,7 @@
"@popperjs/core": "2.11.6", "@popperjs/core": "2.11.6",
"@react-spring/web": "9.5.5", "@react-spring/web": "9.5.5",
"@signalapp/better-sqlite3": "8.4.3", "@signalapp/better-sqlite3": "8.4.3",
"@signalapp/libsignal-client": "0.28.0", "@signalapp/libsignal-client": "0.29.0",
"@signalapp/ringrtc": "2.29.1", "@signalapp/ringrtc": "2.29.1",
"@types/fabric": "4.5.3", "@types/fabric": "4.5.3",
"backbone": "1.4.0", "backbone": "1.4.0",
@ -190,7 +190,7 @@
"@electron/fuses": "1.5.0", "@electron/fuses": "1.5.0",
"@formatjs/intl": "2.6.7", "@formatjs/intl": "2.6.7",
"@mixer/parallel-prettier": "2.0.3", "@mixer/parallel-prettier": "2.0.3",
"@signalapp/mock-server": "3.2.0", "@signalapp/mock-server": "3.2.1",
"@storybook/addon-a11y": "6.5.6", "@storybook/addon-a11y": "6.5.6",
"@storybook/addon-actions": "6.5.6", "@storybook/addon-actions": "6.5.6",
"@storybook/addon-controls": "6.5.6", "@storybook/addon-controls": "6.5.6",

View file

@ -183,16 +183,26 @@ export async function confirmUsername(
strictAssert(usernames.hash(username).equals(hash), 'username hash mismatch'); strictAssert(usernames.hash(username).equals(hash), 'username hash mismatch');
try { try {
await server.confirmUsername({ const { entropy, encryptedUsername } =
hash, usernames.createUsernameLink(username);
proof,
abortSignal, await window.storage.remove('usernameLink');
const { usernameLinkHandle: serverIdString } = await server.confirmUsername(
{
hash,
proof,
encryptedUsername,
abortSignal,
}
);
await window.storage.put('usernameLink', {
entropy,
serverId: uuidToBytes(serverIdString),
}); });
await updateUsernameAndSyncProfile(username); await updateUsernameAndSyncProfile(username);
// TODO: DESKTOP-5687
await resetLink(username);
} catch (error) { } catch (error) {
if (error instanceof HTTPError) { if (error instanceof HTTPError) {
if (error.code === 413 || error.code === 429) { if (error.code === 413 || error.code === 429) {
@ -245,17 +255,15 @@ export async function resetLink(username: string): Promise<void> {
throw new Error('Username has changed on another device'); throw new Error('Username has changed on another device');
} }
const link = usernames.createUsernameLink(username); const { entropy, encryptedUsername } = usernames.createUsernameLink(username);
await window.storage.remove('usernameLink'); await window.storage.remove('usernameLink');
const { usernameLinkHandle: serverIdString } = const { usernameLinkHandle: serverIdString } =
await server.replaceUsernameLink({ await server.replaceUsernameLink({ encryptedUsername });
encryptedUsername: link.encryptedUsername,
});
await window.storage.put('usernameLink', { await window.storage.put('usernameLink', {
entropy: link.entropy, entropy,
serverId: uuidToBytes(serverIdString), serverId: uuidToBytes(serverIdString),
}); });
@ -285,10 +293,8 @@ export async function resolveUsernameByLinkBase64(
serverId serverId
); );
const link = new usernames.UsernameLink( return usernames.decryptUsernameLink({
Buffer.from(entropy), entropy: Buffer.from(entropy),
Buffer.from(usernameLinkEncryptedValue) encryptedUsername: Buffer.from(usernameLinkEncryptedValue),
); });
return link.decryptUsername();
} }

View file

@ -222,18 +222,15 @@ describe('pnp/username', function needsName() {
const linkUuid = bufferToUuid(Buffer.from(usernameLink.serverId)); const linkUuid = bufferToUuid(Buffer.from(usernameLink.serverId));
const encryptedLinkBase64 = await server.lookupByUsernameLink(linkUuid); const encryptedLink = await server.lookupByUsernameLink(linkUuid);
if (!encryptedLinkBase64) { if (!encryptedLink) {
throw new Error('Could not find link on the sever'); throw new Error('Could not find link on the sever');
} }
const encryptedLink = Buffer.from(encryptedLinkBase64, 'base64'); const linkUsername = usernames.decryptUsernameLink({
entropy: Buffer.from(usernameLink.entropy),
const link = new usernames.UsernameLink( encryptedUsername: encryptedLink,
Buffer.from(usernameLink.entropy), });
encryptedLink
);
const linkUsername = link.decryptUsername();
assert.strictEqual(linkUsername, username); assert.strictEqual(linkUsername, username);
state = newState; state = newState;

View file

@ -831,6 +831,7 @@ export type ReplaceUsernameLinkOptionsType = Readonly<{
export type ConfirmUsernameOptionsType = Readonly<{ export type ConfirmUsernameOptionsType = Readonly<{
hash: Uint8Array; hash: Uint8Array;
proof: Uint8Array; proof: Uint8Array;
encryptedUsername: Uint8Array;
abortSignal?: AbortSignal; abortSignal?: AbortSignal;
}>; }>;
@ -843,6 +844,13 @@ export type ReserveUsernameResultType = z.infer<
typeof reserveUsernameResultZod typeof reserveUsernameResultZod
>; >;
const confirmUsernameResultZod = z.object({
usernameLinkHandle: z.string(),
});
export type ConfirmUsernameResultType = z.infer<
typeof confirmUsernameResultZod
>;
const replaceUsernameLinkResultZod = z.object({ const replaceUsernameLinkResultZod = z.object({
usernameLinkHandle: z.string(), usernameLinkHandle: z.string(),
}); });
@ -851,7 +859,9 @@ export type ReplaceUsernameLinkResultType = z.infer<
>; >;
const resolveUsernameLinkResultZod = z.object({ const resolveUsernameLinkResultZod = z.object({
usernameLinkEncryptedValue: z.string().transform(x => Bytes.fromBase64(x)), usernameLinkEncryptedValue: z
.string()
.transform(x => Bytes.fromBase64(fromWebSafeBase64(x))),
}); });
export type ResolveUsernameLinkResultType = z.infer< export type ResolveUsernameLinkResultType = z.infer<
typeof resolveUsernameLinkResultZod typeof resolveUsernameLinkResultZod
@ -1020,7 +1030,9 @@ export type WebAPIType = {
reserveUsername: ( reserveUsername: (
options: ReserveUsernameOptionsType options: ReserveUsernameOptionsType
) => Promise<ReserveUsernameResultType>; ) => Promise<ReserveUsernameResultType>;
confirmUsername(options: ConfirmUsernameOptionsType): Promise<void>; confirmUsername(
options: ConfirmUsernameOptionsType
): Promise<ConfirmUsernameResultType>;
replaceUsernameLink: ( replaceUsernameLink: (
options: ReplaceUsernameLinkOptionsType options: ReplaceUsernameLinkOptionsType
) => Promise<ReplaceUsernameLinkResultType>; ) => Promise<ReplaceUsernameLinkResultType>;
@ -1916,17 +1928,21 @@ export function initialize({
async function confirmUsername({ async function confirmUsername({
hash, hash,
proof, proof,
encryptedUsername,
abortSignal, abortSignal,
}: ConfirmUsernameOptionsType) { }: ConfirmUsernameOptionsType) {
await _ajax({ const response = await _ajax({
call: 'confirmUsername', call: 'confirmUsername',
httpType: 'PUT', httpType: 'PUT',
jsonData: { jsonData: {
usernameHash: toWebSafeBase64(Bytes.toBase64(hash)), usernameHash: toWebSafeBase64(Bytes.toBase64(hash)),
zkProof: toWebSafeBase64(Bytes.toBase64(proof)), zkProof: toWebSafeBase64(Bytes.toBase64(proof)),
encryptedUsername: toWebSafeBase64(Bytes.toBase64(encryptedUsername)),
}, },
responseType: 'json',
abortSignal, abortSignal,
}); });
return confirmUsernameResultZod.parse(response);
} }
async function replaceUsernameLink({ async function replaceUsernameLink({
@ -1938,7 +1954,9 @@ export function initialize({
httpType: 'PUT', httpType: 'PUT',
responseType: 'json', responseType: 'json',
jsonData: { jsonData: {
usernameLinkEncryptedValue: Bytes.toBase64(encryptedUsername), usernameLinkEncryptedValue: toWebSafeBase64(
Bytes.toBase64(encryptedUsername)
),
}, },
}) })
); );

View file

@ -2276,20 +2276,20 @@
bindings "^1.5.0" bindings "^1.5.0"
tar "^6.1.0" tar "^6.1.0"
"@signalapp/libsignal-client@0.28.0", "@signalapp/libsignal-client@^0.28.0": "@signalapp/libsignal-client@0.29.0", "@signalapp/libsignal-client@^0.29.0":
version "0.28.0" version "0.29.0"
resolved "https://registry.yarnpkg.com/@signalapp/libsignal-client/-/libsignal-client-0.28.0.tgz#b1553a4b56fc01afe5e9b2785abd5c680f46ebc4" resolved "https://registry.yarnpkg.com/@signalapp/libsignal-client/-/libsignal-client-0.29.0.tgz#36c467645551e023924371f2d894085dfbd3e59c"
integrity sha512-Vl3vt9hBdPW2/cwuf8+ZMwxmlAlnuBSgsKebRPfDOboLWDRlQRq+tstlwfBFU0e/2ixgY95Wulu46I1cl6H40g== integrity sha512-p+FoCV0wORPoZNixyib/kxPL1+7OdNNjAxCKbiuN+1zx948YDZxVrttJv1FylPrLiTUpF+AloZr88elnUq4ZJA==
dependencies: dependencies:
node-gyp-build "^4.2.3" node-gyp-build "^4.2.3"
uuid "^8.3.0" uuid "^8.3.0"
"@signalapp/mock-server@3.2.0": "@signalapp/mock-server@3.2.1":
version "3.2.0" version "3.2.1"
resolved "https://registry.yarnpkg.com/@signalapp/mock-server/-/mock-server-3.2.0.tgz#9371dc2002a1a8aa25ac815944a443cdc0a1b7c5" resolved "https://registry.yarnpkg.com/@signalapp/mock-server/-/mock-server-3.2.1.tgz#36fd3e72b44dbcb6c82fdb27bbf56f8393e8f065"
integrity sha512-4rpAAH5tV8eoIikb6FozMmrCKr+pqaP9JNyfZQ5YLPanAiTE9iER7WJex0HJ9PhscgswbzWIPFuRyhm/qPocVQ== integrity sha512-irT4U3e8Lve9HODGIlXx+vElONaPNe7Ks9QRoSPSR4o0DbUX/g+zUxfEu7gjEi0CQI8OKxcJHe7e5DbE8mvXng==
dependencies: dependencies:
"@signalapp/libsignal-client" "^0.28.0" "@signalapp/libsignal-client" "^0.29.0"
debug "^4.3.2" debug "^4.3.2"
long "^4.0.0" long "^4.0.0"
micro "^9.3.4" micro "^9.3.4"