diff --git a/.env.example b/.env.example index 251ddfb8a01..37fe7790cca 100644 --- a/.env.example +++ b/.env.example @@ -240,7 +240,7 @@ SESSION_EXPIRY=(1000 * 60 * 60 * 24) * 7 GITHUB_CLIENT_ID=your_client_id GITHUB_CLIENT_SECRET=your_client_secret -GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyone +GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyone so dont change it # Discord: # Get the Client ID and Secret from your Discord Application @@ -248,7 +248,15 @@ GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyon DISCORD_CLIENT_ID=your_client_id DISCORD_CLIENT_SECRET=your_client_secret -DISCORD_CALLBACK_URL=/oauth/discord/callback # this should be the same for everyone +DISCORD_CALLBACK_URL=/oauth/discord/callback # this should be the same for everyone so dont change it + +# Twitter: +# Get the API Key and Secret from your Twitter Application +# Add your "API Key" in Client ID and your "Secret" in Client Secret here: + +TWITTER_API_KEY=your_api_key +TWITTER_API_SECRET=your_secret +TWITTER_CALLBACK_URL=/oauth/twitter/callback # this should be the same for everyone so dont change it ########################### # Application Domains diff --git a/README.md b/README.md index 7ae144ac899..de0209f9f1b 100644 --- a/README.md +++ b/README.md @@ -69,8 +69,8 @@ Keep up with the latest updates by visiting the releases page - [Releases](https * [Mac Install🍎](docs/install/mac_install.md) * [Windows Install💙](docs/install/windows_install.md) * Configuration - * [APIs and Tokens](docs/install/apis_and_tokens.md) - * [User Auth System](docs/install/user_auth_system.md) + * [APIs and Tokens](docs/install/API_&_Auth/apis_and_tokens.md) + * [User Auth System](docs/install/API_&_Auth/user_auth_system.md) * [Online MongoDB Database](docs/install/mongodb.md) * [Languages](docs/install/languages.md) diff --git a/api/models/User.js b/api/models/User.js index f7d07ade228..3d6914cb6d8 100644 --- a/api/models/User.js +++ b/api/models/User.js @@ -80,6 +80,11 @@ const userSchema = mongoose.Schema( unique: true, sparse: true, }, + twitterId: { + type: String, + unique: true, + sparse: true, + }, plugins: { type: Array, default: [], diff --git a/api/package.json b/api/package.json index 157b87fcc4e..de243b28401 100644 --- a/api/package.json +++ b/api/package.json @@ -57,13 +57,14 @@ "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "passport-twitter": "^0.1.5", "pino": "^8.12.1", "sanitize": "^2.1.2", "sharp": "^0.32.1" }, "devDependencies": { "jest": "^29.5.0", - "nodemon": "^2.0.20", + "nodemon": "^3.0.1", "path": "^0.12.7", "supertest": "^6.3.3" } diff --git a/api/server/index.js b/api/server/index.js index 2480dc25f56..2e334c3eafd 100644 --- a/api/server/index.js +++ b/api/server/index.js @@ -16,6 +16,7 @@ const { googleLogin, githubLogin, discordLogin, + twitterLogin, facebookLogin, setupOpenId, } = require('../strategies'); @@ -61,6 +62,9 @@ config.validate(); // Validate the config if (process.env.DISCORD_CLIENT_ID && process.env.DISCORD_CLIENT_SECRET) { passport.use(await discordLogin()); } + if (process.env.TWITTER_API_KEY && process.env.TWITTER_API_SECRET) { + passport.use(await twitterLogin()); + } if ( process.env.OPENID_CLIENT_ID && process.env.OPENID_CLIENT_SECRET && diff --git a/api/server/routes/__tests__/config.spec.js b/api/server/routes/__tests__/config.spec.js index 87ce05af016..82c21b0f46a 100644 --- a/api/server/routes/__tests__/config.spec.js +++ b/api/server/routes/__tests__/config.spec.js @@ -18,6 +18,8 @@ afterEach(() => { delete process.env.GITHUB_CLIENT_SECRET; delete process.env.DISCORD_CLIENT_ID; delete process.env.DISCORD_CLIENT_SECRET; + delete process.env.TWITTER_API_KEY; + delete process.env.TWITTER_API_SECRET; delete process.env.DOMAIN_SERVER; delete process.env.ALLOW_REGISTRATION; delete process.env.ALLOW_SOCIAL_LOGIN; @@ -41,6 +43,8 @@ describe.skip('GET /', () => { process.env.GITHUB_CLIENT_SECRET = 'Test Github client Secret'; process.env.DISCORD_CLIENT_ID = 'Test Discord client Id'; process.env.DISCORD_CLIENT_SECRET = 'Test Discord client Secret'; + process.env.TWITTER_API_KEY = 'Test Twitter api key'; + process.env.TWITTER_API_SECRET = 'Test Twitter api Secret'; process.env.DOMAIN_SERVER = 'http://test-server.com'; process.env.ALLOW_REGISTRATION = 'true'; process.env.ALLOW_SOCIAL_LOGIN = 'true'; @@ -56,6 +60,7 @@ describe.skip('GET /', () => { openidImageUrl: 'http://test-server.com', githubLoginEnabled: true, discordLoginEnabled: true, + twitterLoginEnabled: true, serverDomain: 'http://test-server.com', registrationEnabled: 'true', socialLoginEnabled: 'true', diff --git a/api/server/routes/config.js b/api/server/routes/config.js index e52bda2e956..10870aef939 100644 --- a/api/server/routes/config.js +++ b/api/server/routes/config.js @@ -15,6 +15,7 @@ router.get('/', async function (req, res) { const githubLoginEnabled = !!process.env.GITHUB_CLIENT_ID && !!process.env.GITHUB_CLIENT_SECRET; const discordLoginEnabled = !!process.env.DISCORD_CLIENT_ID && !!process.env.DISCORD_CLIENT_SECRET; + const twitterLoginEnabled = !!process.env.TWITTER_API_KEY && !!process.env.TWITTER_API_SECRET; const serverDomain = process.env.DOMAIN_SERVER || 'http://localhost:3080'; const registrationEnabled = process.env.ALLOW_REGISTRATION === 'true'; const socialLoginEnabled = process.env.ALLOW_SOCIAL_LOGIN === 'true'; @@ -32,6 +33,7 @@ router.get('/', async function (req, res) { openidImageUrl, githubLoginEnabled, discordLoginEnabled, + twitterLoginEnabled, serverDomain, registrationEnabled, socialLoginEnabled, diff --git a/api/server/routes/oauth.js b/api/server/routes/oauth.js index bd82f4cb4e0..fa318ddcc1d 100644 --- a/api/server/routes/oauth.js +++ b/api/server/routes/oauth.js @@ -141,4 +141,31 @@ router.get( }, ); +router.get( + '/twitter', + passport.authenticate('twitter', { + includeEmail: true, + session: false, + }), +); + +router.get( + '/twitter/callback', + passport.authenticate('twitter', { + failureRedirect: `${domains.client}/login`, + failureMessage: true, + includeEmail: true, + session: false, + }), + (req, res) => { + const token = req.user.generateToken(); + res.cookie('token', token, { + expires: new Date(Date.now() + eval(process.env.SESSION_EXPIRY)), + httpOnly: false, + secure: isProduction, + }); + res.redirect(domains.client); + }, +); + module.exports = router; diff --git a/api/strategies/index.js b/api/strategies/index.js index 1c49c2b1cdd..2b46fb0b06a 100644 --- a/api/strategies/index.js +++ b/api/strategies/index.js @@ -2,6 +2,7 @@ const passportLogin = require('./localStrategy'); const googleLogin = require('./googleStrategy'); const githubLogin = require('./githubStrategy'); const discordLogin = require('./discordStrategy'); +const twitterLogin = require('./twitterStrategy'); const jwtLogin = require('./jwtStrategy'); const facebookLogin = require('./facebookStrategy'); const setupOpenId = require('./openidStrategy'); @@ -11,6 +12,7 @@ module.exports = { googleLogin, githubLogin, discordLogin, + twitterLogin, jwtLogin, facebookLogin, setupOpenId, diff --git a/api/strategies/twitterStrategy.js b/api/strategies/twitterStrategy.js new file mode 100644 index 00000000000..723637e36e4 --- /dev/null +++ b/api/strategies/twitterStrategy.js @@ -0,0 +1,45 @@ +const { Strategy: TwitterStrategy } = require('passport-twitter'); +const User = require('../models/User'); +const config = require('../../config/loader'); +const domains = config.domains; + +const twitterLogin = async () => + new TwitterStrategy( + { + consumerKey: process.env.TWITTER_API_KEY, + consumerSecret: process.env.TWITTER_API_SECRET, + callbackURL: `${domains.server}${process.env.TWITTER_CALLBACK_URL}`, + proxy: false, + includeEmail: true, + }, + async (token, tokenSecret, profile, cb) => { + try { + const email = profile.emails && profile.emails.length > 0 ? profile.emails[0].value : null; + + const oldUser = await User.findOne({ email }); + if (oldUser) { + return cb(null, oldUser); + } + + if (!email) { + return cb(new Error('Email not available from Twitter profile')); + } + + const newUser = await new User({ + provider: 'twitter', + twitterId: profile.id, + username: profile.username, + email, + name: profile.displayName, + avatar: profile.photos && profile.photos.length > 0 ? profile.photos[0].value : null, + }).save(); + + cb(null, newUser); + } catch (err) { + console.error(err); + cb(err); + } + }, + ); + +module.exports = twitterLogin; diff --git a/client/src/components/Auth/Login.tsx b/client/src/components/Auth/Login.tsx index 622f3ec8aa0..a89eea417b1 100644 --- a/client/src/components/Auth/Login.tsx +++ b/client/src/components/Auth/Login.tsx @@ -7,7 +7,7 @@ import { useRecoilValue } from 'recoil'; import store from '~/store'; import { localize } from '~/localization/Translation'; import { useGetStartupConfig } from 'librechat-data-provider'; -import { GoogleIcon, OpenIDIcon, GithubIcon, DiscordIcon } from '~/components'; +import { GoogleIcon, OpenIDIcon, GithubIcon, DiscordIcon, TwitterXIcon } from '~/components'; function Login() { const { login, error, isAuthenticated } = useAuthContext(); @@ -115,6 +115,20 @@ function Login() { )} + {startupConfig?.twitterLoginEnabled && startupConfig?.socialLoginEnabled && ( + <> +
+ + +

