{"size": 4677, "ext": "js", "max_stars_repo_path": "auth/index.js", "max_stars_repo_name": "openlawteam/scuttlebutt-akka-persistence-index", "max_stars_repo_stars_event_min_datetime": null, "max_stars_repo_stars_event_max_datetime": null, "max_issues_repo_path": "auth/index.js", "max_issues_repo_name": "openlawteam/scuttlebutt-akka-persistence-index", "max_issues_repo_issues_event_min_datetime": "2020-07-17T07:54:10.000Z", "max_issues_repo_issues_event_max_datetime": "2021-05-09T05:10:30.000Z", "max_forks_repo_path": "auth/index.js", "max_forks_repo_name": "openlawteam/scuttlebutt-akka-persistence-index", "max_forks_repo_forks_event_min_datetime": "2020-10-08T19:41:15.000Z", "max_forks_repo_forks_event_max_datetime": "2020-10-08T19:41:15.000Z"}
{"max_stars_count": null, "max_issues_count": 2, "max_forks_count": 1, "avg_line_length": 34.1386861314, "max_line_length": 139, "alphanum_fraction": 0.5937566816}
const ssbKeys = require('ssb-keys');
const KeysIndex = require('./keyIndex');
const AccessIndex = require('./accessIndex');
const constants = require('./constants');
const R = require('ramda');

const promisify = require('bluebird').promisify;

module.exports = (sbot, config) => {

    const maxUsersPrivateMessagesAtOnce = 7;

    const myKey = '@' + config.keys.public;

    const keysIndex = KeysIndex(sbot, myKey);
    const accessIndex = AccessIndex(sbot, myKey);

    const publishPrivate = promisify(sbot.private.publish);

    function sendKeys(userIds, persistenceId, keys) {

        const content = {
            "type": constants.updateKeyMessageType,
            "persistenceId": persistenceId,
            "keys": keys
        }

        return publishPrivate(content, userIds);
    }

    function sendKeysToUsers(users, persistenceId, sequenceNr, newKeys) {
        // TODO: What if we crash before we've sent the new key to all the users who have been given
        // access?

        // If we're not already in the access list, we add ourselves - otherwise the entity wouldn't be
        // visible to us
        if (!users.includes(myKey)) {
            users.push(myKey);
        }

        const keys = [{
            key: newKeys,
            startSequenceNr: sequenceNr
        }];

        const chunks = R.splitEvery(maxUsersPrivateMessagesAtOnce, users);

        const sendResults = chunks.map(usersChunk => sendKeys(usersChunk, persistenceId, keys));
        return Promise.all(sendResults);
    }

    return {

        /**
         * Track that we've removed a user to the list of people who can access the given persistence ID
         * by sending ourselves the note as a private message.         */
        trackAddUser: (persistenceId, userId) => {
            const grantAccessContent = {
                "type": constants.grantAccessMessageType,
                "persistenceId": persistenceId,
                "userId": userId
            };

            return publishPrivate(grantAccessContent, [myKey]);
        },

        /**
         * Track that we've removed a user to the list of people who can access the given persistence ID
         * by sending ourselves the note as a private message.
         */
        trackRemoveUser: (persistenceId, userId) => {
            const revokeAccessContent = {
                "type": constants.revokeAccessMessageType,
                "persistenceId": persistenceId,
                "userId": userId
            };

            return publishPrivate(revokeAccessContent, [myKey]);
        },

        /**
         * Shares the updated access key to the list of users who are indexed to be granted access to
         * the given persistence ID. Note: the access list always contains ourselves.
         */
        sendUpdatedKey: (persistenceId, sequenceNr, newKeys) => {
            return accessIndex.usersWhoHaveAccessTo(persistenceId).then(results => {
                return sendKeysToUsers(results, persistenceId, sequenceNr, newKeys);
            });
        },
        /**
         * Send the current keys for the given persistence ID to the specified user only.
         */
        sendKeys: (userId, persistenceId) => {
            const currentKeysPromise = keysIndex.getAllKeysFor(persistenceId, myKey);

            return currentKeysPromise.then(currentKeys => {

                // We don't want to exceed the maximum message size so we send only a few at once
                // TODO: calculate exactly how many we can send at once
                const groupedKeys = R.splitEvery(4, currentKeys);

                // We add our own key so that we can keep track of who we've sent a key to
                const results = groupedKeys.map(keys => sendKeys([userId, myKey], persistenceId, keys));

                return Promise.all(results);
            })

        },

        /**
         * Gets the keys for a given persistence ID that the current user has access to. This is a list of sequence numbers and key pairs, 
         * and the range that the key applies to. e.g.
         * 
         *  [{
         *  startSequenceNr: 0,
         *  key: {}
         * }]
         */
        getAllKeysFor: (persistenceId, authorId) => {
            return keysIndex.getAllKeysFor(persistenceId, authorId);
        },

        /**
         * Get the most up to date key for the given persistence ID.
         */
        getMyCurrentKeyFor: (persistenceId) => {
            return keysIndex.getMyCurrentKeyFor(persistenceId);
        },

        usersWeHaveGivenAccessTo: (persistenceId) => {
            return accessIndex.usersWhoHaveAccessTo(persistenceId);
        }

    }


}