Skip to content

Commit

Permalink
Localize expiration timestamps for device assurance grace period (#3703)
Browse files Browse the repository at this point in the history
OKTA-798277 Localize expiration timestamps on client side for device assurance grace period
  • Loading branch information
trevoring-okta authored Sep 4, 2024
1 parent be985b7 commit e3e2ad9
Show file tree
Hide file tree
Showing 19 changed files with 150 additions and 215 deletions.
3 changes: 2 additions & 1 deletion jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,9 @@ module.exports = {
'^LoginRouter$': `${ROOT}/src/LoginRouter`,
},
setupFiles: [
'<rootDir>/test/unit/jest/jest-setup-global.js'
'<rootDir>/test/unit/jest/jest-setup.js'
],
globalSetup: '<rootDir>/test/unit/jest/jest-global-setup.js',
testMatch: [
'**/test/unit/spec/**/*.{js,ts}'
],
Expand Down
4 changes: 1 addition & 3 deletions packages/@okta/i18n/src/properties/login.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1656,9 +1656,7 @@ idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.and

# Device Assurance Grace Period
idx.device_assurance.grace_period.title = Device assurance reminder
# {0} is the number of days until the grace period expires
idx.device_assurance.grace_period.warning.title.due_by_days = Your device doesn't meet the security requirements. Fix the issue within {0} days to prevent lockout.
# {0} is the date that the grace period expires
# {0} is the date that the grace period expires, in Okta short-with-timezone format (e.g. 11/29/2021, 4:15 PM EDT)
idx.device_assurance.grace_period.warning.title.due_by_date = Your device doesn't meet the security requirements. Fix the issue by {0} to prevent lockout.
idx.device_assurance.grace_period.continue_to_app = Continue to app

Expand Down
1 change: 0 additions & 1 deletion packages/@okta/i18n/src/properties/login_ok_PL.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,6 @@ idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.uns
idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required = 》Îñšţåļļ ţĥé Åñðŕöîð Ðéṽîçé Þöļîçý åþþ öñ ţĥîš ðéṽîçé €홝한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ《
idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required_manual_install = 》Ĝö ţö <$1>Šéţţîñĝš îñ Öķţå Ṽéŕîƒý</$1> åñð ƒöļļöŵ ţĥé îñšţŕûçţîöñš ţö îñšţåļļ ţĥé Åñðŕöîð Ðéṽîçé Þöļîçý åþþ โ⾼ئ䀕ヸ€홝한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ《
idx.device_assurance.grace_period.title = 》Ðéṽîçé åššûŕåñçé ŕéɱîñðéŕ 홝한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ《
idx.device_assurance.grace_period.warning.title.due_by_days = 》Ýöûŕ ðéṽîçé ðöéšñ´ţ ɱééţ ţĥé šéçûŕîţý ŕéǫûîŕéɱéñţš· Ƒîẋ ţĥé îššûé ŵîţĥîñ 한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ {0} ðåýš ţö þŕéṽéñţ ļöçķöûţ· 홝한Ӝฐโ《
idx.device_assurance.grace_period.warning.title.due_by_date = 》Ýöûŕ ðéṽîçé ðöéšñ´ţ ɱééţ ţĥé šéçûŕîţý ŕéǫûîŕéɱéñţš· Ƒîẋ ţĥé îššûé ƀý 한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ {0} ţö þŕéṽéñţ ļöçķöûţ· 한Ӝฐโ《
idx.device_assurance.grace_period.continue_to_app = 》Çöñţîñûé ţö åþþ ฐโ⾼ئ䀕ヸ€홝한Ӝฐโ《
api.policy.okta.account.management.insufficient.authenticators.unable.to.sign.in = 》Ûñåƀļé ţö šîĝñ îñ· Çöñţåçţ šûþþöŕţ ƒöŕ åššîšţåñçé· ⾼ئ䀕ヸ€홝한Ӝฐโ⾼ئ䀕ヸ€홝한Ӝฐโ《
1 change: 0 additions & 1 deletion packages/@okta/i18n/src/properties/login_ok_SK.properties
Original file line number Diff line number Diff line change
Expand Up @@ -1248,7 +1248,6 @@ idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.uns
idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required = [[okta-signin-widget:login: idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required]]
idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required_manual_install = [[okta-signin-widget:login: idx.error.code.access_denied.device_assurance.remediation.android.zero.trust.android_device_policy_app_required_manual_install]]
idx.device_assurance.grace_period.title = [[okta-signin-widget:login: idx.device_assurance.grace_period.title]]
idx.device_assurance.grace_period.warning.title.due_by_days = [[okta-signin-widget:login: idx.device_assurance.grace_period.warning.title.due_by_days]]
idx.device_assurance.grace_period.warning.title.due_by_date = [[okta-signin-widget:login: idx.device_assurance.grace_period.warning.title.due_by_date]]
idx.device_assurance.grace_period.continue_to_app = [[okta-signin-widget:login: idx.device_assurance.grace_period.continue_to_app]]
api.policy.okta.account.management.insufficient.authenticators.unable.to.sign.in = [[okta-signin-widget:login: api.policy.okta.account.management.insufficient.authenticators.unable.to.sign.in]]

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"type": "array",
"value": [
{
"message": "Your device doesn't meet the security requirements. Fix the issue by 08/01/2024 to prevent lockout.",
"message": "Your device doesn't meet the security requirements. Fix the issue by 09/05/2024, 12:00 AM UTC to prevent lockout.",
"i18n": {
"key": "idx.device_assurance.grace_period.warning.title.due_by_date",
"params": [
"08/01/2024"
"2024-09-05T00:00:00.000Z"
]
},
"class": "WARNING"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,11 @@
"type": "array",
"value": [
{
"message": "Your device doesn't meet the security requirements. Fix the issue within 7 days to prevent lockout.",
"message": "Your device doesn't meet the security requirements. Fix the issue by 09/05/2024, 12:00 AM UTC to prevent lockout.",
"i18n": {
"key": "idx.device_assurance.grace_period.warning.title.due_by_days",
"key": "idx.device_assurance.grace_period.warning.title.due_by_date",
"params": [
7
"2024-09-05T00:00:00.000Z"
]
},
"class": "WARNING"
Expand Down
33 changes: 33 additions & 0 deletions src/util/TimeUtil.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,4 +93,37 @@ export default {
unit: convertMomentUnits(highestUnit),
};
},

/**
* @method formatDateToDeviceAssuranceGracePeriodExpiryLocaleString
* Conversion from a Date object to a locale string that mimics Okta's `short-with-timezone` format
* but rounded down to the nearest hour
* e.g. new Date(2024-09-05T00:00:00.000Z) -> 09/05/2024, 8:00 PM EDT
*
* @param {Date} date The Date object for the grace period expiry
* @param {LanguageCode} languageCode The user's language code / locale
* @return {string} The formatted `short-with-timezone` local string
*/
formatDateToDeviceAssuranceGracePeriodExpiryLocaleString: (date, languageCode) => {
try {
// Invalid Date objects will return NaN for valueOf()
if (date && !isNaN(date.valueOf()) && languageCode !== null) {
// Round down the date to the nearest hour
date.setMinutes(0, 0, 0);
return date.toLocaleString(languageCode, {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
timeZoneName: 'short',
});
} else {
return null;
}
} catch (e) {
// If `languageCode` isn't in a valid format `toLocaleString()` will throw a `RangeError`
return null;
}
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ const DeviceAssuranceGracePeriodView = BaseForm.extend(

showMessages() {
const messages = this.options.appState.get('messages').value;
const languageCode = this.settings.get('languageCode');
if (messages) {
this.add(createCallout({
content: new EndUserRemediationMessages({ messages }),
content: new EndUserRemediationMessages({ messages, languageCode }),
type: 'warning',
}));
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { View } from '@okta/courage';
import hbs from '@okta/handlebars-inline-precompile';
import { getMessage } from '../../../ion/i18nTransformer';
import TimeUtil from 'util/TimeUtil';
import { loc } from 'util/loc';

const I18N_ACCESS_DENIED_KEY_PREFIX = 'idx.error.code.access_denied.device_assurance.remediation';
const I18N_GRACE_PERIOD_KEY_PREFIX = 'idx.device_assurance.grace_period.warning';
Expand Down Expand Up @@ -72,18 +74,31 @@ export default View.extend({
let explanation = null;
let useCustomHelpText = false;

messages.forEach((message) => {
if (message.i18n.key === ACCESS_DENIED_TITLE_KEY || message.i18n.key.startsWith(GRACE_PERIOD_TITLE_KEY)) {
title = getMessage(message);
} else if (message.i18n.key.startsWith(ACCESS_DENIED_EXPLANATION_KEY_PREFIX)) {
explanation = getMessage(message);
} else if (message.i18n.key.startsWith(HELP_AND_CONTACT_KEY_PREFIX)) {
useCustomHelpText = message.i18n.key === CUSTOM_URL_ADDITIONAL_HELP_KEY;
if (message.links && message.links[0] && message.links[0].url) {
this.additionalHelpUrl = message.links[0].url;
// eslint-disable-next-line complexity
messages.forEach((msg) => {
const { i18n: { key, params = [] }, links, message } = msg;

if (key === ACCESS_DENIED_TITLE_KEY) {
title = getMessage(msg);
} else if (key.startsWith(GRACE_PERIOD_TITLE_KEY)) {
if (params.length > 0) {
const expiry = params[0];
const expiryDate = new Date(expiry);
const localizedExpiry = TimeUtil.formatDateToDeviceAssuranceGracePeriodExpiryLocaleString(
expiryDate,
this.options.languageCode
);
title = localizedExpiry ? loc(key, 'login', [localizedExpiry]) : message;
}
} else if (key.startsWith(ACCESS_DENIED_EXPLANATION_KEY_PREFIX)) {
explanation = getMessage(msg);
} else if (key.startsWith(HELP_AND_CONTACT_KEY_PREFIX)) {
useCustomHelpText = key === CUSTOM_URL_ADDITIONAL_HELP_KEY;
if (links && links[0] && links[0].url) {
this.additionalHelpUrl = links[0].url;
}
} else {
remediationOptions.push(buildRemediationOptionBlockMessage(message));
remediationOptions.push(buildRemediationOptionBlockMessage(msg));
}
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ Object {
},
],
"listStyleType": "disc",
"title": "idx.device_assurance.grace_period.warning.title.due_by_days",
"title": "idx.device_assurance.grace_period.warning.title.due_by_date",
},
Object {
"listStyleType": "disc",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ describe('transformDeviceAssuranceGracePeriod Tests', () => {
beforeEach(() => {
transaction.messages = [
{
message: 'Your device doesn\'t meet the security requirements. Fix the issue within 7 days to prevent lockout.',
message: 'Your device doesn\'t meet the security requirements. Fix the issue by 09/05/2024, 12:00 AM UTC to prevent lockout.',
i18n: {
key: 'idx.device_assurance.grace_period.warning.title.due_by_days',
key: 'idx.device_assurance.grace_period.warning.title.due_by_date',
params: [
7,
'2024-09-05T00:00:00.000Z',
],
},
class: 'ERROR',
Expand Down Expand Up @@ -70,7 +70,7 @@ describe('transformDeviceAssuranceGracePeriod Tests', () => {
formBag,
widgetProps,
});
const remediationMessages = buildEndUserRemediationMessages(transaction.messages!);
const remediationMessages = buildEndUserRemediationMessages(transaction.messages!, 'en');

expect(updatedFormBag.uischema.elements.length).toBe(3);
expect(updatedFormBag).toMatchSnapshot();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,22 @@ import {
InfoboxElement,
TitleElement,
} from '../../../types';
import { buildEndUserRemediationMessages, loc } from '../../../util';
import { buildEndUserRemediationMessages, getLanguageCode, loc } from '../../../util';

export const transformDeviceAssuranceGracePeriod: IdxStepTransformer = ({
formBag,
transaction,
widgetProps,
}) => {
const { uischema } = formBag;
const { messages = [] } = transaction;
const languageCode = getLanguageCode(widgetProps);

// Normally, the transactionMessageTransformer runs after this transformer, but buildEndUserRemediationMessages()
// expects localized transaction messages so we have to call this transformer here.
transactionMessageTransformer(transaction);

const remediationMessages = buildEndUserRemediationMessages(messages);
const remediationMessages = buildEndUserRemediationMessages(messages, languageCode);

const titleElement: TitleElement = {
type: 'Title',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ export const transformOktaVerifyEnrollPoll: IdxStepTransformer = ({

const stepper: StepperLayout = {
type: UISchemaLayoutType.STEPPER,
key: 'stepper_' + channelType,
key: `stepper_${channelType}`,
elements: [
// QR code
{
Expand Down
Loading

0 comments on commit e3e2ad9

Please sign in to comment.