{localize(lang, 'com_auth_twitter_login')}

+
+
+ + )} ); diff --git a/client/src/components/Auth/Registration.tsx b/client/src/components/Auth/Registration.tsx index e859bbf82c0..da2e17241f2 100644 --- a/client/src/components/Auth/Registration.tsx +++ b/client/src/components/Auth/Registration.tsx @@ -9,7 +9,7 @@ import { TRegisterUser, useGetStartupConfig, } from 'librechat-data-provider'; -import { GoogleIcon, OpenIDIcon, GithubIcon, DiscordIcon } from '~/components'; +import { GoogleIcon, OpenIDIcon, GithubIcon, DiscordIcon, TwitterXIcon } from '~/components'; function Registration() { const navigate = useNavigate(); @@ -356,6 +356,20 @@ function Registration() { )} + {startupConfig?.twitterLoginEnabled && startupConfig?.socialLoginEnabled && ( + <> +
+ + +

{localize(lang, 'com_auth_twitter_login')}

+
+
+ + )} ); diff --git a/client/src/components/Auth/__tests__/Login.spec.tsx b/client/src/components/Auth/__tests__/Login.spec.tsx index 0be0f47a06e..30b34ef2a59 100644 --- a/client/src/components/Auth/__tests__/Login.spec.tsx +++ b/client/src/components/Auth/__tests__/Login.spec.tsx @@ -28,6 +28,7 @@ const setup = ({ openidImageUrl: 'http://test-server.com', githubLoginEnabled: true, discordLoginEnabled: true, + twitterLoginEnabled: true, registrationEnabled: true, socialLoginEnabled: true, serverDomain: 'mock-server', diff --git a/client/src/components/Auth/__tests__/Registration.spec.tsx b/client/src/components/Auth/__tests__/Registration.spec.tsx index 6b66f05e4de..7c7da4a4bb7 100644 --- a/client/src/components/Auth/__tests__/Registration.spec.tsx +++ b/client/src/components/Auth/__tests__/Registration.spec.tsx @@ -29,6 +29,7 @@ const setup = ({ openidImageUrl: 'http://test-server.com', githubLoginEnabled: true, discordLoginEnabled: true, + twitterLoginEnabled: true, registrationEnabled: true, socialLoginEnabled: true, serverDomain: 'mock-server', diff --git a/client/src/components/svg/TwitterXIcon.tsx b/client/src/components/svg/TwitterXIcon.tsx new file mode 100644 index 00000000000..1b9f11dc3f2 --- /dev/null +++ b/client/src/components/svg/TwitterXIcon.tsx @@ -0,0 +1,26 @@ +import React from 'react'; + +export default function TwitterXIcon() { + return ( + + + + + + + ); +} diff --git a/client/src/components/svg/index.ts b/client/src/components/svg/index.ts index 9af2fdba26c..c9e7421de15 100644 --- a/client/src/components/svg/index.ts +++ b/client/src/components/svg/index.ts @@ -14,6 +14,7 @@ export { default as GoogleIcon } from './GoogleIcon'; export { default as OpenIDIcon } from './OpenIDIcon'; export { default as GithubIcon } from './GithubIcon'; export { default as DiscordIcon } from './DiscordIcon'; +export { default as TwitterXIcon } from './TwitterXIcon'; export { default as AnthropicIcon } from './AnthropicIcon'; export { default as LinkIcon } from './LinkIcon'; export { default as DotsIcon } from './DotsIcon'; diff --git a/client/src/localization/languages/Eng.tsx b/client/src/localization/languages/Eng.tsx index 647a3545bbb..e6c87f59cf5 100644 --- a/client/src/localization/languages/Eng.tsx +++ b/client/src/localization/languages/Eng.tsx @@ -38,6 +38,7 @@ export default { com_auth_google_login: 'Login with Google', com_auth_github_login: 'Login with Github', com_auth_discord_login: 'Login with Discord', + com_auth_twitter_login: 'Login with Twitter', com_auth_email: 'Email', com_auth_email_required: 'Email is required', com_auth_email_min_length: 'Email must be at least 6 characters', diff --git a/docs/install/apis_and_tokens.md b/docs/install/API_&_Auth/apis_and_tokens.md similarity index 100% rename from docs/install/apis_and_tokens.md rename to docs/install/API_&_Auth/apis_and_tokens.md diff --git a/docs/install/free_ai_apis.md b/docs/install/API_&_Auth/free_ai_apis.md similarity index 100% rename from docs/install/free_ai_apis.md rename to docs/install/API_&_Auth/free_ai_apis.md diff --git a/docs/install/API_&_Auth/twitter-text.md b/docs/install/API_&_Auth/twitter-text.md new file mode 100644 index 00000000000..60d1e49652d --- /dev/null +++ b/docs/install/API_&_Auth/twitter-text.md @@ -0,0 +1,9 @@ +# Twitter example text for Twitter Developer Portal + +### Copy and paste this: + +I want to integrate the "Login with Twitter" feature on my website to make registration simpler and faster for users. Allowing users to log in with their Twitter account eliminates the need for them to create separate usernames and passwords just for my site. This way I reduce friction in the sign-up process and encourage more users to register and try out my website. + +Once a user logs in via Twitter, I can securely collect publicly available profile data like their name, username, profile picture and more. This allows me to personalize and improve the experience for each user without requiring them to fill out long and boring forms. I can also give them the ability to post content from my site directly to Twitter, which could help drive more traffic back to my site. + +Overall, adding Twitter login makes the user experience more seamless, helps acquire more users, provides valuable insights into their public profiles and opens opportunities for engagement and sharing on Twitter. It's a win for all parties involved. By properly implementing Twitter's APIs, I can take advantage of Twitter's huge user base and established social identity without compromising security. This will help my business grow and attract a wider audience. diff --git a/docs/install/user_auth_system.md b/docs/install/API_&_Auth/user_auth_system.md similarity index 87% rename from docs/install/user_auth_system.md rename to docs/install/API_&_Auth/user_auth_system.md index d46f4d8ab5c..bb53841568e 100644 --- a/docs/install/user_auth_system.md +++ b/docs/install/API_&_Auth/user_auth_system.md @@ -113,7 +113,7 @@ OPENID_CALLBACK_URL=/oauth/openid/callback ``` GITHUB_CLIENT_ID=your_client_id GITHUB_CLIENT_SECRET=your_client_secret -GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyone +GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyone so dont change it ``` 9. Save the .env file --- @@ -129,10 +129,36 @@ GITHUB_CALLBACK_URL=/oauth/github/callback # this should be the same for everyon ``` DISCORD_CLIENT_ID=your_client_id DISCORD_CLIENT_SECRET=your_client_secret -DISCORD_CALLBACK_URL=/oauth/discord/callback # this should be the same for everyone +DISCORD_CALLBACK_URL=/oauth/discord/callback # this should be the same for everyone so dont change it ``` 8. Save the .env file --- + +## Twitter Authentication + +1. Go to [Twitter Developer Portal](https://developer.twitter.com/) +2. Sign in and create a free account +3. Describe all of your use cases of Twitter’s data and API (if you don't know what to write, copy and paste [this](./twitter-text.md)) +4. In the Project & Apps tab, select "Default project ..." If you want, modify your project name to something like "LibreChat Login" in settings. +5. Under the Default Project..., open the app. If you want, modify the App Name and upload an App Icon. +6. In "User authentication settings," click on "Set up." +7. In the App permissions, select "Read" and "Request email from users." In Type of App, select "Web App, Automated App, or Bot." +8. In the App Info, put the provided information and save. +``` +Callback URI / Redirect URL= your-domain/oauth/twitter/callback +Website URL= your-domain +Terms of service= https://example.com +Privacy policy= https://example.com +``` +9. In the Keys and tokens, click on Regenerate (the API Key and Secret), copy it and save it somewhere +10. Put the API Key and API Secret in the .env file: +``` +TWITTER_API_KEY=your_api_key +TWITTER_API_SECRET=your_api_secret +TWITTER_CALLBACK_URL=/oauth/twitter/callback # this should be the same for everyone so dont change it +``` +11. Save the .env file + ## **Email and Password Reset** ### General setup diff --git a/mkdocs.yml b/mkdocs.yml index c61df290f7b..f422caee3de 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -87,9 +87,9 @@ nav: - Mac Install: 'install/mac_install.md' - Windows Install: 'install/windows_install.md' - Configuration: - - Free AI APIs: 'install/free_ai_apis.md' - - APIs and Tokens: 'install/apis_and_tokens.md' - - User Auth System: 'install/user_auth_system.md' + - Free AI APIs: 'install/API_&_Auth/free_ai_apis.md' + - APIs and Tokens: 'install/API_&_Auth/apis_and_tokens.md' + - User Auth System: 'install/API_&_Auth/user_auth_system.md' - Online MongoDB Database: 'install/mongodb.md' - Languages: 'install/languages.md' - Features: diff --git a/package-lock.json b/package-lock.json index 99526cdb27b..ed6194738a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -83,13 +83,14 @@ "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "passport-twitter": "^0.1.5", "pino": "^8.12.1", "sanitize": "^2.1.2", "sharp": "^0.32.1" }, "devDependencies": { "jest": "^29.5.0", - "nodemon": "^2.0.20", + "nodemon": "^3.0.1", "path": "^0.12.7", "supertest": "^6.3.3" } @@ -19762,9 +19763,9 @@ } }, "node_modules/nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, "dependencies": { "chokidar": "^3.5.2", @@ -19772,8 +19773,8 @@ "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -19782,7 +19783,7 @@ "nodemon": "bin/nodemon.js" }, "engines": { - "node": ">=8.10.0" + "node": ">=10" }, "funding": { "type": "opencollective", @@ -19798,15 +19799,6 @@ "ms": "^2.1.1" } }, - "node_modules/nodemon/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, "node_modules/nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", @@ -20556,6 +20548,31 @@ "node": ">= 0.4.0" } }, + "node_modules/passport-oauth": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/passport-oauth/-/passport-oauth-0.1.15.tgz", + "integrity": "sha512-ma4W++dGNS/WKxkInG03VDqCRPD/9K/eSaqhvMLBFhpLOfycBus8+FnhcoSR6ug+NzXLjYtjGxMPBE/Gt8KqqA==", + "dependencies": { + "oauth": "0.9.x", + "passport": "~0.1.1", + "pkginfo": "0.2.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/passport-oauth/node_modules/passport": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.1.18.tgz", + "integrity": "sha512-qteYojKG/qth7UBbbGU7aqhe5ndJs6YaUkH2B6+7FWQ0OeyYmWknzOATpMhdoSTDcLLliq9n4Fcy1mGs80iUMw==", + "dependencies": { + "pause": "0.0.1", + "pkginfo": "0.2.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/passport-oauth2": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.7.0.tgz", @@ -20583,6 +20600,18 @@ "node": ">= 0.4.0" } }, + "node_modules/passport-twitter": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/passport-twitter/-/passport-twitter-0.1.5.tgz", + "integrity": "sha512-nQLgJoDcahmKksyf/krsuTq3pM3QhuTkbVYoBr8SzocDmxRShbdbJbH/PxiwSo5/XnrpnIHgAjlqkfqmC7HAZg==", + "dependencies": { + "passport-oauth": "0.1.x", + "pkginfo": "0.2.x" + }, + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -20848,6 +20877,14 @@ "node": ">=8" } }, + "node_modules/pkginfo": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", + "integrity": "sha512-7W7wTrE/NsY8xv/DTGjwNIyNah81EQH0MWcTzrHL6pOpMocOGZc0Mbdz9aXxSrp+U0mSmkU8jrNCDCfUs3sOBg==", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/playwright-core": { "version": "1.36.2", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz", @@ -23791,24 +23828,15 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, "node_modules/simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "dependencies": { - "semver": "~7.0.0" + "semver": "^7.5.3" }, "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/simple-update-notifier/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" + "node": ">=10" } }, "node_modules/sisteransi": { @@ -30477,7 +30505,7 @@ "meilisearch": "^0.33.0", "mongoose": "^7.1.1", "nodemailer": "^6.9.4", - "nodemon": "^2.0.20", + "nodemon": "^3.0.1", "openai": "^3.2.1", "openid-client": "^5.4.2", "passport": "^0.6.0", @@ -30487,6 +30515,7 @@ "passport-google-oauth20": "^2.0.0", "passport-jwt": "^4.0.1", "passport-local": "^1.0.0", + "passport-twitter": "^0.1.5", "path": "^0.12.7", "pino": "^8.12.1", "sanitize": "^2.1.2", @@ -41035,9 +41064,9 @@ "integrity": "sha512-CXjQvrQZV4+6X5wP6ZIgdehJamI63MFoYFGGPtHudWym9qaEHDNdPzaj5bfMCvxG1vhAileSWW90q7nL0N36mA==" }, "nodemon": { - "version": "2.0.22", - "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-2.0.22.tgz", - "integrity": "sha512-B8YqaKMmyuCO7BowF1Z1/mkPqLk6cs/l63Ojtd6otKjMx47Dq1utxfRxcavH1I7VSaL8n5BUaoutadnsX3AAVQ==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.0.1.tgz", + "integrity": "sha512-g9AZ7HmkhQkqXkRc20w+ZfQ73cHLbE8hnPbtaFbFtCumZsjyMhKk9LajQ07U5Ux28lvFjZ5X7HvWR1xzU8jHVw==", "dev": true, "requires": { "chokidar": "^3.5.2", @@ -41045,8 +41074,8 @@ "ignore-by-default": "^1.0.1", "minimatch": "^3.1.2", "pstree.remy": "^1.1.8", - "semver": "^5.7.1", - "simple-update-notifier": "^1.0.7", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", "supports-color": "^5.5.0", "touch": "^3.1.0", "undefsafe": "^2.0.5" @@ -41060,12 +41089,6 @@ "requires": { "ms": "^2.1.1" } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true } } }, @@ -41610,6 +41633,27 @@ "passport-strategy": "1.x.x" } }, + "passport-oauth": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/passport-oauth/-/passport-oauth-0.1.15.tgz", + "integrity": "sha512-ma4W++dGNS/WKxkInG03VDqCRPD/9K/eSaqhvMLBFhpLOfycBus8+FnhcoSR6ug+NzXLjYtjGxMPBE/Gt8KqqA==", + "requires": { + "oauth": "0.9.x", + "passport": "~0.1.1", + "pkginfo": "0.2.x" + }, + "dependencies": { + "passport": { + "version": "0.1.18", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.1.18.tgz", + "integrity": "sha512-qteYojKG/qth7UBbbGU7aqhe5ndJs6YaUkH2B6+7FWQ0OeyYmWknzOATpMhdoSTDcLLliq9n4Fcy1mGs80iUMw==", + "requires": { + "pause": "0.0.1", + "pkginfo": "0.2.x" + } + } + } + }, "passport-oauth2": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/passport-oauth2/-/passport-oauth2-1.7.0.tgz", @@ -41627,6 +41671,15 @@ "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", "integrity": "sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==" }, + "passport-twitter": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/passport-twitter/-/passport-twitter-0.1.5.tgz", + "integrity": "sha512-nQLgJoDcahmKksyf/krsuTq3pM3QhuTkbVYoBr8SzocDmxRShbdbJbH/PxiwSo5/XnrpnIHgAjlqkfqmC7HAZg==", + "requires": { + "passport-oauth": "0.1.x", + "pkginfo": "0.2.x" + } + }, "path": { "version": "0.12.7", "resolved": "https://registry.npmjs.org/path/-/path-0.12.7.tgz", @@ -41829,6 +41882,11 @@ } } }, + "pkginfo": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/pkginfo/-/pkginfo-0.2.3.tgz", + "integrity": "sha512-7W7wTrE/NsY8xv/DTGjwNIyNah81EQH0MWcTzrHL6pOpMocOGZc0Mbdz9aXxSrp+U0mSmkU8jrNCDCfUs3sOBg==" + }, "playwright-core": { "version": "1.36.2", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz", @@ -43774,20 +43832,12 @@ } }, "simple-update-notifier": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-1.1.0.tgz", - "integrity": "sha512-VpsrsJSUcJEseSbMHkrsrAVSdvVS5I96Qo1QAQ4FxQ9wXFcB+pjj7FB7/us9+GcgfW4ziHtYMc1J0PLczb55mg==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", "dev": true, "requires": { - "semver": "~7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } + "semver": "^7.5.3" } }, "sisteransi": { diff --git a/packages/data-provider/src/types.ts b/packages/data-provider/src/types.ts index 6bf0a23d2ba..152b27d49ca 100644 --- a/packages/data-provider/src/types.ts +++ b/packages/data-provider/src/types.ts @@ -189,6 +189,7 @@ export type TStartupConfig = { openidLabel: string; openidImageUrl: string; discordLoginEnabled: boolean; + twitterLoginEnabled: boolean; serverDomain: string; registrationEnabled: boolean; socialLoginEnabled: boolean;