🛂 fix: OIDC Username Array Edge Case (#2394)

* Patch for OpenID username

`username` is generally based on email, rather than `given_name`. The challenge with `given_name` is that it can be a multi-value array (ex: "Nick, Fullname"), which completely breaks the system with: 

```
LibreChat      | ValidationError: User validation failed: username: Cast to string failed for value "[ 'Nickname', 'Firstname' ]" (type Array) at path "username"
LibreChat      |     at Document.invalidate (/app/node_modules/mongoose/lib/document.js:3200:32)
LibreChat      |     at model.$set (/app/node_modules/mongoose/lib/document.js:1459:12)
LibreChat      |     at model.set [as username] (/app/node_modules/mongoose/lib/helpers/document/compile.js:205:19)
LibreChat      |     at OpenIDConnectStrategy._verify (/app/api/strategies/openidStrategy.js:127:27)
LibreChat      |     at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
```

* Update openidStrategy.js

* refactor(openidStrategy): add helper function for stringy username

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
This commit is contained in:
Ventz Petkov 2024-04-12 12:39:11 -04:00 committed by GitHub
parent 9d137ce42f
commit f380f261a5
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -37,6 +37,26 @@ const downloadImage = async (url, imagePath, accessToken) => {
}
};
/**
* Converts an input into a string suitable for a username.
* If the input is a string, it will be returned as is.
* If the input is an array, elements will be joined with underscores.
* In case of undefined or other falsy values, a default value will be returned.
*
* @param {string | string[] | undefined} input - The input value to be converted into a username.
* @param {string} [defaultValue=''] - The default value to return if the input is falsy.
* @returns {string} The processed input as a string suitable for a username.
*/
function convertToUsername(input, defaultValue = '') {
if (typeof input === 'string') {
return input;
} else if (Array.isArray(input)) {
return input.join('_');
}
return defaultValue;
}
async function setupOpenId() {
try {
const issuer = await Issuer.discover(process.env.OPENID_ISSUER);
@ -104,11 +124,13 @@ async function setupOpenId() {
}
}
const username = convertToUsername(userinfo.username || userinfo.given_name || userinfo.email);
if (!user) {
user = new User({
provider: 'openid',
openidId: userinfo.sub,
username: userinfo.username || userinfo.given_name || '',
username,
email: userinfo.email || '',
emailVerified: userinfo.email_verified || false,
name: fullName,
@ -116,7 +138,7 @@ async function setupOpenId() {
} else {
user.provider = 'openid';
user.openidId = userinfo.sub;
user.username = userinfo.username || userinfo.given_name || '';
user.username = username;
user.name = fullName;
}