import { Meteor } from 'meteor/meteor'; import { ServiceConfiguration } from 'meteor/service-configuration'; import _ from 'underscore'; import { CustomOAuth } from '../../../custom-oauth'; import { Logger } from '../../../logger'; import { settings } from '../../../settings/server'; import { addOAuthService } from '../functions/addOAuthService'; const logger = new Logger('rocketchat:lib'); function _OAuthServicesUpdate() { const services = settings.getByRegexp(/^(Accounts_OAuth_|Accounts_OAuth_Custom-)[a-z0-9_]+$/i); services .filter(([, value]) => typeof value === 'boolean') .forEach(([key, value]) => { logger.debug({ oauth_updated: key }); let serviceName = key.replace('Accounts_OAuth_', ''); if (serviceName === 'Meteor') { serviceName = 'meteor-developer'; } if (/Accounts_OAuth_Custom-/.test(key)) { serviceName = key.replace('Accounts_OAuth_Custom-', ''); } if (value === true) { const data = { clientId: settings.get(`${key}_id`), secret: settings.get(`${key}_secret`), }; if (/Accounts_OAuth_Custom-/.test(key)) { data.custom = true; data.clientId = settings.get(`${key}-id`); data.secret = settings.get(`${key}-secret`); data.serverURL = settings.get(`${key}-url`); data.tokenPath = settings.get(`${key}-token_path`); data.identityPath = settings.get(`${key}-identity_path`); data.authorizePath = settings.get(`${key}-authorize_path`); data.scope = settings.get(`${key}-scope`); data.accessTokenParam = settings.get(`${key}-access_token_param`); data.buttonLabelText = settings.get(`${key}-button_label_text`); data.buttonLabelColor = settings.get(`${key}-button_label_color`); data.loginStyle = settings.get(`${key}-login_style`); data.buttonColor = settings.get(`${key}-button_color`); data.tokenSentVia = settings.get(`${key}-token_sent_via`); data.identityTokenSentVia = settings.get(`${key}-identity_token_sent_via`); data.keyField = settings.get(`${key}-key_field`); data.usernameField = settings.get(`${key}-username_field`); data.emailField = settings.get(`${key}-email_field`); data.nameField = settings.get(`${key}-name_field`); data.avatarField = settings.get(`${key}-avatar_field`); data.rolesClaim = settings.get(`${key}-roles_claim`); data.groupsClaim = settings.get(`${key}-groups_claim`); data.channelsMap = settings.get(`${key}-groups_channel_map`); data.channelsAdmin = settings.get(`${key}-channels_admin`); data.mergeUsers = settings.get(`${key}-merge_users`); data.mapChannels = settings.get(`${key}-map_channels`); data.mergeRoles = settings.get(`${key}-merge_roles`); data.rolesToSync = settings.get(`${key}-roles_to_sync`); data.showButton = settings.get(`${key}-show_button`); new CustomOAuth(serviceName.toLowerCase(), { serverURL: data.serverURL, tokenPath: data.tokenPath, identityPath: data.identityPath, authorizePath: data.authorizePath, scope: data.scope, loginStyle: data.loginStyle, tokenSentVia: data.tokenSentVia, identityTokenSentVia: data.identityTokenSentVia, keyField: data.keyField, usernameField: data.usernameField, emailField: data.emailField, nameField: data.nameField, avatarField: data.avatarField, rolesClaim: data.rolesClaim, groupsClaim: data.groupsClaim, mapChannels: data.mapChannels, channelsMap: data.channelsMap, channelsAdmin: data.channelsAdmin, mergeUsers: data.mergeUsers, mergeRoles: data.mergeRoles, rolesToSync: data.rolesToSync, accessTokenParam: data.accessTokenParam, showButton: data.showButton, }); } if (serviceName === 'Facebook') { data.appId = data.clientId; delete data.clientId; } if (serviceName === 'Twitter') { data.consumerKey = data.clientId; delete data.clientId; } if (serviceName === 'Linkedin') { data.clientConfig = { requestPermissions: ['r_liteprofile', 'r_emailaddress'], }; } if (serviceName === 'Nextcloud') { data.buttonLabelText = settings.get('Accounts_OAuth_Nextcloud_button_label_text'); data.buttonLabelColor = settings.get('Accounts_OAuth_Nextcloud_button_label_color'); data.buttonColor = settings.get('Accounts_OAuth_Nextcloud_button_color'); } // If there's no data other than the service name, then put the service name in the data object so the operation won't fail const keys = Object.keys(data).filter((key) => data[key] !== undefined); if (!keys.length) { data.service = serviceName.toLowerCase(); } ServiceConfiguration.configurations.upsert( { service: serviceName.toLowerCase(), }, { $set: data, }, ); } else { ServiceConfiguration.configurations.remove({ service: serviceName.toLowerCase(), }); } }); } const OAuthServicesUpdate = _.debounce(Meteor.bindEnvironment(_OAuthServicesUpdate), 2000); function OAuthServicesRemove(_id) { const serviceName = _id.replace('Accounts_OAuth_Custom-', ''); return ServiceConfiguration.configurations.remove({ service: serviceName.toLowerCase(), }); } settings.watchByRegex(/^Accounts_OAuth_.+/, function () { return OAuthServicesUpdate(); // eslint-disable-line new-cap }); settings.watchByRegex(/^Accounts_OAuth_Custom-[a-z0-9_]+/, function (key, value) { if (!value) { return OAuthServicesRemove(key); // eslint-disable-line new-cap } }); function customOAuthServicesInit() { // Add settings for custom OAuth providers to the settings so they get // automatically added when they are defined in ENV variables Object.keys(process.env).forEach((key) => { if (/Accounts_OAuth_Custom_[a-zA-Z0-9_-]+$/.test(key)) { // Most all shells actually prohibit the usage of - in environment variables // So this will allow replacing - with _ and translate it back to the setting name let name = key.replace('Accounts_OAuth_Custom_', ''); if (name.indexOf('_') > -1) { name = name.replace(name.substr(name.indexOf('_')), ''); } const serviceKey = `Accounts_OAuth_Custom_${name}`; if (key === serviceKey) { const values = { enabled: process.env[`${serviceKey}`] === 'true', clientId: process.env[`${serviceKey}_id`], clientSecret: process.env[`${serviceKey}_secret`], serverURL: process.env[`${serviceKey}_url`], tokenPath: process.env[`${serviceKey}_token_path`], identityPath: process.env[`${serviceKey}_identity_path`], authorizePath: process.env[`${serviceKey}_authorize_path`], scope: process.env[`${serviceKey}_scope`], accessTokenParam: process.env[`${serviceKey}_access_token_param`], buttonLabelText: process.env[`${serviceKey}_button_label_text`], buttonLabelColor: process.env[`${serviceKey}_button_label_color`], loginStyle: process.env[`${serviceKey}_login_style`], buttonColor: process.env[`${serviceKey}_button_color`], tokenSentVia: process.env[`${serviceKey}_token_sent_via`], identityTokenSentVia: process.env[`${serviceKey}_identity_token_sent_via`], keyField: process.env[`${serviceKey}_key_field`], usernameField: process.env[`${serviceKey}_username_field`], nameField: process.env[`${serviceKey}_name_field`], emailField: process.env[`${serviceKey}_email_field`], rolesClaim: process.env[`${serviceKey}_roles_claim`], groupsClaim: process.env[`${serviceKey}_groups_claim`], channelsMap: process.env[`${serviceKey}_groups_channel_map`], channelsAdmin: process.env[`${serviceKey}_channels_admin`], mergeUsers: process.env[`${serviceKey}_merge_users`] === 'true', mapChannels: process.env[`${serviceKey}_map_channels`], mergeRoles: process.env[`${serviceKey}_merge_roles`] === 'true', rolesToSync: process.env[`${serviceKey}_roles_to_sync`], showButton: process.env[`${serviceKey}_show_button`] === 'true', avatarField: process.env[`${serviceKey}_avatar_field`], }; addOAuthService(name, values); } } }); } customOAuthServicesInit();