fix!: Login services button colors (#33333)

pull/33645/head
Yash Rajpal 1 year ago committed by GitHub
parent 15b6f4b713
commit d44f614d0c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 8
      .changeset/fifty-mails-admire.md
  2. 2
      apps/meteor/app/meteor-accounts-saml/server/lib/settings.ts
  3. 2
      apps/meteor/server/lib/oauth/addOAuthService.ts
  4. 4
      apps/meteor/server/settings/cas.ts
  5. 4
      apps/meteor/server/settings/oauth.ts
  6. 1
      apps/meteor/server/startup/migrations/index.ts
  7. 119
      apps/meteor/server/startup/migrations/v317.ts
  8. 2
      apps/meteor/tests/e2e/page-objects/auth.ts
  9. 7
      apps/meteor/tests/e2e/saml.spec.ts
  10. 9
      apps/meteor/tests/e2e/utils/convertHexToRGB.ts
  11. 1
      packages/i18n/src/locales/en.i18n.json
  12. 4
      packages/web-ui-registration/src/LoginServicesButton.tsx

@ -0,0 +1,8 @@
---
'@rocket.chat/web-ui-registration': patch
"@rocket.chat/meteor": major
---
Login services button was not respecting the button color and text color settings. Implemented a fix to respect these settings and change the button colors accordingly.
Added a warning on all settings which allow admins to change OAuth button colors, so that they can be alerted about WCAG (Web Content Accessibility Guidelines) compliance.

@ -230,10 +230,12 @@ export const addSettings = async function (name: string): Promise<void> {
await this.add(`SAML_Custom_${name}_button_label_color`, '#FFFFFF', {
type: 'string',
i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color',
alert: 'OAuth_button_colors_alert',
});
await this.add(`SAML_Custom_${name}_button_color`, '#1d74f5', {
type: 'string',
i18nLabel: 'Accounts_OAuth_Custom_Button_Color',
alert: 'OAuth_button_colors_alert',
});
});

