@signalapp/mock-server
Advanced tools
Comparing version 2.13.0 to 2.14.0-rc.1
{ | ||
"name": "@signalapp/mock-server", | ||
"version": "2.13.0", | ||
"version": "2.14.0-rc.1", | ||
"description": "Mock Signal Server for writing tests", | ||
@@ -43,3 +43,3 @@ "main": "src/index.js", | ||
"dependencies": { | ||
"@signalapp/libsignal-client": "^0.20.0", | ||
"@signalapp/libsignal-client": "^0.22.0", | ||
"debug": "^4.3.2", | ||
@@ -53,3 +53,4 @@ "long": "^4.0.0", | ||
"uuid": "^8.3.2", | ||
"ws": "^8.4.2" | ||
"ws": "^8.4.2", | ||
"zod": "^3.20.2" | ||
}, | ||
@@ -56,0 +57,0 @@ "devDependencies": { |
@@ -6,7 +6,7 @@ /// <reference types="node" /> | ||
import { Group as GroupData } from '../data/group'; | ||
export declare type GroupOptions = Readonly<{ | ||
export type GroupOptions = Readonly<{ | ||
secretParams: GroupSecretParams; | ||
groupState: Proto.IGroup; | ||
}>; | ||
export declare type GroupMember = Readonly<{ | ||
export type GroupMember = Readonly<{ | ||
presentation: ProfileKeyCredentialPresentation; | ||
@@ -16,3 +16,3 @@ profileKey: ProfileKey; | ||
}>; | ||
export declare type GroupFromConfigOptions = Readonly<{ | ||
export type GroupFromConfigOptions = Readonly<{ | ||
secretParams: GroupSecretParams; | ||
@@ -19,0 +19,0 @@ title: string; |
@@ -13,3 +13,3 @@ /// <reference types="node" /> | ||
import { StorageState } from './storage-state'; | ||
export declare type Config = Readonly<{ | ||
export type Config = Readonly<{ | ||
profileName: string; | ||
@@ -37,3 +37,3 @@ contacts: Proto.IAttachmentPointer; | ||
}>; | ||
export declare type EncryptOptions = Readonly<{ | ||
export type EncryptOptions = Readonly<{ | ||
timestamp?: number; | ||
@@ -44,3 +44,3 @@ sealed?: boolean; | ||
}>; | ||
export declare type EncryptTextOptions = EncryptOptions & Readonly<{ | ||
export type EncryptTextOptions = EncryptOptions & Readonly<{ | ||
group?: Group; | ||
@@ -50,17 +50,17 @@ withProfileKey?: boolean; | ||
}>; | ||
export declare type CreateGroupOptions = Readonly<{ | ||
export type CreateGroupOptions = Readonly<{ | ||
title: string; | ||
members: ReadonlyArray<PrimaryDevice>; | ||
}>; | ||
export declare type InviteToGroupOptions = EncryptOptions & Readonly<{ | ||
export type InviteToGroupOptions = EncryptOptions & Readonly<{ | ||
sendInvite?: boolean; | ||
}>; | ||
export declare type SyncSentOptions = Readonly<{ | ||
export type SyncSentOptions = Readonly<{ | ||
timestamp: number; | ||
destinationUUID: UUID; | ||
}>; | ||
export declare type FetchStorageOptions = Readonly<{ | ||
export type FetchStorageOptions = Readonly<{ | ||
timestamp: number; | ||
}>; | ||
export declare type SendStickerPackSyncOptions = Readonly<{ | ||
export type SendStickerPackSyncOptions = Readonly<{ | ||
type: 'install' | 'remove'; | ||
@@ -71,7 +71,7 @@ packId: Buffer; | ||
}>; | ||
export declare type SyncReadMessage = Readonly<{ | ||
export type SyncReadMessage = Readonly<{ | ||
senderUUID: UUID; | ||
timestamp: number; | ||
}>; | ||
export declare type SyncReadOptions = Readonly<{ | ||
export type SyncReadOptions = Readonly<{ | ||
timestamp?: number; | ||
@@ -84,3 +84,3 @@ messages: ReadonlyArray<SyncReadMessage>; | ||
} | ||
export declare type ReceiptOptions = Readonly<{ | ||
export type ReceiptOptions = Readonly<{ | ||
timestamp?: number; | ||
@@ -90,7 +90,7 @@ type: ReceiptType; | ||
}>; | ||
export declare type UnencryptedReceiptOptions = Readonly<{ | ||
export type UnencryptedReceiptOptions = Readonly<{ | ||
timestamp?: number; | ||
messageTimestamp: number; | ||
}>; | ||
export declare type MessageQueueEntry = Readonly<{ | ||
export type MessageQueueEntry = Readonly<{ | ||
source: Device; | ||
@@ -103,3 +103,3 @@ uuidKind: UUIDKind; | ||
}>; | ||
export declare type StoryQueueEntry = Readonly<{ | ||
export type StoryQueueEntry = Readonly<{ | ||
source: Device; | ||
@@ -111,12 +111,12 @@ uuidKind: UUIDKind; | ||
}>; | ||
export declare type SyncMessageQueueEntry = Readonly<{ | ||
export type SyncMessageQueueEntry = Readonly<{ | ||
source: Device; | ||
syncMessage: Proto.ISyncMessage; | ||
}>; | ||
export declare type PrepareChangeNumberEntry = Readonly<{ | ||
export type PrepareChangeNumberEntry = Readonly<{ | ||
device: Device; | ||
envelope: Buffer; | ||
}>; | ||
export declare type PrepareChangeNumberResult = ReadonlyArray<PrepareChangeNumberEntry>; | ||
export declare type ToContactOptions = Readonly<{ | ||
export type PrepareChangeNumberResult = ReadonlyArray<PrepareChangeNumberEntry>; | ||
export type ToContactOptions = Readonly<{ | ||
includeProfileKey?: boolean; | ||
@@ -123,0 +123,0 @@ }>; |
@@ -6,3 +6,7 @@ "use strict"; | ||
if (k2 === undefined) k2 = k; | ||
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); | ||
var desc = Object.getOwnPropertyDescriptor(m, k); | ||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { | ||
desc = { enumerable: true, get: function() { return m[k]; } }; | ||
} | ||
Object.defineProperty(o, k2, desc); | ||
}) : (function(o, m, k, k2) { | ||
@@ -9,0 +13,0 @@ if (k2 === undefined) k2 = k; |
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
import Long from 'long'; | ||
@@ -11,11 +13,11 @@ import { ServerOptions } from 'https'; | ||
import { PrimaryDevice } from './primary-device'; | ||
declare type TrustRoot = Readonly<{ | ||
type TrustRoot = Readonly<{ | ||
privateKey: string; | ||
publicKey: string; | ||
}>; | ||
declare type ZKParams = Readonly<{ | ||
type ZKParams = Readonly<{ | ||
secretParams: string; | ||
publicParams: string; | ||
}>; | ||
export declare type Config = Readonly<{ | ||
export type Config = Readonly<{ | ||
trustRoot?: TrustRoot; | ||
@@ -27,3 +29,3 @@ zkParams?: ZKParams; | ||
}>; | ||
export declare type CreatePrimaryDeviceOptions = Readonly<{ | ||
export type CreatePrimaryDeviceOptions = Readonly<{ | ||
profileName: string; | ||
@@ -34,10 +36,10 @@ initialPreKeyCount?: number; | ||
}>; | ||
export declare type PendingProvision = { | ||
export type PendingProvision = { | ||
complete(response: PendingProvisionResponse): Promise<Device>; | ||
}; | ||
export declare type PendingProvisionResponse = Readonly<{ | ||
export type PendingProvisionResponse = Readonly<{ | ||
provisionURL: string; | ||
primaryDevice: PrimaryDevice; | ||
}>; | ||
export declare type RateLimitOptions = Readonly<{ | ||
export type RateLimitOptions = Readonly<{ | ||
source: UUID; | ||
@@ -44,0 +46,0 @@ target: UUID; |
@@ -6,3 +6,3 @@ /// <reference types="node" /> | ||
import { PrimaryDevice } from './primary-device'; | ||
export declare type StorageStateRecord = Readonly<{ | ||
export type StorageStateRecord = Readonly<{ | ||
type: Proto.ManifestRecord.Identifier.Type; | ||
@@ -12,3 +12,3 @@ key: Buffer; | ||
}>; | ||
export declare type StorageStateNewRecord = Readonly<{ | ||
export type StorageStateNewRecord = Readonly<{ | ||
type: Proto.ManifestRecord.Identifier.Type; | ||
@@ -18,3 +18,3 @@ key?: Buffer; | ||
}>; | ||
export declare type DiffResult = Readonly<{ | ||
export type DiffResult = Readonly<{ | ||
added: ReadonlyArray<Proto.IStorageRecord>; | ||
@@ -21,0 +21,0 @@ removed: ReadonlyArray<Proto.IStorageRecord>; |
@@ -7,11 +7,11 @@ /// <reference types="node" /> | ||
import { DeviceId, UUID } from './types'; | ||
export declare type EncryptedProvisionMessage = { | ||
export type EncryptedProvisionMessage = { | ||
body: Buffer; | ||
ephemeralKey: Buffer; | ||
}; | ||
export declare type ServerCertificate = { | ||
export type ServerCertificate = { | ||
privateKey: PrivateKey; | ||
certificate: Proto.IServerCertificate; | ||
}; | ||
export declare type Sender = { | ||
export type Sender = { | ||
readonly uuid: UUID; | ||
@@ -18,0 +18,0 @@ readonly number?: string; |
/// <reference types="node" /> | ||
import { signalservice as Proto } from '../../protos/compiled'; | ||
export declare type Attachment = { | ||
export type Attachment = { | ||
key: Buffer; | ||
@@ -5,0 +5,0 @@ blob: Buffer; |
@@ -1,2 +0,2 @@ | ||
export declare type Certificates = Readonly<{ | ||
export type Certificates = Readonly<{ | ||
certificateAuthority: string; | ||
@@ -3,0 +3,0 @@ serverPublicParams: string; |
/// <reference types="node" /> | ||
import { UUID } from '../types'; | ||
export declare type Contact = Readonly<{ | ||
export type Contact = Readonly<{ | ||
uuid: UUID; | ||
@@ -5,0 +5,0 @@ number: string; |
@@ -5,3 +5,3 @@ /// <reference types="node" /> | ||
import { DeviceId, RegistrationId, UUID, UUIDKind } from '../types'; | ||
export declare type DeviceOptions = Readonly<{ | ||
export type DeviceOptions = Readonly<{ | ||
uuid: UUID; | ||
@@ -14,3 +14,3 @@ pni: UUID; | ||
}>; | ||
export declare type ChangeNumberOptions = Readonly<{ | ||
export type ChangeNumberOptions = Readonly<{ | ||
number: string; | ||
@@ -20,3 +20,3 @@ pni: UUID; | ||
}>; | ||
export declare type SignedPreKey = Readonly<{ | ||
export type SignedPreKey = Readonly<{ | ||
keyId: number; | ||
@@ -26,7 +26,7 @@ publicKey: PublicKey; | ||
}>; | ||
export declare type PreKey = Readonly<{ | ||
export type PreKey = Readonly<{ | ||
keyId: number; | ||
publicKey: PublicKey; | ||
}>; | ||
export declare type DeviceKeys = Readonly<{ | ||
export type DeviceKeys = Readonly<{ | ||
identityKey: PublicKey; | ||
@@ -36,3 +36,3 @@ signedPreKey: SignedPreKey; | ||
}>; | ||
export declare type SingleUseKey = Readonly<{ | ||
export type SingleUseKey = Readonly<{ | ||
identityKey: PublicKey; | ||
@@ -39,0 +39,0 @@ signedPreKey: SignedPreKey; |
@@ -9,3 +9,3 @@ /// <reference types="node" /> | ||
import { AttachmentId, DeviceId, ProvisioningCode, RegistrationId, UUID, UUIDKind } from '../types'; | ||
import { JSONMessage } from '../data/json.d'; | ||
import { Message, UsernameConfirmation, UsernameReservation } from '../data/schemas'; | ||
import { ModifyGroupResult, ServerGroup } from './group'; | ||
@@ -18,19 +18,19 @@ export declare enum EnvelopeType { | ||
} | ||
export declare type ProvisioningResponse = Readonly<{ | ||
export type ProvisioningResponse = Readonly<{ | ||
envelope: Buffer; | ||
}>; | ||
export declare type GroupCredentialsRange = Readonly<{ | ||
export type GroupCredentialsRange = Readonly<{ | ||
from: number; | ||
to: number; | ||
}>; | ||
export declare type StorageCredentials = Readonly<{ | ||
export type StorageCredentials = Readonly<{ | ||
username: string; | ||
password: string; | ||
}>; | ||
export declare type GroupCredentials = Array<{ | ||
export type GroupCredentials = Array<{ | ||
credential: string; | ||
redemptionTime: number; | ||
}>; | ||
export declare type PreparedMultiDeviceMessage = ReadonlyArray<[Device, JSONMessage]>; | ||
export declare type ProvisionDeviceOptions = Readonly<{ | ||
export type PreparedMultiDeviceMessage = ReadonlyArray<[Device, Message]>; | ||
export type ProvisionDeviceOptions = Readonly<{ | ||
number: string; | ||
@@ -42,3 +42,3 @@ password: string; | ||
}>; | ||
export declare type RegisterDeviceOptions = Readonly<{ | ||
export type RegisterDeviceOptions = Readonly<{ | ||
uuid: UUID; | ||
@@ -50,3 +50,3 @@ pni: UUID; | ||
}>; | ||
export declare type PrepareMultiDeviceMessageResult = Readonly<{ | ||
export type PrepareMultiDeviceMessageResult = Readonly<{ | ||
status: 'stale'; | ||
@@ -65,3 +65,3 @@ staleDevices: ReadonlyArray<number>; | ||
}>; | ||
export declare type StorageWriteResult = Readonly<{ | ||
export type StorageWriteResult = Readonly<{ | ||
updated: false; | ||
@@ -78,3 +78,3 @@ manifest: Proto.IStorageManifest; | ||
}>; | ||
export declare type ModifyGroupOptions = Readonly<{ | ||
export type ModifyGroupOptions = Readonly<{ | ||
group: ServerGroup; | ||
@@ -85,3 +85,3 @@ actions: Proto.GroupChange.IActions; | ||
}>; | ||
export declare type EncryptedStickerPack = Readonly<{ | ||
export type EncryptedStickerPack = Readonly<{ | ||
id: Buffer; | ||
@@ -91,3 +91,3 @@ manifest: Buffer; | ||
}>; | ||
export declare type IsSendRateLimitedOptions = Readonly<{ | ||
export type IsSendRateLimitedOptions = Readonly<{ | ||
source: UUID; | ||
@@ -103,4 +103,4 @@ target: UUID; | ||
private readonly devicesByUUID; | ||
private readonly devicesByAuth; | ||
private readonly usedUUIDs; | ||
private readonly devicesByAuth; | ||
private readonly storageAuthByUsername; | ||
@@ -116,2 +116,6 @@ private readonly storageAuthByDevice; | ||
private readonly groups; | ||
private readonly uuidByUsername; | ||
private readonly uuidByReservedUsername; | ||
private readonly usernameByUUID; | ||
private readonly reservedUsernameByUUID; | ||
protected privCertificate: ServerCertificate | undefined; | ||
@@ -133,3 +137,3 @@ protected privZKSecret: ServerSecretParams | undefined; | ||
storeStickerPack(pack: EncryptedStickerPack): Promise<void>; | ||
prepareMultiDeviceMessage(source: Device | undefined, targetUUID: UUID, messages: ReadonlyArray<JSONMessage>): Promise<PrepareMultiDeviceMessageResult>; | ||
prepareMultiDeviceMessage(source: Device | undefined, targetUUID: UUID, messages: ReadonlyArray<Message>): Promise<PrepareMultiDeviceMessageResult>; | ||
handlePreparedMultiDeviceMessage(source: Device | undefined, targetUUID: UUID, prepared: PreparedMultiDeviceMessage): Promise<void>; | ||
@@ -153,2 +157,8 @@ abstract handleMessage(source: Device | undefined, uuidKind: UUIDKind, envelopeType: EnvelopeType, target: Device, encrypted: Buffer): Promise<void>; | ||
protected abstract onStorageManifestUpdate(device: Device, version: Long): Promise<void>; | ||
reserveUsername(uuid: UUID, { usernameHashes }: UsernameReservation): Promise<Buffer | undefined>; | ||
confirmUsername(uuid: UUID, { usernameHash, zkProof, }: UsernameConfirmation): Promise<boolean>; | ||
deleteUsername(uuid: UUID): Promise<void>; | ||
lookupByUsernameHash(usernameHash: Buffer): Promise<UUID | undefined>; | ||
lookupByUsername(username: string): Promise<UUID | undefined>; | ||
setUsername(uuid: UUID, username: string): Promise<void>; | ||
getDevice(number: string, deviceId: DeviceId): Promise<Device | undefined>; | ||
@@ -155,0 +165,0 @@ getDeviceByUUID(uuid: UUID, deviceId?: DeviceId): Promise<Device | undefined>; |
@@ -13,2 +13,3 @@ "use strict"; | ||
const debug_1 = __importDefault(require("debug")); | ||
const libsignal_client_1 = require("@signalapp/libsignal-client"); | ||
const zkgroup_1 = require("@signalapp/libsignal-client/zkgroup"); | ||
@@ -35,4 +36,4 @@ const compiled_1 = require("../../protos/compiled"); | ||
this.devicesByUUID = new Map(); | ||
this.devicesByAuth = new Map(); | ||
this.usedUUIDs = new Set(); | ||
this.devicesByAuth = new Map(); | ||
this.storageAuthByUsername = new Map(); | ||
@@ -48,2 +49,6 @@ this.storageAuthByDevice = new Map(); | ||
this.groups = new Map(); | ||
this.uuidByUsername = new Map(); | ||
this.uuidByReservedUsername = new Map(); | ||
this.usernameByUUID = new Map(); | ||
this.reservedUsernameByUUID = new Map(); | ||
} | ||
@@ -469,2 +474,66 @@ // | ||
// | ||
// Usernames | ||
// | ||
async reserveUsername(uuid, { usernameHashes }) { | ||
// Clear previously reserved usernames | ||
const reserved = this.reservedUsernameByUUID.get(uuid); | ||
if (reserved !== undefined) { | ||
this.reservedUsernameByUUID.delete(uuid); | ||
this.uuidByReservedUsername.delete(reserved); | ||
} | ||
for (const hash of usernameHashes) { | ||
const hashHex = hash.toString('hex'); | ||
if (this.uuidByReservedUsername.has(hashHex)) { | ||
continue; | ||
} | ||
if (this.uuidByUsername.has(hashHex)) { | ||
continue; | ||
} | ||
this.reservedUsernameByUUID.set(uuid, hashHex); | ||
this.uuidByReservedUsername.set(hashHex, uuid); | ||
return hash; | ||
} | ||
return undefined; | ||
} | ||
async confirmUsername(uuid, { usernameHash, zkProof, }) { | ||
// Clear previously reserved usernames | ||
const reserved = this.reservedUsernameByUUID.get(uuid); | ||
if (reserved !== usernameHash.toString('hex')) { | ||
return false; | ||
} | ||
try { | ||
libsignal_client_1.usernames.verifyProof(zkProof, usernameHash); | ||
} | ||
catch (error) { | ||
debug('failed to verify username proof of %s: %O', uuid, error); | ||
return false; | ||
} | ||
this.reservedUsernameByUUID.delete(uuid); | ||
this.uuidByReservedUsername.delete(reserved); | ||
this.uuidByUsername.set(reserved, uuid); | ||
this.usernameByUUID.set(uuid, reserved); | ||
return true; | ||
} | ||
async deleteUsername(uuid) { | ||
const hash = this.usernameByUUID.get(uuid); | ||
if (!hash) { | ||
return; | ||
} | ||
this.uuidByUsername.delete(hash); | ||
this.usernameByUUID.delete(uuid); | ||
} | ||
async lookupByUsernameHash(usernameHash) { | ||
return this.uuidByUsername.get(usernameHash.toString('hex')); | ||
} | ||
// For easier testing | ||
async lookupByUsername(username) { | ||
return this.uuidByUsername.get(libsignal_client_1.usernames.hash(username).toString('hex')); | ||
} | ||
// For easier testing | ||
async setUsername(uuid, username) { | ||
const hash = libsignal_client_1.usernames.hash(username).toString('hex'); | ||
this.usernameByUUID.set(uuid, hash); | ||
this.uuidByUsername.set(hash, uuid); | ||
} | ||
// | ||
// Utils | ||
@@ -471,0 +540,0 @@ // |
import { ServerSecretParams, ServerZkProfileOperations, UuidCiphertext } from '@signalapp/libsignal-client/zkgroup'; | ||
import { signalservice as Proto } from '../../protos/compiled'; | ||
import { Group } from '../data/group'; | ||
export declare type ServerGroupOptions = Readonly<{ | ||
export type ServerGroupOptions = Readonly<{ | ||
profileOps: ServerZkProfileOperations; | ||
@@ -9,3 +9,3 @@ zkSecret: ServerSecretParams; | ||
}>; | ||
export declare type ModifyGroupResult = Readonly<{ | ||
export type ModifyGroupResult = Readonly<{ | ||
conflict: false; | ||
@@ -12,0 +12,0 @@ signedChange: Proto.IGroupChange; |
@@ -14,2 +14,3 @@ "use strict"; | ||
const group_1 = require("../data/group"); | ||
const schemas_1 = require("../data/schemas"); | ||
const { AccessRequired } = compiled_1.signalservice.AccessControl; | ||
@@ -20,15 +21,8 @@ const { Role } = compiled_1.signalservice.Member; | ||
super(); | ||
// TODO(indutny): use zod or something | ||
assert_1.default.ok(state.publicKey, 'Group public key must be present'); | ||
assert_1.default.strictEqual(state.version, 0, 'Initial group version must be zero'); | ||
assert_1.default.ok(state.accessControl, 'Group access control must be present'); | ||
assert_1.default.ok(typeof state.accessControl.attributes === 'number' && | ||
typeof state.accessControl.members === 'number' && | ||
typeof state.accessControl.addFromInviteLink === 'number', 'Group access control must be configured'); | ||
assert_1.default.ok(state.members && state.members.length > 0, 'Group members must be present'); | ||
this.privPublicParams = new zkgroup_1.GroupPublicParams(Buffer.from(state.publicKey)); | ||
const parsedState = schemas_1.GroupStateSchema.parse(state); | ||
this.privPublicParams = new zkgroup_1.GroupPublicParams(Buffer.from(parsedState.publicKey)); | ||
this.profileOps = profileOps; | ||
this.zkSecret = zkSecret; | ||
const unrolledState = { ...state }; | ||
unrolledState.members = state.members.map((member) => this.unrollMember(member)); | ||
unrolledState.members = (state.members ?? []).map((member) => this.unrollMember(member)); | ||
this.privChanges = { | ||
@@ -35,0 +29,0 @@ groupChanges: [{ |
@@ -17,2 +17,3 @@ "use strict"; | ||
const util_1 = require("../util"); | ||
const schemas_1 = require("../data/schemas"); | ||
const types_1 = require("../types"); | ||
@@ -60,10 +61,3 @@ const compiled_1 = require("../../protos/compiled"); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const body = await (0, micro_1.json)(req); | ||
if (typeof body.registrationId !== 'number') { | ||
return (0, micro_1.send)(res, 400, { error: 'Invalid registration id' }); | ||
} | ||
if (typeof body.pniRegistrationId !== 'number') { | ||
return (0, micro_1.send)(res, 400, { error: 'Invalid PNI registration id' }); | ||
} | ||
const body = schemas_1.RegistrationDataSchema.parse(await (0, micro_1.json)(req)); | ||
const device = await server.provisionDevice({ | ||
@@ -222,4 +216,3 @@ number: username, | ||
const uuidKind = uuidKindFromQuery(req); | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const body = await (0, micro_1.json)(req); | ||
const body = schemas_1.DeviceKeysSchema.parse(await (0, micro_1.json)(req)); | ||
try { | ||
@@ -266,2 +259,42 @@ const parseKey = (base64) => { | ||
}); | ||
const reserveUsername = (0, microrouter_1.put)('/v1/accounts/username_hash/reserve', async (req, res) => { | ||
const device = await auth(req, res); | ||
if (!device) { | ||
return; | ||
} | ||
const body = schemas_1.UsernameReservationSchema.parse(await (0, micro_1.json)(req)); | ||
const usernameHash = await server.reserveUsername(device.uuid, body); | ||
if (!usernameHash) { | ||
return (0, micro_1.send)(res, 409); | ||
} | ||
return { usernameHash: (0, util_1.toURLSafeBase64)(usernameHash) }; | ||
}); | ||
const confirmUsername = (0, microrouter_1.put)('/v1/accounts/username_hash/confirm', async (req, res) => { | ||
const device = await auth(req, res); | ||
if (!device) { | ||
return; | ||
} | ||
const body = schemas_1.UsernameConfirmationSchema.parse(await (0, micro_1.json)(req)); | ||
const result = await server.confirmUsername(device.uuid, body); | ||
if (!result) { | ||
return (0, micro_1.send)(res, 409); | ||
} | ||
return (0, micro_1.send)(res, 200); | ||
}); | ||
const deleteUsername = (0, microrouter_1.del)('/v1/accounts/username_hash', async (req, res) => { | ||
const device = await auth(req, res); | ||
if (!device) { | ||
return; | ||
} | ||
await server.deleteUsername(device.uuid); | ||
return (0, micro_1.send)(res, 204); | ||
}); | ||
const lookupByUsernameHash = (0, microrouter_1.get)('/v1/accounts/username_hash/:hash', async (req, res) => { | ||
const { hash = '' } = req.params; | ||
const uuid = await server.lookupByUsernameHash((0, util_1.fromURLSafeBase64)(hash)); | ||
if (!uuid) { | ||
return (0, micro_1.send)(res, 404); | ||
} | ||
return { uuid }; | ||
}); | ||
const putChallenge = (0, microrouter_1.put)('/v1/challenge', async (req, res) => { | ||
@@ -437,3 +470,3 @@ const device = await auth(req, res); | ||
// TODO(indutny): support nameless devices? They use different route | ||
provisionDevice, getDeviceKeys, getAllDeviceKeys, getAttachment, getStickerPack, getSticker, putKeys, getKeys, whoami, putChallenge, | ||
provisionDevice, getDeviceKeys, getAllDeviceKeys, getAttachment, getStickerPack, getSticker, putKeys, getKeys, whoami, reserveUsername, confirmUsername, deleteUsername, lookupByUsernameHash, putChallenge, | ||
// Technically these should live on a separate server, but who cares | ||
@@ -440,0 +473,0 @@ getGroup, getGroupVersion, getGroupLogs, createGroup, modifyGroup, getStorageManifest, getStorageManifestByVersion, putStorage, putStorageRead, |
/// <reference types="node" /> | ||
/// <reference types="node" /> | ||
import { Buffer } from 'buffer'; | ||
@@ -3,0 +4,0 @@ import { IncomingMessage } from 'http'; |
@@ -16,2 +16,3 @@ "use strict"; | ||
const compiled_1 = require("../../../protos/compiled"); | ||
const schemas_1 = require("../../data/schemas"); | ||
const crypto_2 = require("../../crypto"); | ||
@@ -93,2 +94,3 @@ const util_1 = require("../../util"); | ||
{ name: 'desktop.pnp', enabled: true }, | ||
{ name: 'desktop.usernames', enabled: true }, | ||
{ | ||
@@ -175,3 +177,3 @@ name: 'global.groupsv2.maxGroupSize', | ||
} | ||
const { messages } = JSON.parse(buffer_1.Buffer.from(body).toString()); | ||
const { messages } = schemas_1.MessageListSchema.parse(JSON.parse(buffer_1.Buffer.from(body).toString())); | ||
const targetUUID = params.uuid; | ||
@@ -242,7 +244,3 @@ const target = await this.server.getDeviceByUUID(targetUUID); | ||
} | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
const json = JSON.parse(buffer_1.Buffer.from(body).toString()); | ||
if (typeof json.registrationId !== 'number') { | ||
return [400, { error: 'Invalid registration id' }]; | ||
} | ||
const { registrationId, pniRegistrationId, } = schemas_1.RegistrationDataSchema.parse(JSON.parse(buffer_1.Buffer.from(body).toString())); | ||
const device = await server.provisionDevice({ | ||
@@ -252,4 +250,4 @@ number: username, | ||
provisioningCode: params.code, | ||
registrationId: json.registrationId, | ||
pniRegistrationId: json.pniRegistrationId, | ||
registrationId, | ||
pniRegistrationId, | ||
}); | ||
@@ -256,0 +254,0 @@ return [200, { |
/// <reference types="node" /> | ||
import { ParsedUrlQuery } from 'querystring'; | ||
import { WSRequest, WSResponse } from './service'; | ||
export declare type AbbreviatedResponse = Readonly<[ | ||
export type AbbreviatedResponse = Readonly<[ | ||
number, | ||
unknown | ||
]>; | ||
export declare type Handler = (params: any, body: Uint8Array | undefined, headers: Record<string, string>, query?: ParsedUrlQuery) => Promise<AbbreviatedResponse>; | ||
export type Handler = (params: any, body: Uint8Array | undefined, headers: Record<string, string>, query?: ParsedUrlQuery) => Promise<AbbreviatedResponse>; | ||
export declare class Router { | ||
@@ -10,0 +10,0 @@ private readonly routes; |
import WebSocket from 'ws'; | ||
import { signalservice as SignalService } from '../../../protos/compiled'; | ||
export declare type WSRequest = SignalService.IWebSocketRequestMessage; | ||
export declare type WSResponse = SignalService.IWebSocketResponseMessage; | ||
export type WSRequest = SignalService.IWebSocketRequestMessage; | ||
export type WSResponse = SignalService.IWebSocketResponseMessage; | ||
interface RequestOptions { | ||
@@ -6,0 +6,0 @@ readonly body?: Uint8Array; |
@@ -1,6 +0,6 @@ | ||
export declare type UUID = string; | ||
export declare type ProvisioningCode = string; | ||
export declare type RegistrationId = number; | ||
export declare type DeviceId = number; | ||
export declare type AttachmentId = string; | ||
export type UUID = string; | ||
export type ProvisioningCode = string; | ||
export type RegistrationId = number; | ||
export type DeviceId = number; | ||
export type AttachmentId = string; | ||
export declare enum UUIDKind { | ||
@@ -7,0 +7,0 @@ ACI = "ACI", |
/// <reference types="node" /> | ||
import { ProtocolAddress } from '@signalapp/libsignal-client'; | ||
import type { RegistrationId } from './types'; | ||
export declare type PromiseQueueConfig = Readonly<{ | ||
export type PromiseQueueConfig = Readonly<{ | ||
timeout?: number; | ||
}>; | ||
export declare type MultiRecipientMessageRecipient = Readonly<{ | ||
export type MultiRecipientMessageRecipient = Readonly<{ | ||
uuid: string; | ||
@@ -13,3 +13,3 @@ deviceId: number; | ||
}>; | ||
export declare type MultiRecipientMessage = Readonly<{ | ||
export type MultiRecipientMessage = Readonly<{ | ||
recipients: ReadonlyArray<MultiRecipientMessageRecipient>; | ||
@@ -19,3 +19,3 @@ commonMaterial: Buffer; | ||
export declare function generateRandomE164(): string; | ||
export declare type ParseAuthHeaderResult = { | ||
export type ParseAuthHeaderResult = { | ||
username: string; | ||
@@ -47,1 +47,3 @@ password: string; | ||
export declare function generateRegistrationId(): RegistrationId; | ||
export declare function toURLSafeBase64(buf: Uint8Array): string; | ||
export declare function fromURLSafeBase64(base64: string): Buffer; |
@@ -8,3 +8,3 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.generateRegistrationId = exports.getTodayInSeconds = exports.combineMultiRecipientMessage = exports.parseMultiRecipientMessage = exports.addressToString = exports.PromiseQueue = exports.parseAuthHeader = exports.generateRandomE164 = void 0; | ||
exports.fromURLSafeBase64 = exports.toURLSafeBase64 = exports.generateRegistrationId = exports.getTodayInSeconds = exports.combineMultiRecipientMessage = exports.parseMultiRecipientMessage = exports.addressToString = exports.PromiseQueue = exports.parseAuthHeader = exports.generateRandomE164 = void 0; | ||
const assert_1 = __importDefault(require("assert")); | ||
@@ -180,1 +180,16 @@ const protobufjs_1 = require("protobufjs"); | ||
exports.generateRegistrationId = generateRegistrationId; | ||
function toURLSafeBase64(buf) { | ||
return Buffer.from(buf) | ||
.toString('base64') | ||
.replace(/\+/g, '-') | ||
.replace(/\//g, '_') | ||
.replace(/=+$/g, ''); | ||
} | ||
exports.toURLSafeBase64 = toURLSafeBase64; | ||
function fromURLSafeBase64(base64) { | ||
const source = base64.replace(/-/g, '+').replace(/_/g, '/'); | ||
// Note that `Buffer.from()` ignores padding anyway so we don't need to | ||
// restore it. | ||
return Buffer.from(source, 'base64'); | ||
} | ||
exports.fromURLSafeBase64 = fromURLSafeBase64; |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
64
3223412
11
59335
1
+ Addedzod@^3.20.2
+ Added@signalapp/libsignal-client@0.22.2(transitive)
+ Addedzod@3.24.1(transitive)
- Removed@signalapp/libsignal-client@0.20.0(transitive)