mirror of
https://github.com/signalapp/Signal-Desktop.git
synced 2026-04-27 20:03:25 +01:00
Use libsignal-net typed Chat API for lookup by username
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
@@ -15,7 +15,8 @@ import EventListener from 'node:events';
|
|||||||
import type { IncomingMessage } from 'node:http';
|
import type { IncomingMessage } from 'node:http';
|
||||||
import { setTimeout as sleep } from 'node:timers/promises';
|
import { setTimeout as sleep } from 'node:timers/promises';
|
||||||
|
|
||||||
import type { AbortableProcess } from '../util/AbortableProcess.std.js';
|
import type { UnauthUsernamesService } from '@signalapp/libsignal-client/dist/net';
|
||||||
|
|
||||||
import { strictAssert } from '../util/assert.std.js';
|
import { strictAssert } from '../util/assert.std.js';
|
||||||
import { explodePromise } from '../util/explodePromise.std.js';
|
import { explodePromise } from '../util/explodePromise.std.js';
|
||||||
import {
|
import {
|
||||||
@@ -33,7 +34,10 @@ import * as Errors from '../types/errors.std.js';
|
|||||||
import * as Bytes from '../Bytes.std.js';
|
import * as Bytes from '../Bytes.std.js';
|
||||||
import { createLogger } from '../logging/log.std.js';
|
import { createLogger } from '../logging/log.std.js';
|
||||||
|
|
||||||
|
import type { AbortableProcess } from '../util/AbortableProcess.std.js';
|
||||||
import type {
|
import type {
|
||||||
|
ChatKind,
|
||||||
|
IChatConnection,
|
||||||
IncomingWebSocketRequest,
|
IncomingWebSocketRequest,
|
||||||
IWebSocketResource,
|
IWebSocketResource,
|
||||||
WebSocketResourceOptions,
|
WebSocketResourceOptions,
|
||||||
@@ -97,8 +101,8 @@ export class SocketManager extends EventListener {
|
|||||||
jitter: JITTER,
|
jitter: JITTER,
|
||||||
});
|
});
|
||||||
|
|
||||||
#authenticated?: AbortableProcess<IWebSocketResource>;
|
#authenticated?: AbortableProcess<IChatConnection<'auth'>>;
|
||||||
#unauthenticated?: AbortableProcess<IWebSocketResource>;
|
#unauthenticated?: AbortableProcess<IChatConnection<'unauth'>>;
|
||||||
#unauthenticatedExpirationTimer?: NodeJS.Timeout;
|
#unauthenticatedExpirationTimer?: NodeJS.Timeout;
|
||||||
#credentials?: WebAPICredentials;
|
#credentials?: WebAPICredentials;
|
||||||
#lazyProxyAgent?: Promise<ProxyAgent>;
|
#lazyProxyAgent?: Promise<ProxyAgent>;
|
||||||
@@ -260,7 +264,7 @@ export class SocketManager extends EventListener {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let authenticated: IWebSocketResource;
|
let authenticated: IChatConnection<'auth'>;
|
||||||
try {
|
try {
|
||||||
authenticated = await process.getResult();
|
authenticated = await process.getResult();
|
||||||
|
|
||||||
@@ -364,7 +368,7 @@ export class SocketManager extends EventListener {
|
|||||||
|
|
||||||
// Either returns currently connecting/active authenticated
|
// Either returns currently connecting/active authenticated
|
||||||
// IWebSocketResource or connects a fresh one.
|
// IWebSocketResource or connects a fresh one.
|
||||||
public async getAuthenticatedResource(): Promise<IWebSocketResource> {
|
public async getAuthenticatedResource(): Promise<IChatConnection<'auth'>> {
|
||||||
if (!this.#authenticated) {
|
if (!this.#authenticated) {
|
||||||
strictAssert(this.#credentials !== undefined, 'Missing credentials');
|
strictAssert(this.#credentials !== undefined, 'Missing credentials');
|
||||||
await this.authenticate(this.#credentials);
|
await this.authenticate(this.#credentials);
|
||||||
@@ -427,13 +431,18 @@ export class SocketManager extends EventListener {
|
|||||||
}).getResult();
|
}).getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getUnauthenticatedLibsignalApi(): Promise<UnauthUsernamesService> {
|
||||||
|
const resource = await this.#getUnauthenticatedResource();
|
||||||
|
return resource.libsignalWebsocket;
|
||||||
|
}
|
||||||
|
|
||||||
// Fetch-compatible wrapper around underlying unauthenticated/authenticated
|
// Fetch-compatible wrapper around underlying unauthenticated/authenticated
|
||||||
// websocket resources. This wrapper supports only limited number of features
|
// websocket resources. This wrapper supports only limited number of features
|
||||||
// of node-fetch despite being API compatible.
|
// of node-fetch despite being API compatible.
|
||||||
public async fetch(url: string, init: RequestInit): Promise<Response> {
|
public async fetch(url: string, init: RequestInit): Promise<Response> {
|
||||||
const headers = new Headers(init.headers);
|
const headers = new Headers(init.headers);
|
||||||
|
|
||||||
let resource: IWebSocketResource;
|
let resource: IChatConnection<'auth'> | IChatConnection<'unauth'>;
|
||||||
if (this.#isAuthenticated(headers)) {
|
if (this.#isAuthenticated(headers)) {
|
||||||
resource = await this.getAuthenticatedResource();
|
resource = await this.getAuthenticatedResource();
|
||||||
} else {
|
} else {
|
||||||
@@ -618,7 +627,7 @@ export class SocketManager extends EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async #getUnauthenticatedResource(): Promise<IWebSocketResource> {
|
async #getUnauthenticatedResource(): Promise<IChatConnection<'unauth'>> {
|
||||||
if (this.#expirationReason) {
|
if (this.#expirationReason) {
|
||||||
throw new HTTPError(`SocketManager ${this.#expirationReason} expired`, {
|
throw new HTTPError(`SocketManager ${this.#expirationReason} expired`, {
|
||||||
code: 0,
|
code: 0,
|
||||||
@@ -642,7 +651,7 @@ export class SocketManager extends EventListener {
|
|||||||
window.SignalContext.getResolvedMessagesLocale()
|
window.SignalContext.getResolvedMessagesLocale()
|
||||||
);
|
);
|
||||||
|
|
||||||
const process: AbortableProcess<IWebSocketResource> =
|
const process: AbortableProcess<IChatConnection<'unauth'>> =
|
||||||
connectUnauthenticatedLibsignal({
|
connectUnauthenticatedLibsignal({
|
||||||
libsignalNet: this.libsignalNet,
|
libsignalNet: this.libsignalNet,
|
||||||
name: UNAUTHENTICATED_CHANNEL_NAME,
|
name: UNAUTHENTICATED_CHANNEL_NAME,
|
||||||
@@ -652,7 +661,7 @@ export class SocketManager extends EventListener {
|
|||||||
|
|
||||||
this.#unauthenticated = process;
|
this.#unauthenticated = process;
|
||||||
|
|
||||||
let unauthenticated: IWebSocketResource;
|
let unauthenticated: IChatConnection<'unauth'>;
|
||||||
try {
|
try {
|
||||||
unauthenticated = await this.#unauthenticated.getResult();
|
unauthenticated = await this.#unauthenticated.getResult();
|
||||||
this.#setUnauthenticatedStatus({
|
this.#setUnauthenticatedStatus({
|
||||||
@@ -771,8 +780,8 @@ export class SocketManager extends EventListener {
|
|||||||
return webSocketResourceConnection;
|
return webSocketResourceConnection;
|
||||||
}
|
}
|
||||||
|
|
||||||
async #checkResource(
|
async #checkResource<Chat extends ChatKind>(
|
||||||
process?: AbortableProcess<IWebSocketResource>
|
process?: AbortableProcess<IChatConnection<Chat>>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (!process) {
|
if (!process) {
|
||||||
return;
|
return;
|
||||||
@@ -786,7 +795,7 @@ export class SocketManager extends EventListener {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
#dropAuthenticated(process: AbortableProcess<IWebSocketResource>): void {
|
#dropAuthenticated(process: AbortableProcess<IChatConnection<'auth'>>): void {
|
||||||
if (this.#authenticated !== process) {
|
if (this.#authenticated !== process) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -807,7 +816,9 @@ export class SocketManager extends EventListener {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#dropUnauthenticated(process: AbortableProcess<IWebSocketResource>): void {
|
#dropUnauthenticated(
|
||||||
|
process: AbortableProcess<IChatConnection<'unauth'>>
|
||||||
|
): void {
|
||||||
if (this.#unauthenticated !== process) {
|
if (this.#unauthenticated !== process) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -822,7 +833,7 @@ export class SocketManager extends EventListener {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async #startUnauthenticatedExpirationTimer(
|
async #startUnauthenticatedExpirationTimer(
|
||||||
expected: IWebSocketResource
|
expected: IChatConnection<'unauth'>
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const process = this.#unauthenticated;
|
const process = this.#unauthenticated;
|
||||||
strictAssert(
|
strictAssert(
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ import type {
|
|||||||
UntaggedPniString,
|
UntaggedPniString,
|
||||||
} from '../types/ServiceId.std.js';
|
} from '../types/ServiceId.std.js';
|
||||||
import {
|
import {
|
||||||
|
fromAciObject,
|
||||||
ServiceIdKind,
|
ServiceIdKind,
|
||||||
serviceIdSchema,
|
serviceIdSchema,
|
||||||
aciSchema,
|
aciSchema,
|
||||||
@@ -628,27 +629,29 @@ async function _promiseAjax<Type extends ResponseType, OutputShape>(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function _retryAjax<Type extends ResponseType, OutputShape>(
|
async function _retry<R>(
|
||||||
url: string | null,
|
f: () => Promise<R>,
|
||||||
options: PromiseAjaxOptionsType<Type, OutputShape>,
|
provided?: { abortSignal?: AbortSignal } & (
|
||||||
providedLimit?: number,
|
| { limit: number; count: number }
|
||||||
providedCount?: number
|
| { limit?: undefined; count?: undefined }
|
||||||
): Promise<unknown> {
|
)
|
||||||
const count = (providedCount || 0) + 1;
|
): Promise<R> {
|
||||||
const limit = providedLimit || 3;
|
const count = (provided?.count ?? 0) + 1;
|
||||||
|
const limit = provided?.limit ?? 3;
|
||||||
|
const abortSignal = provided?.abortSignal;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return await _promiseAjax(url, options);
|
return await f();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (
|
if (
|
||||||
e instanceof HTTPError &&
|
e instanceof HTTPError &&
|
||||||
e.code === -1 &&
|
e.code === -1 &&
|
||||||
count < limit &&
|
count < limit &&
|
||||||
!options.abortSignal?.aborted
|
!abortSignal?.aborted
|
||||||
) {
|
) {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
resolve(_retryAjax(url, options, limit, count));
|
resolve(_retry(f, { abortSignal, limit, count }));
|
||||||
}, 1000);
|
}, 1000);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -681,7 +684,9 @@ async function _outerAjax<Type extends ResponseType, OutputShape>(
|
|||||||
return _promiseAjax(url, options);
|
return _promiseAjax(url, options);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _retryAjax(url, options);
|
return _retry(() => _promiseAjax(url, options), {
|
||||||
|
abortSignal: options.abortSignal,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function makeHTTPError(
|
function makeHTTPError(
|
||||||
@@ -944,13 +949,7 @@ export type GetAccountForUsernameOptionsType = Readonly<{
|
|||||||
hash: Uint8Array;
|
hash: Uint8Array;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
const getAccountForUsernameResultZod = z.object({
|
export type GetAccountForUsernameResultType = AciString | null;
|
||||||
uuid: aciSchema,
|
|
||||||
});
|
|
||||||
|
|
||||||
export type GetAccountForUsernameResultType = z.infer<
|
|
||||||
typeof getAccountForUsernameResultZod
|
|
||||||
>;
|
|
||||||
|
|
||||||
const getDevicesResultZod = z.object({
|
const getDevicesResultZod = z.object({
|
||||||
devices: z.array(
|
devices: z.array(
|
||||||
@@ -2450,19 +2449,12 @@ export async function getTransferArchive({
|
|||||||
export async function getAccountForUsername({
|
export async function getAccountForUsername({
|
||||||
hash,
|
hash,
|
||||||
}: GetAccountForUsernameOptionsType): Promise<GetAccountForUsernameResultType> {
|
}: GetAccountForUsernameOptionsType): Promise<GetAccountForUsernameResultType> {
|
||||||
const hashBase64 = toWebSafeBase64(Bytes.toBase64(hash));
|
const aci = await _retry(async () => {
|
||||||
return _ajax({
|
const chat = await socketManager.getUnauthenticatedLibsignalApi();
|
||||||
host: 'chatService',
|
return chat.lookUpUsernameHash({ hash });
|
||||||
call: 'username',
|
|
||||||
httpType: 'GET',
|
|
||||||
urlParameters: `/${hashBase64}`,
|
|
||||||
responseType: 'json',
|
|
||||||
redactUrl: _createRedactor(hashBase64),
|
|
||||||
unauthenticated: true,
|
|
||||||
accessKey: undefined,
|
|
||||||
groupSendToken: undefined,
|
|
||||||
zodSchema: getAccountForUsernameResultZod,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return aci ? fromAciObject(aci) : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function putProfile(
|
export async function putProfile(
|
||||||
|
|||||||
@@ -37,9 +37,11 @@ import type { LibSignalError, Net } from '@signalapp/libsignal-client';
|
|||||||
import { ErrorCode } from '@signalapp/libsignal-client';
|
import { ErrorCode } from '@signalapp/libsignal-client';
|
||||||
import { Buffer } from 'node:buffer';
|
import { Buffer } from 'node:buffer';
|
||||||
import type {
|
import type {
|
||||||
|
AuthenticatedChatConnection,
|
||||||
ChatServerMessageAck,
|
ChatServerMessageAck,
|
||||||
ChatServiceListener,
|
ChatServiceListener,
|
||||||
ConnectionEventsListener,
|
ConnectionEventsListener,
|
||||||
|
UnauthenticatedChatConnection,
|
||||||
} from '@signalapp/libsignal-client/dist/net/Chat.js';
|
} from '@signalapp/libsignal-client/dist/net/Chat.js';
|
||||||
import type { EventHandler } from './EventTarget.std.js';
|
import type { EventHandler } from './EventTarget.std.js';
|
||||||
import EventTarget from './EventTarget.std.js';
|
import EventTarget from './EventTarget.std.js';
|
||||||
@@ -281,6 +283,12 @@ export class CloseEvent extends Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ChatKind = 'auth' | 'unauth';
|
||||||
|
|
||||||
|
type LibsignalChatConnection<Kind extends ChatKind> = Kind extends 'auth'
|
||||||
|
? AuthenticatedChatConnection
|
||||||
|
: UnauthenticatedChatConnection;
|
||||||
|
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
export interface IWebSocketResource extends IResource {
|
export interface IWebSocketResource extends IResource {
|
||||||
sendRequest(options: SendRequestOptions): Promise<Response>;
|
sendRequest(options: SendRequestOptions): Promise<Response>;
|
||||||
@@ -296,8 +304,12 @@ export interface IWebSocketResource extends IResource {
|
|||||||
localPort(): number | undefined;
|
localPort(): number | undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
type LibsignalWebSocketResourceHolder = {
|
export type IChatConnection<Chat extends ChatKind> = IWebSocketResource & {
|
||||||
resource: LibsignalWebSocketResource | undefined;
|
get libsignalWebsocket(): LibsignalChatConnection<Chat>;
|
||||||
|
};
|
||||||
|
|
||||||
|
type LibsignalWebSocketResourceHolder<Chat extends ChatKind> = {
|
||||||
|
resource: LibsignalWebSocketResource<Chat> | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNEXPECTED_DISCONNECT_CODE = 3001;
|
const UNEXPECTED_DISCONNECT_CODE = 3001;
|
||||||
@@ -312,20 +324,20 @@ export function connectUnauthenticatedLibsignal({
|
|||||||
name: string;
|
name: string;
|
||||||
userLanguages: ReadonlyArray<string>;
|
userLanguages: ReadonlyArray<string>;
|
||||||
keepalive: KeepAliveOptionsType;
|
keepalive: KeepAliveOptionsType;
|
||||||
}): AbortableProcess<LibsignalWebSocketResource> {
|
}): AbortableProcess<LibsignalWebSocketResource<'unauth'>> {
|
||||||
const logId = `LibsignalWebSocketResource(${name})`;
|
const logId = `LibsignalWebSocketResource(${name})`;
|
||||||
const listener: LibsignalWebSocketResourceHolder & ConnectionEventsListener =
|
const listener: LibsignalWebSocketResourceHolder<'unauth'> &
|
||||||
{
|
ConnectionEventsListener = {
|
||||||
resource: undefined,
|
resource: undefined,
|
||||||
onConnectionInterrupted(cause: LibSignalError | null): void {
|
onConnectionInterrupted(cause: LibSignalError | null): void {
|
||||||
if (!this.resource) {
|
if (!this.resource) {
|
||||||
logDisconnectedListenerWarn(logId, 'onConnectionInterrupted');
|
logDisconnectedListenerWarn(logId, 'onConnectionInterrupted');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.resource.onConnectionInterrupted(cause);
|
this.resource.onConnectionInterrupted(cause);
|
||||||
this.resource = undefined;
|
this.resource = undefined;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return connectLibsignal(
|
return connectLibsignal(
|
||||||
abortSignal =>
|
abortSignal =>
|
||||||
libsignalNet.connectUnauthenticatedChat(listener, {
|
libsignalNet.connectUnauthenticatedChat(listener, {
|
||||||
@@ -356,9 +368,10 @@ export function connectAuthenticatedLibsignal({
|
|||||||
receiveStories: boolean;
|
receiveStories: boolean;
|
||||||
userLanguages: ReadonlyArray<string>;
|
userLanguages: ReadonlyArray<string>;
|
||||||
keepalive: KeepAliveOptionsType;
|
keepalive: KeepAliveOptionsType;
|
||||||
}): AbortableProcess<LibsignalWebSocketResource> {
|
}): AbortableProcess<LibsignalWebSocketResource<'auth'>> {
|
||||||
const logId = `LibsignalWebSocketResource(${name})`;
|
const logId = `LibsignalWebSocketResource(${name})`;
|
||||||
const listener: LibsignalWebSocketResourceHolder & ChatServiceListener = {
|
const listener: LibsignalWebSocketResourceHolder<'auth'> &
|
||||||
|
ChatServiceListener = {
|
||||||
resource: undefined,
|
resource: undefined,
|
||||||
onIncomingMessage(
|
onIncomingMessage(
|
||||||
envelope: Uint8Array,
|
envelope: Uint8Array,
|
||||||
@@ -418,16 +431,14 @@ function logDisconnectedListenerWarn(logId: string, method: string): void {
|
|||||||
log.warn(`${logId} received ${method}, but listener already disconnected`);
|
log.warn(`${logId} received ${method}, but listener already disconnected`);
|
||||||
}
|
}
|
||||||
|
|
||||||
function connectLibsignal(
|
function connectLibsignal<Chat extends ChatKind>(
|
||||||
makeConnection: (
|
makeConnection: (
|
||||||
abortSignal: AbortSignal
|
abortSignal: AbortSignal
|
||||||
) => Promise<
|
) => Promise<LibsignalChatConnection<Chat>>,
|
||||||
Net.UnauthenticatedChatConnection | Net.AuthenticatedChatConnection
|
resourceHolder: LibsignalWebSocketResourceHolder<Chat>,
|
||||||
>,
|
|
||||||
resourceHolder: LibsignalWebSocketResourceHolder,
|
|
||||||
logId: string,
|
logId: string,
|
||||||
keepalive: KeepAliveOptionsType
|
keepalive: KeepAliveOptionsType
|
||||||
): AbortableProcess<LibsignalWebSocketResource> {
|
): AbortableProcess<LibsignalWebSocketResource<Chat>> {
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
const connectAsync = async () => {
|
const connectAsync = async () => {
|
||||||
try {
|
try {
|
||||||
@@ -454,7 +465,7 @@ function connectLibsignal(
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
return new AbortableProcess<LibsignalWebSocketResource>(
|
return new AbortableProcess<LibsignalWebSocketResource<Chat>>(
|
||||||
`${logId}.connect`,
|
`${logId}.connect`,
|
||||||
{
|
{
|
||||||
abort() {
|
abort() {
|
||||||
@@ -470,9 +481,9 @@ function connectLibsignal(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LibsignalWebSocketResource
|
export class LibsignalWebSocketResource<Chat extends ChatKind>
|
||||||
extends EventTarget
|
extends EventTarget
|
||||||
implements IWebSocketResource
|
implements IChatConnection<Chat>
|
||||||
{
|
{
|
||||||
// The reason that the connection was closed, if it was closed.
|
// The reason that the connection was closed, if it was closed.
|
||||||
//
|
//
|
||||||
@@ -487,7 +498,7 @@ export class LibsignalWebSocketResource
|
|||||||
#keepalive: KeepAlive;
|
#keepalive: KeepAlive;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly chatService: Net.ChatConnection,
|
private readonly chatService: LibsignalChatConnection<Chat>,
|
||||||
private readonly socketIpVersion: IpVersion,
|
private readonly socketIpVersion: IpVersion,
|
||||||
private readonly localPortNumber: number,
|
private readonly localPortNumber: number,
|
||||||
private readonly logId: string,
|
private readonly logId: string,
|
||||||
@@ -576,6 +587,10 @@ export class LibsignalWebSocketResource
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
get libsignalWebsocket(): LibsignalChatConnection<Chat> {
|
||||||
|
return this.chatService;
|
||||||
|
}
|
||||||
|
|
||||||
public async sendRequestGetDebugInfo(
|
public async sendRequestGetDebugInfo(
|
||||||
options: SendRequestOptions
|
options: SendRequestOptions
|
||||||
): Promise<Response> {
|
): Promise<Response> {
|
||||||
|
|||||||
@@ -1,21 +1,20 @@
|
|||||||
// Copyright 2022 Signal Messenger, LLC
|
// Copyright 2022 Signal Messenger, LLC
|
||||||
// SPDX-License-Identifier: AGPL-3.0-only
|
// SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { usernames, LibSignalErrorBase } from '@signalapp/libsignal-client';
|
import { usernames } from '@signalapp/libsignal-client';
|
||||||
|
|
||||||
import type { UserNotFoundModalStateType } from '../state/ducks/globalModals.preload.js';
|
import type { UserNotFoundModalStateType } from '../state/ducks/globalModals.preload.js';
|
||||||
import { createLogger } from '../logging/log.std.js';
|
import { createLogger } from '../logging/log.std.js';
|
||||||
import type { AciString } from '../types/ServiceId.std.js';
|
import type { AciString } from '../types/ServiceId.std.js';
|
||||||
|
import * as Errors from '../types/errors.std.js';
|
||||||
|
import { ToastType } from '../types/Toast.dom.js';
|
||||||
|
import { strictAssert } from './assert.std.js';
|
||||||
|
import type { UUIDFetchStateKeyType } from './uuidFetchState.std.js';
|
||||||
|
import { getServiceIdsForE164s } from './getServiceIdsForE164s.dom.js';
|
||||||
import {
|
import {
|
||||||
getAccountForUsername,
|
getAccountForUsername,
|
||||||
cdsLookup,
|
cdsLookup,
|
||||||
} from '../textsecure/WebAPI.preload.js';
|
} from '../textsecure/WebAPI.preload.js';
|
||||||
import * as Errors from '../types/errors.std.js';
|
|
||||||
import { ToastType } from '../types/Toast.dom.js';
|
|
||||||
import { HTTPError } from '../types/HTTPError.std.js';
|
|
||||||
import { strictAssert } from './assert.std.js';
|
|
||||||
import type { UUIDFetchStateKeyType } from './uuidFetchState.std.js';
|
|
||||||
import { getServiceIdsForE164s } from './getServiceIdsForE164s.dom.js';
|
|
||||||
|
|
||||||
const log = createLogger('lookupConversationWithoutServiceId');
|
const log = createLogger('lookupConversationWithoutServiceId');
|
||||||
|
|
||||||
@@ -155,33 +154,17 @@ export async function checkForUsername(
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const accountAci = await getAccountForUsername({
|
||||||
const account = await getAccountForUsername({
|
hash,
|
||||||
hash,
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (!account.uuid) {
|
if (!accountAci) {
|
||||||
log.error("checkForUsername: Returned account didn't include a uuid");
|
log.error("checkForUsername: Returned account didn't include a uuid");
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
aci: account.uuid,
|
|
||||||
username: fixedUsername,
|
|
||||||
};
|
|
||||||
} catch (error) {
|
|
||||||
if (error instanceof HTTPError) {
|
|
||||||
if (error.code === 404) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invalid username
|
|
||||||
if (error instanceof LibSignalErrorBase) {
|
|
||||||
log.error('checkForUsername: invalid username');
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw error;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
aci: accountAci,
|
||||||
|
username: fixedUsername,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user