@ -118,6 +118,7 @@ export async function addOAuthService(name: string, values: { [k: string]: strin
section: `Custom OAuth: ${name}`,
i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
await settingsRegistry.add(`Accounts_OAuth_Custom-${name}-button_color`, values.buttonColor || '#1d74f5', {
type: 'string',
@ -125,6 +126,7 @@ export async function addOAuthService(name: string, values: { [k: string]: strin
section: `Custom OAuth: ${name}`,
i18nLabel: 'Accounts_OAuth_Custom_Button_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
await settingsRegistry.add(`Accounts_OAuth_Custom-${name}-key_field`, values.keyField || 'username', {
type: 'select',

@ -33,8 +33,8 @@ export const createCasSettings = () =>
await this.add('CAS_popup_width', 810, { type: 'int', group: 'CAS', public: true });
await this.add('CAS_popup_height', 610, { type: 'int', group: 'CAS', public: true });
await this.add('CAS_button_label_text', 'CAS', { type: 'string', group: 'CAS' });
await this.add('CAS_button_label_color', '#FFFFFF', { type: 'color', group: 'CAS' });
await this.add('CAS_button_color', '#1d74f5', { type: 'color', group: 'CAS' });
await this.add('CAS_button_label_color', '#FFFFFF', { type: 'color', group: 'CAS', alert: 'OAuth_button_colors_alert' });
await this.add('CAS_button_color', '#1d74f5', { type: 'color', group: 'CAS', alert: 'OAuth_button_colors_alert' });
await this.add('CAS_autoclose', true, { type: 'boolean', group: 'CAS' });
});
});

@ -115,12 +115,14 @@ export const createOauthSettings = () =>
public: true,
i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
await this.add('Accounts_OAuth_Nextcloud_button_color', '#0082c9', {
type: 'string',
public: true,
i18nLabel: 'Accounts_OAuth_Custom_Button_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
});
@ -273,11 +275,13 @@ export const createOauthSettings = () =>
type: 'string',
i18nLabel: 'Accounts_OAuth_Custom_Button_Label_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
await this.add('Accounts_OAuth_Dolphin_button_color', '#1d74f5', {
type: 'string',
i18nLabel: 'Accounts_OAuth_Custom_Button_Color',
persistent: true,
alert: 'OAuth_button_colors_alert',
});
});
await this.section('Facebook', async function () {

@ -22,5 +22,6 @@ import './v313';
import './v314';
import './v315';
import './v316';
import './v317';
export * from './xrun';

@ -0,0 +1,119 @@
import type { ILoginServiceConfiguration, OAuthConfiguration } from '@rocket.chat/core-typings';
import { Settings, LoginServiceConfiguration } from '@rocket.chat/models';
import { isTruthy } from '../../../lib/isTruthy';
import { SystemLogger } from '../../lib/logger/system';
import { addMigration } from '../../lib/migrations';
const newDefaultButtonColor = '#e4e7ea';
const newDefaultButtonLabelColor = '#1f2329';
const settingsToUpdate = [
// button background colors
{ key: 'SAML_Custom_Default_button_color', defaultValue: '#1d74f5', newValue: newDefaultButtonColor },
{ key: 'CAS_button_color', defaultValue: '#1d74f5', newValue: newDefaultButtonColor },
{ key: 'Accounts_OAuth_Nextcloud_button_color', defaultValue: '#0082c9', newValue: newDefaultButtonColor },
{ key: 'Accounts_OAuth_Dolphin_button_color', defaultValue: '#1d74f5', newValue: newDefaultButtonColor },
// button label colors
{ key: 'SAML_Custom_Default_button_label_color', defaultValue: '#1d74f5', newValue: newDefaultButtonLabelColor },
{ key: 'CAS_button_label_color', defaultValue: '#1d74f5', newValue: newDefaultButtonLabelColor },
{ key: 'Accounts_OAuth_Nextcloud_button_label_color', defaultValue: '#1d74f5', newValue: newDefaultButtonLabelColor },
{ key: 'Accounts_OAuth_Dolphin_button_label_color', defaultValue: '#1d74f5', newValue: newDefaultButtonLabelColor },
];
const getSettingValue = async (key: string) => Settings.getValueById(key);
async function updateOAuthServices(): Promise<void> {
const services = await Settings.find({ _id: { $regex: /^(Accounts_OAuth_|Accounts_OAuth_Custom-)[a-z0-9_]+$/i } }).toArray();
const filteredServices = services.filter(({ value }) => typeof value === 'boolean');
for await (const { _id: key, value } of filteredServices) {
if (value !== true) {
continue;
}
let serviceName = key.replace('Accounts_OAuth_', '');
if (serviceName === 'Meteor') {
serviceName = 'meteor-developer';
}
if (/Accounts_OAuth_Custom-/.test(key)) {
serviceName = key.replace('Accounts_OAuth_Custom-', '');
}
const serviceKey = serviceName.toLowerCase();
const data: Partial<ILoginServiceConfiguration & Omit<OAuthConfiguration, '_id'>> = {};
if (/Accounts_OAuth_Custom-/.test(key)) {
data.buttonLabelColor = (await getSettingValue(`${key}-button_label_color`)) as string;
data.buttonColor = (await getSettingValue(`${key}-button_color`)) as string;
}
if (serviceName === 'Nextcloud') {
data.buttonLabelColor = (await getSettingValue('Accounts_OAuth_Nextcloud_button_label_color')) as string;
data.buttonColor = (await getSettingValue('Accounts_OAuth_Nextcloud_button_color')) as string;
}
await LoginServiceConfiguration.createOrUpdateService(serviceKey, data);
}
}
addMigration({
version: 317,
name: 'Change default color of OAuth login services buttons',
async up() {
const promises = settingsToUpdate
.map(async ({ key, defaultValue, newValue }) => {
const oldSettingValue = await getSettingValue(key);
if (!oldSettingValue || oldSettingValue !== defaultValue) {
return;
}
SystemLogger.warn(`The default value of the setting ${key} has changed to ${newValue}. Please review your settings.`);
return Settings.updateOne({ _id: key }, { $set: { value: newValue } });
})
.filter(isTruthy);
await Promise.all(promises);
const customOAuthButtonColors = await Settings.find({
_id: { $regex: /^Accounts_OAuth_Custom-[a-zA-Z0-9_-]+-button_color$/ },
}).toArray();
const customOAuthButtonLabelColors = await Settings.find({
_id: { $regex: /^Accounts_OAuth_Custom-[a-zA-Z0-9_-]+-button_label_color$/ },
}).toArray();
const buttonColorPromises = customOAuthButtonColors
.map(({ _id, value, packageValue }) => {
if (packageValue !== value) {
return;
}
SystemLogger.warn(
`The default value of the custom setting ${_id} has changed to ${newDefaultButtonColor}. Please review your settings.`,
);
return Settings.updateOne({ _id }, { $set: { value: newDefaultButtonColor } });
})
.filter(isTruthy);
const buttonLabelColorPromises = customOAuthButtonLabelColors
.map(({ _id, value, packageValue }) => {
if (packageValue !== value) {
return;
}
SystemLogger.warn(
`The default value of the custom setting ${_id} has changed to ${newDefaultButtonLabelColor}. Please review your settings.`,
);
return Settings.updateOne({ _id }, { $set: { value: newDefaultButtonLabelColor } });
})
.filter(isTruthy);
await Promise.all([...buttonColorPromises, ...buttonLabelColorPromises]);
// update login service configurations
await updateOAuthServices();
},
});

@ -20,7 +20,7 @@ export class Registration {
}
get btnLoginWithSaml(): Locator {
return this.page.locator('role=button[name="SAML"]');
return this.page.locator('role=button[name="SAML test login button"]');
}
get btnLoginWithGoogle(): Locator {

@ -10,6 +10,7 @@ import * as constants from './config/constants';
import { createUserFixture } from './fixtures/collections/users';
import { Users } from './fixtures/userStates';
import { Registration } from './page-objects';
import { convertHexToRGB } from './utils/convertHexToRGB';
import { createCustomRole, deleteCustomRole } from './utils/custom-role';
import { getUserInfo } from './utils/getUserInfo';
import { parseMeteorResponse } from './utils/parseMeteorResponse';
@ -59,6 +60,8 @@ const resetTestData = async ({ api, cleanupOnly = false }: { api?: any; cleanupO
{ _id: 'SAML_Custom_Default_issuer', value: 'http://localhost:3000/_saml/metadata/test-sp' },
{ _id: 'SAML_Custom_Default_entry_point', value: 'http://localhost:8080/simplesaml/saml2/idp/SSOService.php' },
{ _id: 'SAML_Custom_Default_idp_slo_redirect_url', value: 'http://localhost:8080/simplesaml/saml2/idp/SingleLogoutService.php' },
{ _id: 'SAML_Custom_Default_button_label_text', value: 'SAML test login button' },
{ _id: 'SAML_Custom_Default_button_color', value: '#185925' },
];
await Promise.all(settings.map(({ _id, value }) => setSettingValueById(api, _id, value)));
@ -152,6 +155,10 @@ test.describe('SAML', () => {
await expect(poRegistration.btnLoginWithSaml).toBeVisible({ timeout: 10000 });
});
await test.step('expect to have SAML login button to have the required background color', async () => {
await expect(poRegistration.btnLoginWithSaml).toHaveCSS('background-color', convertHexToRGB('#185925'));
});
await test.step('expect to be redirected to the IdP for login', async () => {
await poRegistration.btnLoginWithSaml.click();

@ -0,0 +1,9 @@
export const convertHexToRGB = (hex: string) => {
hex = hex.replace(/^#/, '');
const red = parseInt(hex.substring(0, 2), 16);
const green = parseInt(hex.substring(2, 4), 16);
const blue = parseInt(hex.substring(4, 6), 16);
return `rgb(${red}, ${green}, ${blue})`;
};

@ -4030,6 +4030,7 @@
"OAuth": "OAuth",
"OAuth_Description": "Configure authentication methods beyond just username and password.",
"OAuth_Application": "OAuth Application",
"OAuth_button_colors_alert": "Changing the color may result in non-compliance with WCAG (Web Content Accessibility Guidelines) requirements. Please ensure that the new colors meet the recommended contrast and readability standards to maintain accessibility for all users.",
"Objects": "Objects",
"Off": "Off",
"Off_the_record_conversation": "Off-the-Record Conversation",

@ -15,6 +15,8 @@ const LoginServicesButton = <T extends LoginService>({
className,
disabled,
setError,
buttonColor,
buttonLabelColor,
...props
}: T & {
className?: string;
@ -43,6 +45,8 @@ const LoginServicesButton = <T extends LoginService>({
alignItems='center'
display='flex'
justifyContent='center'
color={buttonLabelColor}
backgroundColor={buttonColor}
>
{buttonLabelText || t('Sign_in_with__provider__', { provider: title })}
</Button>

Loading…
Cancel
Save