File size: 4,608 Bytes
f0743f4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
const { logger } = require('@librechat/data-schemas');
const { encrypt, decrypt } = require('@librechat/api');
const { findOnePluginAuth, updatePluginAuth, deletePluginAuth } = require('~/models');

/**
 * Asynchronously retrieves and decrypts the authentication value for a user's plugin, based on a specified authentication field.
 *
 * @param {string} userId - The unique identifier of the user for whom the plugin authentication value is to be retrieved.
 * @param {string} authField - The specific authentication field (e.g., 'API_KEY', 'URL') whose value is to be retrieved and decrypted.
 * @param {boolean} throwError - Whether to throw an error if the authentication value does not exist. Defaults to `true`.
 * @param {string} [pluginKey] - Optional plugin key to make the lookup more specific to a particular plugin.
 * @returns {Promise<string|null>} A promise that resolves to the decrypted authentication value if found, or `null` if no such authentication value exists for the given user and field.
 *
 * The function throws an error if it encounters any issue during the retrieval or decryption process, or if the authentication value does not exist.
 *
 * @example
 * // To get the decrypted value of the 'token' field for a user with userId '12345':
 * getUserPluginAuthValue('12345', 'token').then(value => {
 *   console.log(value);
 * }).catch(err => {
 *   console.error(err);
 * });
 *
 * @example
 * // To get the decrypted value of the 'API_KEY' field for a specific plugin:
 * getUserPluginAuthValue('12345', 'API_KEY', true, 'mcp-server-name').then(value => {
 *   console.log(value);
 * }).catch(err => {
 *   console.error(err);
 * });
 *
 * @throws {Error} Throws an error if there's an issue during the retrieval or decryption process, or if the authentication value does not exist.
 * @async
 */
const getUserPluginAuthValue = async (userId, authField, throwError = true, pluginKey) => {
  try {
    const searchParams = { userId, authField };
    if (pluginKey) {
      searchParams.pluginKey = pluginKey;
    }

    const pluginAuth = await findOnePluginAuth(searchParams);
    if (!pluginAuth) {
      const pluginInfo = pluginKey ? ` for plugin ${pluginKey}` : '';
      throw new Error(`No plugin auth ${authField} found for user ${userId}${pluginInfo}`);
    }

    const decryptedValue = await decrypt(pluginAuth.value);
    return decryptedValue;
  } catch (err) {
    if (!throwError) {
      return null;
    }
    logger.error('[getUserPluginAuthValue]', err);
    throw err;
  }
};

// const updateUserPluginAuth = async (userId, authField, pluginKey, value) => {
//   try {
//     const encryptedValue = encrypt(value);

//     const pluginAuth = await PluginAuth.findOneAndUpdate(
//       { userId, authField },
//       {
//         $set: {
//           value: encryptedValue,
//           pluginKey
//         }
//       },
//       {
//         new: true,
//         upsert: true
//       }
//     );

//     return pluginAuth;
//   } catch (err) {
//     logger.error('[getUserPluginAuthValue]', err);
//     return err;
//   }
// };

/**
 *
 * @async
 * @param {string} userId
 * @param {string} authField
 * @param {string} pluginKey
 * @param {string} value
 * @returns {Promise<IPluginAuth>}
 * @throws {Error}
 */
const updateUserPluginAuth = async (userId, authField, pluginKey, value) => {
  try {
    const encryptedValue = await encrypt(value);
    return await updatePluginAuth({
      userId,
      authField,
      pluginKey,
      value: encryptedValue,
    });
  } catch (err) {
    logger.error('[updateUserPluginAuth]', err);
    return err;
  }
};

/**
 * @async
 * @param {string} userId
 * @param {string | null} authField - The specific authField to delete, or null if `all` is true.
 * @param {boolean} [all=false] - Whether to delete all auths for the user (or for a specific pluginKey if provided).
 * @param {string} [pluginKey] - Optional. If `all` is true and `pluginKey` is provided, delete all auths for this user and pluginKey.
 * @returns {Promise<import('mongoose').DeleteResult>}
 * @throws {Error}
 */
const deleteUserPluginAuth = async (userId, authField, all = false, pluginKey) => {
  try {
    return await deletePluginAuth({
      userId,
      authField,
      pluginKey,
      all,
    });
  } catch (err) {
    logger.error(
      `[deleteUserPluginAuth] Error deleting ${all ? 'all' : 'single'} auth(s) for userId: ${userId}${pluginKey ? ` and pluginKey: ${pluginKey}` : ''}`,
      err,
    );
    return err;
  }
};

module.exports = {
  getUserPluginAuthValue,
  updateUserPluginAuth,
  deleteUserPluginAuth,
};