mirror of
https://github.com/yu-i-i/overleaf-cep.git
synced 2026-05-31 21:01:33 +02:00
121 lines
4.2 KiB
JavaScript
121 lines
4.2 KiB
JavaScript
import Settings from '@overleaf/settings'
|
|
import logger from '@overleaf/logger'
|
|
import { promisify } from 'util'
|
|
import passport from 'passport'
|
|
import ldapjs from 'ldapauth-fork/node_modules/ldapjs/lib/index.js'
|
|
import UserGetter from '../../../../../app/src/Features/User/UserGetter.js'
|
|
import { splitFullName } from '../../../utils.mjs'
|
|
|
|
function _searchLDAP(client, baseDN, options) {
|
|
return new Promise((resolve, reject) => {
|
|
const searchEntries = []
|
|
client.search(baseDN, options, (error, res) => {
|
|
if (error) {
|
|
reject(error)
|
|
} else {
|
|
res.on('searchEntry', entry => searchEntries.push(entry.object))
|
|
res.on('error', reject)
|
|
res.on('end', () => resolve(searchEntries))
|
|
}
|
|
})
|
|
})
|
|
}
|
|
|
|
async function fetchLDAPContacts(userId, contacts) {
|
|
if (!Settings.ldap?.enable || !process.env.OVERLEAF_LDAP_CONTACTS_FILTER) {
|
|
return []
|
|
}
|
|
|
|
const ldapOptions = passport._strategy('ldapauth').options.server
|
|
const { attEmail, attFirstName = "", attLastName = "", attName = "" } = Settings.ldap
|
|
const {
|
|
url,
|
|
timeout,
|
|
connectTimeout,
|
|
tlsOptions,
|
|
starttls,
|
|
bindDN,
|
|
bindCredentials
|
|
} = ldapOptions
|
|
const searchBase = process.env.OVERLEAF_LDAP_CONTACTS_SEARCH_BASE || ldapOptions.searchBase
|
|
const searchScope = process.env.OVERLEAF_LDAP_CONTACTS_SEARCH_SCOPE || 'sub'
|
|
const ldapConfig = { url, timeout, connectTimeout, tlsOptions }
|
|
|
|
let ldapUsers
|
|
let client
|
|
|
|
try {
|
|
await new Promise((resolve, reject) => {
|
|
client = ldapjs.createClient(ldapConfig)
|
|
client.on('error', (error) => { reject(error) })
|
|
client.on('connectTimeout', (error) => { reject(error) })
|
|
client.on('connect', () => { resolve() })
|
|
})
|
|
|
|
if (starttls) {
|
|
const starttlsAsync = promisify(client.starttls).bind(client)
|
|
await starttlsAsync(tlsOptions, null)
|
|
}
|
|
const bindAsync = promisify(client.bind).bind(client)
|
|
await bindAsync(bindDN, bindCredentials)
|
|
|
|
async function createContactsSearchFilter(client, ldapOptions, userId, contactsFilter) {
|
|
const searchProperty = process.env.OVERLEAF_LDAP_CONTACTS_PROPERTY
|
|
if (!searchProperty) {
|
|
return contactsFilter
|
|
}
|
|
const email = await UserGetter.promises.getUserEmail(userId)
|
|
const searchOptions = {
|
|
scope: ldapOptions.searchScope,
|
|
attributes: [searchProperty],
|
|
filter: `(${Settings.ldap.attEmail}=${email})`
|
|
}
|
|
const searchBase = ldapOptions.searchBase
|
|
const ldapUser = (await _searchLDAP(client, searchBase, searchOptions))[0]
|
|
const searchPropertyValue = ldapUser ? ldapUser[searchProperty]
|
|
: process.env.OVERLEAF_LDAP_CONTACTS_NON_LDAP_VALUE || 'IMATCHNOTHING'
|
|
return contactsFilter.replace(/{{userProperty}}/g, searchPropertyValue)
|
|
}
|
|
|
|
const filter = await createContactsSearchFilter(client, ldapOptions, userId, process.env.OVERLEAF_LDAP_CONTACTS_FILTER)
|
|
const searchOptions = { scope: searchScope, attributes: [attEmail, attFirstName, attLastName, attName], filter }
|
|
|
|
ldapUsers = await _searchLDAP(client, searchBase, searchOptions)
|
|
} catch (error) {
|
|
logger.warn({ error }, 'Error in fetchLDAPContacts')
|
|
return []
|
|
} finally {
|
|
client?.unbind()
|
|
}
|
|
|
|
const newLDAPContacts = ldapUsers.reduce((acc, ldapUser) => {
|
|
const email = Array.isArray(ldapUser[attEmail])
|
|
? ldapUser[attEmail][0]?.toLowerCase()
|
|
: ldapUser[attEmail]?.toLowerCase()
|
|
if (!email) return acc
|
|
if (!contacts.some(contact => contact.email === email)) {
|
|
let nameParts = ["", ""]
|
|
if ((!attFirstName || !attLastName) && attName) {
|
|
nameParts = splitFullName(ldapUser[attName] || "")
|
|
}
|
|
const firstName = attFirstName ? (ldapUser[attFirstName] || "") : nameParts[0]
|
|
const lastName = attLastName ? (ldapUser[attLastName] || "") : nameParts[1]
|
|
acc.push({
|
|
first_name: firstName,
|
|
last_name: lastName,
|
|
email: email,
|
|
type: 'user'
|
|
})
|
|
}
|
|
return acc
|
|
}, [])
|
|
|
|
return newLDAPContacts.sort((a, b) =>
|
|
a.last_name.localeCompare(b.last_name) ||
|
|
a.first_name.localeCompare(b.first_name) ||
|
|
a.email.localeCompare(b.email)
|
|
)
|
|
}
|
|
|
|
export default fetchLDAPContacts
|