diff --git a/package.json b/package.json index fe12b75..8dd34ec 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "dependencies": { "@hapi/boom": "^9.1.3", "axios": "^1.3.3", + "cache-manager": "^5.2.2", "futoin-hkdf": "^1.5.1", "libphonenumber-js": "^1.10.20", "libsignal": "https://github.com/adiwajshing/libsignal-node.git", diff --git a/src/Store/index.ts b/src/Store/index.ts index f744671..74be5a3 100644 --- a/src/Store/index.ts +++ b/src/Store/index.ts @@ -1,2 +1,3 @@ +import makeCacheManagerAuthState from './make-cache-manager-store' import makeInMemoryStore from './make-in-memory-store' -export { makeInMemoryStore } \ No newline at end of file +export { makeInMemoryStore, makeCacheManagerAuthState } \ No newline at end of file diff --git a/src/Store/make-cache-manager-store.ts b/src/Store/make-cache-manager-store.ts new file mode 100644 index 0000000..f870080 --- /dev/null +++ b/src/Store/make-cache-manager-store.ts @@ -0,0 +1,100 @@ +import { caching, Store } from 'cache-manager' +import { proto } from '../../WAProto' +import { AuthenticationCreds } from '../Types' +import { BufferJSON, initAuthCreds } from '../Utils' +import logger from '../Utils/logger' + +const makeCacheManagerAuthState = async(store: Store, sessionKey: string) => { + const defaultKey = (file: string): string => `${sessionKey}:${file}` + + const databaseConn = await caching(store) + + const writeData = async(file: string, data: object) => { + let ttl: number | undefined = undefined + if(file === 'creds') { + ttl = 63115200 // 2 years + } + + await databaseConn.set( + defaultKey(file), + JSON.stringify(data, BufferJSON.replacer), + ttl + ) + } + + const readData = async(file: string): Promise => { + try { + const data = await databaseConn.get(defaultKey(file)) + + if(data) { + return JSON.parse(data as string, BufferJSON.reviver) + } + + return null + } catch(error) { + logger.error(error) + return null + } + } + + const removeData = async(file: string) => { + try { + return await databaseConn.del(defaultKey(file)) + } catch{ + logger.error(`Error removing ${file} from session ${sessionKey}`) + } + } + + const clearState = async() => { + try { + const result = await databaseConn.store.keys(`${sessionKey}*`) + await Promise.all( + result.map(async(key) => await databaseConn.del(key)) + ) + } catch(err) { + } + } + + const creds: AuthenticationCreds = (await readData('creds')) || initAuthCreds() + + return { + clearState, + saveCreds: () => writeData('creds', creds), + state: { + creds, + keys: { + get: async(type: string, ids: string[]) => { + const data = {} + await Promise.all( + ids.map(async(id) => { + let value: proto.Message.AppStateSyncKeyData | AuthenticationCreds | null = + await readData(`${type}-${id}`) + if(type === 'app-state-sync-key' && value) { + value = proto.Message.AppStateSyncKeyData.fromObject(value) + } + + data[id] = value + }) + ) + + return data + }, + set: async(data) => { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const tasks: Promise[] = [] + for(const category in data) { + for(const id in data[category]) { + const value = data[category][id] + const key = `${category}-${id}` + tasks.push(value ? writeData(key, value) : removeData(key)) + } + } + + await Promise.all(tasks) + }, + } + } + } +} + +export default makeCacheManagerAuthState \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 1bedd46..fe4498b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1913,6 +1913,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +cache-manager@^5.2.2: + version "5.2.2" + resolved "https://registry.yarnpkg.com/cache-manager/-/cache-manager-5.2.2.tgz#1f2e3328247a3c5c63b722cadab6e084b924d320" + integrity sha512-QYEct/rVt5HfNvyWpHQurOa1IgpjP9V0X3E5O8rdEmuKcucpnMs7CwK0bHvv92svxZXlN2w5hgMFdrbiYoHeIQ== + dependencies: + lodash.clonedeep "^4.5.0" + lru-cache "~9.1.1" + cacheable-lookup@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz#3476a8215d046e5a3202a9209dd13fec1f933a27" @@ -4893,6 +4901,11 @@ lodash.capitalize@^4.2.1: resolved "https://registry.yarnpkg.com/lodash.capitalize/-/lodash.capitalize-4.2.1.tgz#f826c9b4e2a8511d84e3aca29db05e1a4f3b72a9" integrity sha512-kZzYOKspf8XVX5AvmQF94gQW0lejFVgb80G85bU4ZWzoJ6C03PQg3coYAUpSTpQWelrZELd3XWgHzw4Ck5kaIw== +lodash.clonedeep@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + integrity sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ== + lodash.escaperegexp@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.escaperegexp/-/lodash.escaperegexp-4.1.2.tgz#64762c48618082518ac3df4ccf5d5886dae20347" @@ -4972,6 +4985,11 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" +lru-cache@~9.1.1: + version "9.1.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-9.1.2.tgz#255fdbc14b75589d6d0e73644ca167a8db506835" + integrity sha512-ERJq3FOzJTxBbFjZ7iDs+NiK4VI9Wz+RdrrAB8dio1oV+YvdPzUEE4QNiT2VD51DkIbCYRUUzCRkssXCHqSnKQ== + lunr@^2.3.9: version "2.3.9" resolved "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz"