Some checks failed
build-and-deploy / build-and-deploy (push) Has been cancelled
137 lines
4.2 KiB
TypeScript
137 lines
4.2 KiB
TypeScript
/**
|
|
* PostgreSQL-based auth state for Baileys
|
|
* Stores credentials and keys in the database instead of files
|
|
*/
|
|
import type { AuthenticationCreds, SignalDataTypeMap } from '@whiskeysockets/baileys'
|
|
import * as baileys from '@whiskeysockets/baileys'
|
|
import { query } from '../../utils/database'
|
|
|
|
// Get functions from baileys module
|
|
const initAuthCreds = (baileys as any).initAuthCreds || (baileys as any).default?.initAuthCreds
|
|
const BufferJSON = (baileys as any).BufferJSON || (baileys as any).default?.BufferJSON
|
|
const proto = (baileys as any).proto || (baileys as any).default?.proto
|
|
|
|
export interface PostgresAuthState {
|
|
state: {
|
|
creds: AuthenticationCreds
|
|
keys: {
|
|
get: <T extends keyof SignalDataTypeMap>(type: T, ids: string[]) => Promise<{ [id: string]: SignalDataTypeMap[T] }>
|
|
set: (data: { [type: string]: { [id: string]: SignalDataTypeMap[keyof SignalDataTypeMap] | null } }) => Promise<void>
|
|
}
|
|
}
|
|
saveCreds: () => Promise<void>
|
|
}
|
|
|
|
export async function usePostgresAuthState(instanceId: string): Promise<PostgresAuthState> {
|
|
// Load or create credentials
|
|
const loadCreds = async (): Promise<AuthenticationCreds> => {
|
|
const result = await query<{ key_data: any }>(
|
|
'SELECT key_data FROM auth_keys WHERE instance_id = $1 AND key_type = $2 AND key_id = $3',
|
|
[instanceId, 'creds', 'default']
|
|
)
|
|
|
|
if (result.rows.length > 0 && result.rows[0].key_data) {
|
|
return JSON.parse(JSON.stringify(result.rows[0].key_data), BufferJSON.reviver)
|
|
}
|
|
|
|
return initAuthCreds()
|
|
}
|
|
|
|
// Save credentials
|
|
const saveCreds = async (creds: AuthenticationCreds): Promise<void> => {
|
|
const data = JSON.parse(JSON.stringify(creds, BufferJSON.replacer))
|
|
await query(
|
|
`INSERT INTO auth_keys (instance_id, key_type, key_id, key_data)
|
|
VALUES ($1, $2, $3, $4)
|
|
ON CONFLICT (instance_id, key_type, key_id)
|
|
DO UPDATE SET key_data = $4, updated_at = NOW()`,
|
|
[instanceId, 'creds', 'default', data]
|
|
)
|
|
}
|
|
|
|
// Load keys by type and ids
|
|
const loadKeys = async <T extends keyof SignalDataTypeMap>(
|
|
type: T,
|
|
ids: string[]
|
|
): Promise<{ [id: string]: SignalDataTypeMap[T] }> => {
|
|
const result: { [id: string]: SignalDataTypeMap[T] } = {}
|
|
|
|
if (ids.length === 0) return result
|
|
|
|
const placeholders = ids.map((_, i) => `$${i + 3}`).join(', ')
|
|
const queryResult = await query<{ key_id: string; key_data: any }>(
|
|
`SELECT key_id, key_data FROM auth_keys
|
|
WHERE instance_id = $1 AND key_type = $2 AND key_id IN (${placeholders})`,
|
|
[instanceId, type, ...ids]
|
|
)
|
|
|
|
for (const row of queryResult.rows) {
|
|
let value = JSON.parse(JSON.stringify(row.key_data), BufferJSON.reviver)
|
|
|
|
// Handle special types
|
|
if (type === 'app-state-sync-key' && value) {
|
|
value = proto.Message.AppStateSyncKeyData.fromObject(value)
|
|
}
|
|
|
|
result[row.key_id] = value
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// Save keys
|
|
const saveKeys = async (
|
|
data: { [type: string]: { [id: string]: SignalDataTypeMap[keyof SignalDataTypeMap] | null } }
|
|
): Promise<void> => {
|
|
for (const type in data) {
|
|
for (const id in data[type]) {
|
|
const value = data[type][id]
|
|
|
|
if (value === null) {
|
|
// Delete key
|
|
await query(
|
|
'DELETE FROM auth_keys WHERE instance_id = $1 AND key_type = $2 AND key_id = $3',
|
|
[instanceId, type, id]
|
|
)
|
|
} else {
|
|
// Upsert key
|
|
const serialized = JSON.parse(JSON.stringify(value, BufferJSON.replacer))
|
|
await query(
|
|
`INSERT INTO auth_keys (instance_id, key_type, key_id, key_data)
|
|
VALUES ($1, $2, $3, $4)
|
|
ON CONFLICT (instance_id, key_type, key_id)
|
|
DO UPDATE SET key_data = $4, updated_at = NOW()`,
|
|
[instanceId, type, id, serialized]
|
|
)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load initial credentials
|
|
const creds = await loadCreds()
|
|
|
|
return {
|
|
state: {
|
|
creds,
|
|
keys: {
|
|
get: loadKeys,
|
|
set: saveKeys
|
|
}
|
|
},
|
|
saveCreds: async () => {
|
|
await saveCreds(creds)
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear all auth data for an instance
|
|
*/
|
|
export async function clearAuthState(instanceId: string): Promise<void> {
|
|
await query(
|
|
'DELETE FROM auth_keys WHERE instance_id = $1',
|
|
[instanceId]
|
|
)
|
|
}
|