mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-16 16:30:15 +01:00
📁 feat: Integrate SharePoint File Picker and Download Workflow (#8651)
* feat(sharepoint): integrate SharePoint file picker and download workflow Introduces end‑to‑end SharePoint import support: * Token exchange with Microsoft Graph and scope management (`useSharePointToken`) * Re‑usable hooks: `useSharePointPicker`, `useSharePointDownload`, `useSharePointFileHandling` * FileSearch dropdown now offers **From Local Machine** / **From SharePoint** sources and gracefully falls back when SharePoint is disabled * Agent upload model, `AttachFileMenu`, and `DropdownPopup` extended for SharePoint files and sub‑menus * Blurry overlay with progress indicator and `maxSelectionCount` limit during downloads * Cache‑flush utility (`config/flush-cache.js`) supporting Redis & filesystem, with dry‑run and npm script * Updated `SharePointIcon` (uses `currentColor`) and new i18n keys * Bug fixes: placeholder syntax in progress message, picker event‑listener cleanup * Misc style and performance optimizations * Fix ESLint warnings --------- Co-authored-by: Atef Bellaaj <slalom.bellaaj@external.daimlertruck.com>
This commit is contained in:
parent
b6413b06bc
commit
a955097faf
40 changed files with 2500 additions and 123 deletions
86
api/server/services/GraphTokenService.js
Normal file
86
api/server/services/GraphTokenService.js
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
const { getOpenIdConfig } = require('~/strategies/openidStrategy');
|
||||
const { logger } = require('~/config');
|
||||
const { CacheKeys } = require('librechat-data-provider');
|
||||
const getLogStores = require('~/cache/getLogStores');
|
||||
const client = require('openid-client');
|
||||
|
||||
/**
|
||||
* Get Microsoft Graph API token using existing token exchange mechanism
|
||||
* @param {Object} user - User object with OpenID information
|
||||
* @param {string} accessToken - Current access token from Authorization header
|
||||
* @param {string} scopes - Graph API scopes for the token
|
||||
* @param {boolean} fromCache - Whether to try getting token from cache first
|
||||
* @returns {Promise<Object>} Graph API token response with access_token and expires_in
|
||||
*/
|
||||
async function getGraphApiToken(user, accessToken, scopes, fromCache = true) {
|
||||
try {
|
||||
if (!user.openidId) {
|
||||
throw new Error('User must be authenticated via Entra ID to access Microsoft Graph');
|
||||
}
|
||||
|
||||
if (!accessToken) {
|
||||
throw new Error('Access token is required for token exchange');
|
||||
}
|
||||
|
||||
if (!scopes) {
|
||||
throw new Error('Graph API scopes are required for token exchange');
|
||||
}
|
||||
|
||||
const config = getOpenIdConfig();
|
||||
if (!config) {
|
||||
throw new Error('OpenID configuration not available');
|
||||
}
|
||||
|
||||
const cacheKey = `${user.openidId}:${scopes}`;
|
||||
const tokensCache = getLogStores(CacheKeys.OPENID_EXCHANGED_TOKENS);
|
||||
|
||||
if (fromCache) {
|
||||
const cachedToken = await tokensCache.get(cacheKey);
|
||||
if (cachedToken) {
|
||||
logger.debug(`[GraphTokenService] Using cached Graph API token for user: ${user.openidId}`);
|
||||
return cachedToken;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug(`[GraphTokenService] Requesting new Graph API token for user: ${user.openidId}`);
|
||||
logger.debug(`[GraphTokenService] Requested scopes: ${scopes}`);
|
||||
|
||||
const grantResponse = await client.genericGrantRequest(
|
||||
config,
|
||||
'urn:ietf:params:oauth:grant-type:jwt-bearer',
|
||||
{
|
||||
scope: scopes,
|
||||
assertion: accessToken,
|
||||
requested_token_use: 'on_behalf_of',
|
||||
},
|
||||
);
|
||||
|
||||
const tokenResponse = {
|
||||
access_token: grantResponse.access_token,
|
||||
token_type: 'Bearer',
|
||||
expires_in: grantResponse.expires_in || 3600,
|
||||
scope: scopes,
|
||||
};
|
||||
|
||||
await tokensCache.set(
|
||||
cacheKey,
|
||||
tokenResponse,
|
||||
(grantResponse.expires_in || 3600) * 1000, // Convert to milliseconds
|
||||
);
|
||||
|
||||
logger.debug(
|
||||
`[GraphTokenService] Successfully obtained and cached Graph API token for user: ${user.openidId}`,
|
||||
);
|
||||
return tokenResponse;
|
||||
} catch (error) {
|
||||
logger.error(
|
||||
`[GraphTokenService] Failed to acquire Graph API token for user ${user.openidId}:`,
|
||||
error,
|
||||
);
|
||||
throw new Error(`Graph token acquisition failed: ${error.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
getGraphApiToken,
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue