diff --git a/.env.example b/.env.example
index 0b7fa848e6..9eb117ae68 100644
--- a/.env.example
+++ b/.env.example
@@ -399,6 +399,13 @@ FIREBASE_STORAGE_BUCKET=
FIREBASE_MESSAGING_SENDER_ID=
FIREBASE_APP_ID=
+#========================#
+# Shared Links #
+#========================#
+
+ALLOW_SHARED_LINKS=true
+ALLOW_SHARED_LINKS_PUBLIC=true
+
#===================================================#
# UI #
#===================================================#
diff --git a/api/server/routes/config.js b/api/server/routes/config.js
index 07022bc535..de3c0d89c9 100644
--- a/api/server/routes/config.js
+++ b/api/server/routes/config.js
@@ -8,6 +8,14 @@ const emailLoginEnabled =
process.env.ALLOW_EMAIL_LOGIN === undefined || isEnabled(process.env.ALLOW_EMAIL_LOGIN);
const passwordResetEnabled = isEnabled(process.env.ALLOW_PASSWORD_RESET);
+const sharedLinksEnabled =
+ process.env.ALLOW_SHARED_LINKS === undefined || isEnabled(process.env.ALLOW_SHARED_LINKS);
+
+const publicSharedLinksEnabled =
+ sharedLinksEnabled &&
+ (process.env.ALLOW_SHARED_LINKS_PUBLIC === undefined ||
+ isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC));
+
router.get('/', async function (req, res) {
const isBirthday = () => {
const today = new Date();
@@ -52,6 +60,8 @@ router.get('/', async function (req, res) {
helpAndFaqURL: process.env.HELP_AND_FAQ_URL || 'https://librechat.ai',
interface: req.app.locals.interfaceConfig,
modelSpecs: req.app.locals.modelSpecs,
+ sharedLinksEnabled,
+ publicSharedLinksEnabled,
analyticsGtmId: process.env.ANALYTICS_GTM_ID,
};
diff --git a/api/server/routes/share.js b/api/server/routes/share.js
index 7fbdae23f1..cc75024224 100644
--- a/api/server/routes/share.js
+++ b/api/server/routes/share.js
@@ -8,21 +8,33 @@ const {
deleteSharedLink,
} = require('~/models/Share');
const requireJwtAuth = require('~/server/middleware/requireJwtAuth');
+const { isEnabled } = require('~/server/utils');
const router = express.Router();
/**
* Shared messages
- * this route does not require authentication
*/
-router.get('/:shareId', async (req, res) => {
- const share = await getSharedMessages(req.params.shareId);
+const allowSharedLinks =
+ process.env.ALLOW_SHARED_LINKS === undefined || isEnabled(process.env.ALLOW_SHARED_LINKS);
- if (share) {
- res.status(200).json(share);
- } else {
- res.status(404).end();
- }
-});
+if (allowSharedLinks) {
+ const allowSharedLinksPublic =
+ process.env.ALLOW_SHARED_LINKS_PUBLIC === undefined ||
+ isEnabled(process.env.ALLOW_SHARED_LINKS_PUBLIC);
+ router.get(
+ '/:shareId',
+ allowSharedLinksPublic ? (req, res, next) => next() : requireJwtAuth,
+ async (req, res) => {
+ const share = await getSharedMessages(req.params.shareId);
+
+ if (share) {
+ res.status(200).json(share);
+ } else {
+ res.status(404).end();
+ }
+ },
+ );
+}
/**
* Shared links
diff --git a/client/src/components/Chat/ExportAndShareMenu.tsx b/client/src/components/Chat/ExportAndShareMenu.tsx
index 4a343ccffe..ba556499ee 100644
--- a/client/src/components/Chat/ExportAndShareMenu.tsx
+++ b/client/src/components/Chat/ExportAndShareMenu.tsx
@@ -8,7 +8,13 @@ import useLocalize from '~/hooks/useLocalize';
import ExportButton from './ExportButton';
import store from '~/store';
-export default function ExportAndShareMenu({ className = '' }: { className?: string }) {
+export default function ExportAndShareMenu({
+ isSharedButtonEnabled,
+ className = '',
+}: {
+ isSharedButtonEnabled: boolean;
+ className?: string;
+}) {
const localize = useLocalize();
const conversation = useRecoilValue(store.conversationByIndex(0));
@@ -41,13 +47,15 @@ export default function ExportAndShareMenu({ className = '' }: { className?: str
{conversation && conversation.conversationId && (
<>