mirror of
https://github.com/danny-avila/LibreChat.git
synced 2026-11-02 03:56:35 +00:00
* feat: wire trusted agent trigger dispatch * feat: add durable agent trigger delivery * fix: annotate trigger envelope byte limit * test: isolate trigger startup in server specs * fix: fence trigger delivery during account deletion * test: isolate trigger service in user controller specs * fix: close trigger deletion admission race * fix: harden account deletion fences * fix: close durable trigger review gaps * fix: require offline stale-fence recovery * fix: type trigger lane sequence ids * fix: fence admin user deletion triggers * fix: make trigger deletion recovery durable * fix: harden offline user deletion * fix: serialize trigger lane publication * style: sort trigger delivery imports * fix: recover orphaned trigger publications * fix: preserve trigger recovery ordering * fix: fence trigger publication during purge * fix: defer remote trigger deletion fences * fix: close durable delivery cleanup races * fix: drain CLI generation owners before deletion
69 lines
2.4 KiB
JavaScript
69 lines
2.4 KiB
JavaScript
const { AGENT_TRIGGER_SCOPE } = require('@librechat/api');
|
|
const { logger, runAsSystem } = require('@librechat/data-schemas');
|
|
const { SystemRoles } = require('librechat-data-provider');
|
|
const { Strategy: JwtStrategy, ExtractJwt } = require('passport-jwt');
|
|
const { getUserById, updateUser } = require('~/models');
|
|
|
|
const AGENT_TRIGGER_ADMISSION_PATHS = ['/api/agents/chat/agents', '/api/agents/chat/steer/deliver'];
|
|
|
|
/** A trigger-scoped bearer is deliberately useless outside the two internal
|
|
* admission routes that the execution host calls. */
|
|
function isAgentTriggerAdmissionRequest(req) {
|
|
if (req?.method !== 'POST' || req?.headers?.['x-lc-agent-trigger'] !== '1') {
|
|
return false;
|
|
}
|
|
try {
|
|
const pathname = new URL(req.originalUrl ?? req.url ?? '', 'http://localhost').pathname;
|
|
return AGENT_TRIGGER_ADMISSION_PATHS.some((path) => pathname.endsWith(path));
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// JWT strategy
|
|
const jwtLogin = () =>
|
|
new JwtStrategy(
|
|
{
|
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
secretOrKey: process.env.JWT_SECRET,
|
|
passReqToCallback: true,
|
|
},
|
|
async (req, payload, done) => {
|
|
try {
|
|
if (payload?.scope === AGENT_TRIGGER_SCOPE && !isAgentTriggerAdmissionRequest(req)) {
|
|
done(null, false, { message: 'Agent trigger token is not valid for this endpoint' });
|
|
return;
|
|
}
|
|
const user = await runAsSystem(() =>
|
|
getUserById(
|
|
payload?.id,
|
|
'-password -__v -totpSecret -backupCodes +agentTriggerDeletionStartedAt',
|
|
),
|
|
);
|
|
if (user?.agentTriggerDeletionStartedAt != null) {
|
|
done(null, false, {
|
|
message: 'Account deletion is in progress',
|
|
code: 'ACCOUNT_DELETION_IN_PROGRESS',
|
|
});
|
|
return;
|
|
}
|
|
if (user) {
|
|
user.id = user._id.toString();
|
|
/** Absent on the full doc means local user; null skips getUserPrincipals' fallback lookup */
|
|
user.idOnTheSource ??= null;
|
|
if (!user.role) {
|
|
user.role = SystemRoles.USER;
|
|
await runAsSystem(() => updateUser(user.id, { role: user.role }));
|
|
}
|
|
done(null, user);
|
|
} else {
|
|
logger.warn('[jwtLogin] JwtStrategy => no user found: ' + payload?.id);
|
|
done(null, false);
|
|
}
|
|
} catch (err) {
|
|
done(err, false);
|
|
}
|
|
},
|
|
);
|
|
|
|
module.exports = jwtLogin;
|