mirror of
https://github.com/FranP-code/Baileys.git
synced 2025-10-13 00:32:22 +00:00
* refactor: migrate WASignalGroup to TypeScript and remove deprecated files * chore: remove WASignalGroup JavaScript files from package.json * refactor: update SenderKeyStore and SenderKeyStateStructure interfaces to export and add deserialize method. Fix types * chore: lint issue * refactor: improve constructor type checking and getSeed method in SenderChainKey * refactor: update key handling to use Buffer for improved consistency * signal: consistent naming and dir structure + add some missing types * fix: lint issues --------- Co-authored-by: Rajeh Taher <rajeh@reforward.dev>
162 lines
5.3 KiB
TypeScript
162 lines
5.3 KiB
TypeScript
import * as libsignal from 'libsignal'
|
|
import { SignalAuthState } from '../Types'
|
|
import { SignalRepository } from '../Types/Signal'
|
|
import { generateSignalPubKey } from '../Utils'
|
|
import { jidDecode } from '../WABinary'
|
|
import type { SenderKeyStore } from './Group/group_cipher'
|
|
import { SenderKeyName } from './Group/sender-key-name'
|
|
import { SenderKeyRecord } from './Group/sender-key-record'
|
|
import { GroupCipher, GroupSessionBuilder, SenderKeyDistributionMessage } from './Group'
|
|
|
|
export function makeLibSignalRepository(auth: SignalAuthState): SignalRepository {
|
|
const storage: SenderKeyStore = signalStorage(auth)
|
|
return {
|
|
decryptGroupMessage({ group, authorJid, msg }) {
|
|
const senderName = jidToSignalSenderKeyName(group, authorJid)
|
|
const cipher = new GroupCipher(storage, senderName)
|
|
|
|
return cipher.decrypt(msg)
|
|
},
|
|
async processSenderKeyDistributionMessage({ item, authorJid }) {
|
|
const builder = new GroupSessionBuilder(storage)
|
|
if (!item.groupId) {
|
|
throw new Error('Group ID is required for sender key distribution message')
|
|
}
|
|
|
|
const senderName = jidToSignalSenderKeyName(item.groupId, authorJid)
|
|
|
|
const senderMsg = new SenderKeyDistributionMessage(
|
|
null,
|
|
null,
|
|
null,
|
|
null,
|
|
item.axolotlSenderKeyDistributionMessage
|
|
)
|
|
const senderNameStr = senderName.toString()
|
|
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
|
|
if (!senderKey) {
|
|
await storage.storeSenderKey(senderName, new SenderKeyRecord())
|
|
}
|
|
|
|
await builder.process(senderName, senderMsg)
|
|
},
|
|
async decryptMessage({ jid, type, ciphertext }) {
|
|
const addr = jidToSignalProtocolAddress(jid)
|
|
const session = new libsignal.SessionCipher(storage, addr)
|
|
let result: Buffer
|
|
switch (type) {
|
|
case 'pkmsg':
|
|
result = await session.decryptPreKeyWhisperMessage(ciphertext)
|
|
break
|
|
case 'msg':
|
|
result = await session.decryptWhisperMessage(ciphertext)
|
|
break
|
|
default:
|
|
throw new Error(`Unknown message type: ${type}`)
|
|
}
|
|
|
|
return result
|
|
},
|
|
async encryptMessage({ jid, data }) {
|
|
const addr = jidToSignalProtocolAddress(jid)
|
|
const cipher = new libsignal.SessionCipher(storage, addr)
|
|
|
|
const { type: sigType, body } = await cipher.encrypt(data)
|
|
const type = sigType === 3 ? 'pkmsg' : 'msg'
|
|
return { type, ciphertext: Buffer.from(body, 'binary') }
|
|
},
|
|
async encryptGroupMessage({ group, meId, data }) {
|
|
const senderName = jidToSignalSenderKeyName(group, meId)
|
|
const builder = new GroupSessionBuilder(storage)
|
|
|
|
const senderNameStr = senderName.toString()
|
|
const { [senderNameStr]: senderKey } = await auth.keys.get('sender-key', [senderNameStr])
|
|
if (!senderKey) {
|
|
await storage.storeSenderKey(senderName, new SenderKeyRecord())
|
|
}
|
|
|
|
const senderKeyDistributionMessage = await builder.create(senderName)
|
|
const session = new GroupCipher(storage, senderName)
|
|
const ciphertext = await session.encrypt(data)
|
|
|
|
return {
|
|
ciphertext,
|
|
senderKeyDistributionMessage: senderKeyDistributionMessage.serialize()
|
|
}
|
|
},
|
|
async injectE2ESession({ jid, session }) {
|
|
const cipher = new libsignal.SessionBuilder(storage, jidToSignalProtocolAddress(jid))
|
|
await cipher.initOutgoing(session)
|
|
},
|
|
jidToSignalProtocolAddress(jid) {
|
|
return jidToSignalProtocolAddress(jid).toString()
|
|
}
|
|
}
|
|
}
|
|
|
|
const jidToSignalProtocolAddress = (jid: string) => {
|
|
const { user, device } = jidDecode(jid)!
|
|
return new libsignal.ProtocolAddress(user, device || 0)
|
|
}
|
|
|
|
const jidToSignalSenderKeyName = (group: string, user: string): SenderKeyName => {
|
|
return new SenderKeyName(group, jidToSignalProtocolAddress(user))
|
|
}
|
|
|
|
function signalStorage({ creds, keys }: SignalAuthState): SenderKeyStore & Record<string, any> {
|
|
return {
|
|
loadSession: async (id: string) => {
|
|
const { [id]: sess } = await keys.get('session', [id])
|
|
if (sess) {
|
|
return libsignal.SessionRecord.deserialize(sess)
|
|
}
|
|
},
|
|
storeSession: async (id: string, session: libsignal.SessionRecord) => {
|
|
await keys.set({ session: { [id]: session.serialize() } })
|
|
},
|
|
isTrustedIdentity: () => {
|
|
return true
|
|
},
|
|
loadPreKey: async (id: number | string) => {
|
|
const keyId = id.toString()
|
|
const { [keyId]: key } = await keys.get('pre-key', [keyId])
|
|
if (key) {
|
|
return {
|
|
privKey: Buffer.from(key.private),
|
|
pubKey: Buffer.from(key.public)
|
|
}
|
|
}
|
|
},
|
|
removePreKey: (id: number) => keys.set({ 'pre-key': { [id]: null } }),
|
|
loadSignedPreKey: () => {
|
|
const key = creds.signedPreKey
|
|
return {
|
|
privKey: Buffer.from(key.keyPair.private),
|
|
pubKey: Buffer.from(key.keyPair.public)
|
|
}
|
|
},
|
|
loadSenderKey: async (senderKeyName: SenderKeyName) => {
|
|
const keyId = senderKeyName.toString()
|
|
const { [keyId]: key } = await keys.get('sender-key', [keyId])
|
|
if (key) {
|
|
return SenderKeyRecord.deserialize(key)
|
|
}
|
|
|
|
return new SenderKeyRecord()
|
|
},
|
|
storeSenderKey: async (senderKeyName: SenderKeyName, key: SenderKeyRecord) => {
|
|
const keyId = senderKeyName.toString()
|
|
const serialized = JSON.stringify(key.serialize())
|
|
await keys.set({ 'sender-key': { [keyId]: Buffer.from(serialized, 'utf-8') } })
|
|
},
|
|
getOurRegistrationId: () => creds.registrationId,
|
|
getOurIdentity: () => {
|
|
const { signedIdentityKey } = creds
|
|
return {
|
|
privKey: Buffer.from(signedIdentityKey.private),
|
|
pubKey: generateSignalPubKey(signedIdentityKey.public)
|
|
}
|
|
}
|
|
}
|
|
}
|