From 4d7c5a2feea9e13b1421a88ee4b893e4117f7cd1 Mon Sep 17 00:00:00 2001 From: Guy Sartorelli Date: Mon, 2 Oct 2023 13:56:44 +1300 Subject: [PATCH] ENH Add field for toggling between everyone and groups --- client/dist/js/bundle-cms.js | 2 +- client/src/legacy/SiteConfig.js | 49 +- src/Extension/SiteConfigExtension.php | 70 +- src/Service/EnforcementManager.php | 33 +- tests/Behat/Context/LoginContext.php | 2 +- tests/Behat/features/mfa-enabled.feature | 40 +- tests/php/Authenticator/LoginHandlerTest.php | 65 +- tests/php/Authenticator/LoginHandlerTest.yml | 9 + tests/php/Service/EnforcementManagerTest.php | 730 ++++++++++++++----- tests/php/Service/EnforcementManagerTest.yml | 9 + 10 files changed, 773 insertions(+), 236 deletions(-) diff --git a/client/dist/js/bundle-cms.js b/client/dist/js/bundle-cms.js index 42b13360..7164a083 100644 --- a/client/dist/js/bundle-cms.js +++ b/client/dist/js/bundle-cms.js @@ -1 +1 @@ -!function(){var e={189:function(e,t,n){"use strict";var o=i(n(460)),r=i(n(7355)),a=i(n(941));function i(e){return e&&e.__esModule?e:{default:e}}window.document.addEventListener("DOMContentLoaded",(()=>{(0,o.default)(),(0,r.default)(),(0,a.default)()}))},460:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=l(n(6648)),r=l(n(440)),a=l(n(6021)),i=l(n(9521));function l(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{(0,i.default)(),o.default.component.registerMany({MFARegister:r.default,RegisteredMFAMethodListField:a.default})}},7355:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(6648)),r=i(n(6683)),a=i(n(4180));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{(0,a.default)(),o.default.reducer.register("mfaAdministration",r.default)}},941:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(n(6648)),r=a(n(3311));function a(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{o.default.transform("apply-sudo-mode-to-mfa",(e=>{e.component("RegisteredMFAMethodListField",r.default)}))}},9521:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(9487)),r=i(n(1284)),a=i(n(6648));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.component.registerMany({BackupCodeRegister:o.default,BackupCodeVerify:r.default})}},4180:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(6648)),r=i(n(7286)),a=i(n(23));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{o.default.reducer.register("mfaRegister",r.default),o.default.reducer.register("mfaVerify",a.default)}},9487:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=s(n(7086)),a=s(n(9768)),i=n(4855),l=n(1661);function s(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends o.Component{constructor(e){super(e),this.state={recentlyCopied:!1},this.printRef=null,this.setPrintRef=e=>{this.printRef=e},this.copyMessageTimeout=null,this.handlePrint=this.handlePrint.bind(this),this.handleCopy=this.handleCopy.bind(this)}getFormattedCodes(){const{codes:e}=this.props;return e.map((e=>(0,l.formatCode)(e)))}handlePrint(e){e.preventDefault(),(new a.default).print(this.printRef,['body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif }'])}handleCopy(e){e.preventDefault();const{copyFeedbackDuration:t}=this.props;this.setState({recentlyCopied:!0}),this.copyMessageTimeout&&clearTimeout(this.copyMessageTimeout),this.copyMessageTimeout=setTimeout((()=>{this.setState({recentlyCopied:!1})}),t)}renderCodes(){return o.default.createElement("pre",{ref:this.setPrintRef,className:"mfa-register-backup-codes__code-grid"},this.getFormattedCodes().map((e=>o.default.createElement("div",{key:e},e))))}renderDescription(){const{ss:{i18n:e}}=window,{method:{supportLink:t,supportText:n}}=this.props;return o.default.createElement("p",null,e._t("MFABackupCodesRegister.DESCRIPTION","Recovery codes enable you to log into your account in the event your primary authentication is not available. Each code can only be used once. Store these codes somewhere safe, as they will not be viewable after leaving this page.")," ",t&&o.default.createElement("a",{href:t,target:"_blank",rel:"noopener noreferrer"},n||e._t("MFARegister.RECOVERY_HELP","Learn more about recovery codes.")))}renderPrintAction(){const{ss:{i18n:e}}=window;return o.default.createElement("button",{type:"button",onClick:this.handlePrint,className:"btn btn-link"},e._t("MFABackupCodesRegister.PRINT","Print codes"))}renderDownloadAction(){const{codes:e,method:t}=this.props,{Blob:n,URL:r,ss:{i18n:a},navigator:i}=window,l=`${t.name}.txt`,s=new n([e.join("\r\n")],{type:"text/plain;charset=UTF-8"}),u=r.createObjectURL(s);return o.default.createElement("a",{download:l,href:u,className:"btn btn-link",onClick:e=>{i.msSaveBlob&&(e.preventDefault(),i.msSaveBlob(s,l))}},a._t("MFABackupCodesRegister.DOWNLOAD","Download"))}renderCopyAction(){const{codes:e}=this.props,{recentlyCopied:t}=this.state,{ss:{i18n:n}}=window,r=t?n._t("MFABackupCodesRegister.COPY_RECENT","Copied!"):n._t("MFABackupCodesRegister.COPY","Copy codes");return o.default.createElement(i.CopyToClipboard,{text:e.join("\n")},o.default.createElement("button",{type:"button",className:"mfa-register-backup-codes__copy-to-clipboard btn btn-link",onClick:this.handleCopy},r))}render(){const{onCompleteRegistration:e}=this.props,{ss:{i18n:t}}=window;return o.default.createElement("div",{className:"mfa-register-backup-codes__container"},this.renderDescription(),this.renderCodes(),o.default.createElement("div",{className:"mfa-register-backup-codes__helper-links"},this.renderPrintAction(),this.renderDownloadAction(),this.renderCopyAction()),o.default.createElement("button",{className:"btn btn-primary",onClick:()=>e()},t._t("MFABackupCodesRegister.FINISH","Finish")))}}c.propTypes={codes:r.default.arrayOf(r.default.string),copyFeedbackDuration:r.default.number},c.defaultProps={copyFeedbackDuration:3e3};var d=c;t.default=d},1284:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=i(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var l=r?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(o,a,l):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=(o=n(7820))&&o.__esModule?o:{default:o};function i(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(i=function(e){return e?n:t})(e)}class l extends r.Component{constructor(e){super(e),this.state={value:""},this.codeInput=r.default.createRef(),this.handleChange=this.handleChange.bind(this),this.handleCompleteVerification=this.handleCompleteVerification.bind(this)}componentDidMount(){this.codeInput.current&&this.codeInput.current.focus()}handleChange(e){this.setState({value:e.target.value})}handleCompleteVerification(e){e.preventDefault();const{onCompleteVerification:t}=this.props;t({code:this.state.value})}renderControls(){const{moreOptionsControl:e}=this.props,{ss:{i18n:t}}=window;return r.default.createElement("ul",{className:"mfa-action-list mfa-action-list--backup-codes"},r.default.createElement("li",{className:"mfa-action-list__item"},r.default.createElement("button",{className:"btn btn-primary",disabled:0===this.state.value.length,onClick:this.handleCompleteVerification},t._t("MFABackupCodesVerify.NEXT","Next"))),e&&r.default.createElement("li",{className:"mfa-action-list__item"},e))}renderDescription(){const{ss:{i18n:e}}=window,{method:t}=this.props;return r.default.createElement("p",null,e._t("MFABackupCodesVerify.DESCRIPTION","Use one of the recovery codes you received")," ",t&&t.supportLink&&r.default.createElement("a",{href:t.supportLink,target:"_blank",rel:"noopener noreferrer"},e._t("MFARegister.RECOVERY_HELP","How to use recovery codes.")))}renderInput(){const{error:e}=this.props,{ss:{i18n:t}}=window,n=t._t("MFABackupCodesVerify.LABEL","Enter recovery code"),o=(0,a.default)("mfa-verify-backup-codes__input-container",{"has-error":!!e});return r.default.createElement("div",{className:o},r.default.createElement("label",{htmlFor:"backup-code",className:"control-label"},n),r.default.createElement("input",{className:"mfa-verify-backup-codes__input text form-control",type:"text",placeholder:n,id:"backup-code",ref:this.codeInput,onChange:this.handleChange}),e&&r.default.createElement("div",{className:"help-block"},e))}render(){const{graphic:e,name:t}=this.props;return r.default.createElement("form",{className:"mfa-verify-backup-codes__container"},r.default.createElement("div",{className:"mfa-verify-backup-codes__content"},this.renderDescription(),this.renderInput()),r.default.createElement("div",{className:"mfa-verify-backup-codes__image-holder"},r.default.createElement("img",{className:"mfa-verify-backup-codes__image",src:e,alt:t})),this.renderControls())}}var s=l;t.default=s},2469:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=h(n(7086)),r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=h(n(4510)),i=h(n(42)),l=h(n(3141)),s=h(n(5292)),u=h(n(1820)),c=h(n(3947)),d=(h(n(5666)),h(n(7462)));function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}function h(e){return e&&e.__esModule?e:{default:e}}class p extends r.Component{constructor(e){super(e),this.state={complete:!1,failed:!1,submitting:!1},this.handleSendReset=this.handleSendReset.bind(this)}async handleSendReset(){const{ss:{i18n:e}}=window,t=e._t("MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION"]),n=e._t("MultiFactorAuthentication.CONFIRMATION_TITLE",d.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=e._t("MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION_BUTTON",d.default["MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION_BUTTON"]);if(!await(0,l.default)({title:n,message:t,confirmText:o}))return;this.setState({submitting:!0});const r=JSON.stringify({csrf_token:a.default.get("SecurityID")});(0,i.default)(this.props.resetEndpoint,"POST",r).then((e=>e.json())).then((e=>{const t=!!e.error;this.setState({complete:!0,failed:t,submitting:!1})})).catch((()=>{this.setState({complete:!0,failed:!0,submitting:!1})}))}renderAction(){const{ss:{i18n:e}}=window,{resetEndpoint:t}=this.props,{complete:n,submitting:o}=this.state;return n||o?null:r.default.createElement("p",{className:"account-reset-action"},r.default.createElement("button",{className:"btn btn-outline-secondary",disabled:!t,onClick:this.handleSendReset,type:"button"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_ACTION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_ACTION"])))}renderSending(){const{ss:{i18n:e}}=window,{LoadingIndicatorComponent:t}=this.props;return r.default.createElement("p",{className:"account-reset-action account-reset-action--sending"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(t,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING"])))}renderFailure(){const{ss:{i18n:e}}=window;return r.default.createElement("p",{className:"account-reset-action account-reset-action--failure"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(u.default,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING_FAILURE"])))}renderSuccess(){const{ss:{i18n:e}}=window;return r.default.createElement("p",{className:"account-reset-action account-reset-action--success"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(c.default,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING_SUCCESS",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING_SUCCESS"])))}renderStatusMessage(){const{complete:e,failed:t,submitting:n}=this.state;return n?this.renderSending():e?t?this.renderFailure():this.renderSuccess():null}render(){const{ss:{i18n:e}}=window;return r.default.createElement("div",{className:"account-reset"},r.default.createElement("h5",{className:"account-reset__title"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_TITLE",d.default["MultiFactorAuthentication.ACCOUNT_RESET_TITLE"])),r.default.createElement("p",{className:"account-reset__description"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_DESCRIPTION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_DESCRIPTION"])),this.renderAction(),this.renderStatusMessage())}}p.propTypes={resetEndpoint:o.default.string,LoadingIndicatorComponent:o.default.oneOfType([o.default.object,o.default.func])},p.defaultProps={LoadingIndicatorComponent:s.default};var m=p;t.default=m},1509:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=h(n(3141)),a=h(n(7086)),i=h(n(7820)),l=h(n(8488)),s=h(n(5695)),u=h(n(2468)),c=h(n(9831)),d=h(n(8628)),f=h(n(7462));function h(e){return e&&e.__esModule?e:{default:e}}function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}class m extends o.PureComponent{getStatusMessage(){const{isBackupMethod:e,isDefaultMethod:t}=this.props,{ss:{i18n:n}}=window;return t?n._t("MultiFactorAuthentication.DEFAULT_REGISTERED",f.default["MultiFactorAuthentication.DEFAULT_REGISTERED"]):e?n._t("MultiFactorAuthentication.BACKUP_REGISTERED",f.default["MultiFactorAuthentication.BACKUP_REGISTERED"]):n._t("MultiFactorAuthentication.REGISTERED",f.default["MultiFactorAuthentication.REGISTERED"])}renderRemove(){const{canRemove:e,method:t,RemoveComponent:n}=this.props;return e?o.default.createElement(n,{method:t}):null}renderReset(){const{canReset:e,isBackupMethod:t,method:n}=this.props;if(!e)return null;const a={method:n};if(t){const{ss:{i18n:e}}=window,t=e._t("MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION",f.default["MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION"]),n=e._t("MultiFactorAuthentication.CONFIRMATION_TITLE",f.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=e._t("MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION_BUTTON",f.default["MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION_BUTTON"]);a.onReset=async e=>{await(0,r.default)({title:n,message:t,confirmText:o})&&e()}}return o.default.createElement(c.default,a)}renderSetAsDefault(){const{isDefaultMethod:e,isBackupMethod:t,method:n,SetDefaultComponent:r}=this.props;return e||t?null:o.default.createElement(r,{method:n})}renderControls(){const{canRemove:e,canReset:t}=this.props;return e||t?o.default.createElement("div",null,this.renderRemove(),this.renderReset(),this.renderSetAsDefault()):null}renderNameAndStatus(){const{method:e,createdDate:t}=this.props,{ss:{i18n:n}}=window,o=this.getStatusMessage();return l.default.locale(n.detectLocale()),n.inject(o,{method:e.name,date:(0,l.default)(t).format("L")})}render(){const{tag:e,className:t}=this.props,n=(0,i.default)(t,"registered-method-list-item");return o.default.createElement(e,{className:n},this.renderNameAndStatus(),this.renderControls())}}m.propTypes={method:s.default.isRequired,isDefaultMethod:a.default.bool,isBackupMethod:a.default.bool,canRemove:a.default.bool,canReset:a.default.bool,onRemove:a.default.func,onReset:a.default.func,createdDate:a.default.string,className:a.default.string,tag:a.default.string,RemoveComponent:a.default.oneOfType([a.default.object,a.default.func]),SetDefaultComponent:a.default.oneOfType([a.default.object,a.default.func])},m.defaultProps={isDefaultMethod:!1,isBackupMethod:!1,canRemove:!1,canReset:!1,tag:"li",RemoveComponent:u.default,SetDefaultComponent:d.default};var E=m;t.default=E},2468:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=h(n(7363)),r=h(n(7086)),a=n(1624),i=h(n(3141)),l=h(n(4510)),s=h(n(42)),u=n(8631),c=n(9861),d=h(n(5695)),f=h(n(7462));function h(e){return e&&e.__esModule?e:{default:e}}const p=(e,t)=>{let{method:n,onRemove:r,defaultMethod:a,registeredMethods:u,onDeregisterMethod:c,onAddAvailableMethod:d,onSetDefaultMethod:h}=e,{backupMethod:p,endpoints:{remove:m}}=t;const{ss:{i18n:E}}=window,M=async()=>{const e=E._t("MultiFactorAuthentication.DELETE_CONFIRMATION",f.default["MultiFactorAuthentication.DELETE_CONFIRMATION"]),t=E._t("MultiFactorAuthentication.CONFIRMATION_TITLE",f.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=E._t("MultiFactorAuthentication.DELETE_CONFIRMATION_BUTTON",f.default["MultiFactorAuthentication.DELETE_CONFIRMATION_BUTTON"]);if(!await(0,i.default)({title:t,message:e,confirmText:o}))return;const r=l.default.get("SecurityID"),M=`${m.replace("{urlSegment}",n.urlSegment)}?SecurityID=${r}`;(0,s.default)(M,"DELETE").then((e=>e.json().then((t=>{if(200===e.status)return c(n),d(t.availableMethod),n.urlSegment===a&&h(null),void(!t.hasBackupMethod&&p&&u.find((e=>e.urlSegment===p.urlSegment))&&c(p));const o=t.errors&&` Errors: \n - ${t.errors.join("\n -")}`||"";throw Error(`Could not delete method. Error code ${e.status}.${o}`)}))))};return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:r?r(M):M},E._t("MultiFactorAuthentication.REMOVE_METHOD",f.default["MultiFactorAuthentication.REMOVE_METHOD"]))};p.propTypes={method:d.default.isRequired,onRemove:r.default.func,defaultMethod:r.default.string.isRequired,registeredMethods:r.default.arrayOf(d.default).isRequired,onDeregisterMethod:r.default.func.isRequired,onAddAvailableMethod:r.default.func.isRequired,onSetDefaultMethod:r.default.func.isRequired},p.contextTypes={backupMethod:d.default,endpoints:r.default.shape({register:r.default.string,remove:r.default.string})};var m=(0,a.connect)((e=>{let{mfaAdministration:{defaultMethod:t,registeredMethods:n}}=e;return{defaultMethod:t,registeredMethods:n}}),(e=>({onDeregisterMethod:t=>{e((0,c.deregisterMethod)(t))},onAddAvailableMethod:t=>{e((0,u.addAvailableMethod)(t))},onSetDefaultMethod:t=>e((0,c.setDefaultMethod)(t))})))(p);t.default=m},9831:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=h(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=f(n(7086)),a=n(1624),i=n(440),l=n(8631),s=f(n(5695)),u=f(n(2949)),c=f(n(7442)),d=f(n(7462));function f(e){return e&&e.__esModule?e:{default:e}}function h(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(h=function(e){return e?n:t})(e)}class p extends o.Component{constructor(e){super(e),this.state={modalOpen:!1},this.handleReset=this.handleReset.bind(this),this.handleToggleModal=this.handleToggleModal.bind(this)}handleToggleModal(){this.setState((e=>({modalOpen:!e.modalOpen})))}handleReset(){const{onResetMethod:e,method:t}=this.props,{allAvailableMethods:n}=this.context,o=n.find((e=>e.urlSegment===t.urlSegment));if(!o)throw Error(`Cannot register the method given: ${t.name} (${t.urlSegment}).`);e(o),this.handleToggleModal()}render(){const{onReset:e}=this.props,{backupMethod:t,endpoints:n,resources:r}=this.context,a=e?()=>e(this.handleReset):this.handleReset;return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:a},window.ss.i18n._t("MultiFactorAuthentication.RESET_METHOD",d.default["MultiFactorAuthentication.RESET_METHOD"]),o.default.createElement(c.default,{backupMethod:t,isOpen:this.state.modalOpen,toggle:this.handleToggleModal,resources:r,endpoints:n,disallowedScreens:[i.SCREEN_CHOOSE_METHOD,i.SCREEN_INTRODUCTION]}))}}p.propTypes={method:s.default.isRequired,onReset:r.default.func},p.contextTypes={allAvailableMethods:r.default.arrayOf(u.default),backupMethod:s.default,endpoints:r.default.shape({register:r.default.string}),resources:r.default.object};var m=(0,a.connect)(null,(e=>({onResetMethod:t=>{e((0,l.chooseMethod)(t)),e((0,l.showScreen)(i.SCREEN_REGISTER_METHOD))}})))(p);t.default=m},8628:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=d(n(7086)),a=d(n(5695)),i=d(n(4510)),l=n(1624),s=d(n(42)),u=n(9861),c=d(n(7462));function d(e){return e&&e.__esModule?e:{default:e}}function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}class h extends o.Component{constructor(e){super(e),this.handleSetDefault=this.handleSetDefault.bind(this)}handleSetDefault(){const{method:e,onSetDefaultMethod:t}=this.props,{endpoints:{setDefault:n}}=this.context,o=i.default.get("SecurityID"),r=`${n.replace("{urlSegment}",e.urlSegment)}?SecurityID=${o}`;(0,s.default)(r,"PUT").then((n=>n.json().then((o=>{if(200===n.status)return void t(e.urlSegment);const r=o.errors&&` Errors: \n - ${o.errors.join("\n -")}`||"";throw Error(`Could not set default method. Error code ${n.status}.${r}`)}))))}render(){const{ss:{i18n:e}}=window;return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:this.handleSetDefault},e._t("MultiFactorAuthentication.SET_AS_DEFAULT",c.default["MultiFactorAuthentication.SET_AS_DEFAULT"]))}}t.Component=h,h.propTypes={method:a.default.isRequired},h.contextTypes={endpoints:r.default.shape({setDefault:r.default.string})};var p=(0,l.connect)(null,(e=>({onSetDefaultMethod:t=>e((0,u.setDefaultMethod)(t))})))(h);t.default=p},6021:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=_(n(7086)),r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=M(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=n(8127),i=n(1624),l=_(n(7820)),s=_(n(5695)),u=_(n(2949)),c=n(8631),d=n(9861),f=n(440),h=_(n(1509)),p=_(n(2469)),m=_(n(7442)),E=_(n(7462));function M(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(M=function(e){return e?n:t})(e)}function _(e){return e&&e.__esModule?e:{default:e}}class g extends r.Component{constructor(e){super(e),this.state={modalOpen:!1},this.handleToggleModal=this.handleToggleModal.bind(this)}getChildContext(){const{allAvailableMethods:e,backupMethod:t,endpoints:n,resources:o}=this.props;return{allAvailableMethods:e,backupMethod:t,endpoints:n,resources:o}}componentDidMount(){const{onSetDefaultMethod:e,initialDefaultMethod:t,onSetRegisteredMethods:n,initialRegisteredMethods:o,onUpdateAvailableMethods:r,initialAvailableMethods:a}=this.props;n(o),r(a),e(t)}getBaseMethods(){const{backupMethod:e}=this.props;let{registeredMethods:t}=this.props;return t?(e&&(t=t.filter((t=>t.urlSegment!==e.urlSegment))),t):[]}handleToggleModal(){this.setState((e=>({modalOpen:!e.modalOpen})))}renderNoMethodsMessage(){if(this.getBaseMethods().length)return null;const{readOnly:e}=this.props,{ss:{i18n:t}}=window,n=e?"MultiFactorAuthentication.NO_METHODS_REGISTERED_READONLY":"MultiFactorAuthentication.NO_METHODS_REGISTERED";return r.default.createElement("div",{className:"registered-mfa-method-list-field__no-methods"},t._t(n,E.default[n]))}renderBackupMethod(){const{backupMethod:e,backupCreatedDate:t,registeredMethods:n,readOnly:o,MethodListItemComponent:a}=this.props;if(!e)return null;const i=n.find((t=>t.urlSegment===e.urlSegment));return i?r.default.createElement(a,{method:i,createdDate:t,canReset:!o,isBackupMethod:!0,tag:"div",className:"registered-method-list-item--backup"}):null}renderBaseMethods(){const{isMFARequired:e}=this.props,t=this.getBaseMethods();if(!t.length)return[];const{defaultMethod:n,readOnly:o,MethodListItemComponent:a}=this.props;return t.map((i=>{const l={method:i,key:i.urlSegment,isDefaultMethod:n&&i.urlSegment===n,canRemove:!(o||e&&1===t.length),canReset:!o};return r.default.createElement(a,l)}))}renderModal(){const{backupMethod:e,endpoints:t,resources:n,RegisterModalComponent:o}=this.props;return r.default.createElement(o,{backupMethod:e,isOpen:this.state.modalOpen,toggle:this.handleToggleModal,resources:n,endpoints:t,disallowedScreens:[f.SCREEN_INTRODUCTION]})}renderAddButton(){const{availableMethods:e,registeredMethods:t,readOnly:n,onResetRegister:o}=this.props;if(n||!e||0===e.length)return null;const{ss:{i18n:i}}=window,l=t.length?i._t("MultiFactorAuthentication.ADD_ANOTHER_METHOD",E.default["MultiFactorAuthentication.ADD_ANOTHER_METHOD"]):i._t("MultiFactorAuthentication.ADD_FIRST_METHOD",E.default["MultiFactorAuthentication.ADD_FIRST_METHOD"]);return r.default.createElement(a.Button,{className:"registered-mfa-method-list-field__button",outline:!0,type:"button",onClick:()=>{this.handleToggleModal(),o()}},l)}render(){const{readOnly:e,resetEndpoint:t}=this.props,n=(0,l.default)({"registered-mfa-method-list-field":!0,"registered-mfa-method-list-field--read-only":e});return r.default.createElement("div",{className:n},r.default.createElement("ul",{className:"method-list"},this.renderBaseMethods()),this.renderNoMethodsMessage(),this.renderAddButton(),this.renderBackupMethod(),e&&r.default.createElement("hr",null),e&&r.default.createElement(p.default,{resetEndpoint:t}),this.renderModal())}}t.Component=g,g.propTypes={backupMethod:s.default,defaultMethod:o.default.string,readOnly:o.default.bool,isMFARequired:o.default.bool,initialDefaultMethod:o.default.string,initialRegisteredMethods:o.default.arrayOf(s.default),initialAvailableMethods:o.default.arrayOf(u.default),allAvailableMethods:o.default.arrayOf(u.default),resetEndpoint:o.default.string,endpoints:o.default.shape({register:o.default.string,remove:o.default.string}),resources:o.default.object,availableMethods:o.default.arrayOf(u.default),registeredMethods:o.default.arrayOf(s.default),registrationScreen:o.default.number,MethodListItemComponent:o.default.oneOfType([o.default.object,o.default.func]),RegisterModalComponent:o.default.oneOfType([o.default.object,o.default.func])},g.defaultProps={initialAvailableMethods:[],MethodListItemComponent:h.default,RegisterModalComponent:m.default},g.childContextTypes={allAvailableMethods:o.default.arrayOf(u.default),backupMethod:s.default,endpoints:o.default.shape({register:o.default.string,remove:o.default.string,setDefault:o.default.string}),resources:o.default.object};var y=(0,i.connect)((e=>{const{availableMethods:t,screen:n}=e.mfaRegister,{defaultMethod:o,registeredMethods:r}=e.mfaAdministration;return{availableMethods:t,defaultMethod:o,registeredMethods:r||[],registrationScreen:n}}),(e=>({onResetRegister:()=>{e((0,c.chooseMethod)(null)),e((0,c.showScreen)(f.SCREEN_CHOOSE_METHOD))},onUpdateAvailableMethods:t=>{e((0,c.setAvailableMethods)(t))},onSetDefaultMethod:t=>{e((0,d.setDefaultMethod)(t))},onSetRegisteredMethods:t=>{e((0,d.setRegisteredMethods)(t))}})))(g);t.default=y},1820:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7363))&&o.__esModule?o:{default:o};t.default=e=>{let{color:t="currentColor",size:n="3em"}=e;return r.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:n,width:n},r.default.createElement("g",{fill:t},r.default.createElement("path",{d:"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"})))}},3947:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7363))&&o.__esModule?o:{default:o};t.default=e=>{let{color:t="currentColor",size:n="3em"}=e;return r.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:n,width:n},r.default.createElement("g",{fill:t},r.default.createElement("path",{d:"M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"})))}},5292:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(n(7363)),r=a(n(7820));function a(e){return e&&e.__esModule?e:{default:e}}t.default=e=>{let{block:t=!1,size:n="6em"}=e;return o.default.createElement("div",{style:{height:n,width:n},className:(0,r.default)({"mfa-loading-indicator":!0,"mfa-loading-indicator--block":t})})}},440:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.SCREEN_REGISTER_METHOD=t.SCREEN_INTRODUCTION=t.SCREEN_COMPLETE=t.SCREEN_CHOOSE_METHOD=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=M(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=E(n(7086)),a=E(n(42)),i=n(6648),l=E(n(2949)),s=E(n(5695)),u=E(n(5292)),c=E(n(6910)),d=E(n(3954)),f=E(n(1824)),h=n(1624),p=n(8631),m=E(n(1196));function E(e){return e&&e.__esModule?e:{default:e}}function M(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(M=function(e){return e?n:t})(e)}function _(){return _=Object.assign?Object.assign.bind():function(e){for(var t=1;te.json().then((e=>{const{SecurityID:t,...n}=e;this.setState({registerProps:n,token:t})}))))}handleBack(){const{availableMethods:e,onShowIntroduction:t,onShowChooseMethod:n}=this.props;return 1===e.length&&t?t():(this.setState({registerProps:null}),n())}handleCompleteRegistration(e){const{endpoints:{register:t},selectedMethod:n,onRemoveAvailableMethod:o,onRegister:r}=this.props,{token:i}=this.state,l=i?`?SecurityID=${i}`:"";(0,a.default)(`${t.replace("{urlSegment}",n.urlSegment)}${l}`,"POST",JSON.stringify(e)).then((e=>201===e.status?(this.setState({registerProps:null}),"function"==typeof r&&r(n),o(n),this.setupBackupMethod(),null):e.json())).then((e=>{if(e&&e.errors){const t=e.errors.join(", ");this.setState((e=>({registerProps:{...e.registerProps,error:t}})))}}))}shouldSetupBackupMethod(){const{backupMethod:e,registeredMethods:t}=this.props;return!!e&&!t.find((t=>t.urlSegment===e.urlSegment))}handleSkip(){const{skip:e}=this.props.endpoints;e&&(window.location=this.props.endpoints.skip)}renderIntroduction(){const{canSkip:e,resources:t,endpoints:{skip:n},showSubTitle:r,IntroductionComponent:a}=this.props;return o.default.createElement(a,{canSkip:n&&e,onSkip:this.handleSkip,resources:t,showTitle:r})}renderMethod(){const{selectedMethod:e,showSubTitle:t,TitleComponent:n}=this.props,{registerProps:r}=this.state;if(!e)return null;if(!r)return o.default.createElement(u.default,{block:!0});const a=(0,i.loadComponent)(e.component);return o.default.createElement("div",null,t&&o.default.createElement(n,null),o.default.createElement(a,_({},r,{method:e,onBack:this.handleBack,onCompleteRegistration:this.handleCompleteRegistration})))}renderOptions(){const{availableMethods:e,showSubTitle:t,SelectMethodComponent:n}=this.props;return o.default.createElement(n,{methods:e,showTitle:t})}render(){const{screen:e,onCompleteRegistration:t,showTitle:n,showSubTitle:r,completeMessage:a,CompleteComponent:i}=this.props,{ss:{i18n:l}}=window;if(4===e)return o.default.createElement(i,{showTitle:r,onComplete:t,message:a});let s;switch(e){case 3:s=this.renderOptions();break;case 2:s=this.renderMethod();break;default:s=this.renderIntroduction()}return o.default.createElement("div",null,n&&o.default.createElement("h1",{className:"mfa-app-title"},l._t("MFARegister.TITLE","Multi-factor authentication")),s)}}t.Component=g,g.propTypes={availableMethods:r.default.arrayOf(l.default),backupMethod:l.default,canSkip:r.default.bool,endpoints:r.default.shape({register:r.default.string.isRequired,skip:r.default.string}),onRegister:r.default.func,onCompleteRegistration:r.default.func.isRequired,registeredMethods:r.default.arrayOf(s.default),resources:r.default.object,showTitle:r.default.bool,showSubTitle:r.default.bool,IntroductionComponent:r.default.oneOfType([r.default.object,r.default.func]),SelectMethodComponent:r.default.oneOfType([r.default.object,r.default.func]),CompleteComponent:r.default.oneOfType([r.default.object,r.default.func]),TitleComponent:r.default.oneOfType([r.default.object,r.default.func])},g.defaultProps={resources:{},showTitle:!0,showSubTitle:!0,showIntroduction:!0,IntroductionComponent:c.default,SelectMethodComponent:f.default,CompleteComponent:d.default,TitleComponent:m.default};var y=(0,h.connect)((e=>{const t=e.mfaRegister||e;return{screen:t.screen,selectedMethod:t.method,availableMethods:t.availableMethods}}),(e=>({onShowIntroduction:()=>e((0,p.showScreen)(1)),onShowComplete:()=>e((0,p.showScreen)(4)),onSelectMethod:t=>e((0,p.chooseMethod)(t)),onShowChooseMethod:()=>{e((0,p.chooseMethod)(null)),e((0,p.showScreen)(3))},onRemoveAvailableMethod:t=>e((0,p.removeAvailableMethod)(t))})))(g);t.default=y},3954:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(7363)),r=i(n(7086)),a=i(n(1196));function i(e){return e&&e.__esModule?e:{default:e}}const l=e=>{let{onComplete:t,showTitle:n,message:r}=e;return o.default.createElement("div",{className:"mfa-register-confirmation"},o.default.createElement("i",{className:"font-icon-check-mark mfa-register-confirmation__icon"}),n&&o.default.createElement(a.default,{className:"mfa-register-confirmation__title"}),o.default.createElement("p",{className:"mfa-register-confirmation__description"},r||window.ss.i18n._t("MFARegister.SETUP_COMPLETE_DESCRIPTION","You will be able to edit these settings later from your profile area.")),o.default.createElement("button",{onClick:t,className:"mfa-register-confirmation__continue btn btn-primary"},window.ss.i18n._t("MFARegister.SETUP_COMPLETE_CONTINUE","Continue")))};l.propTypes={onComplete:r.default.func.isRequired,showTitle:r.default.bool},l.defaultProps={showTitle:!0};var s=l;t.default=s},6910:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=t.ActionList=void 0;var o=c(n(7363)),r=c(n(7086)),a=n(8631),i=n(1624),l=n(440),s=c(n(1196)),u=c(n(7462));function c(e){return e&&e.__esModule?e:{default:e}}const d=e=>{let{canSkip:t,onContinue:n,onSkip:r}=e;const{ss:{i18n:a}}=window;return o.default.createElement("ul",{className:"mfa-action-list"},o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-primary",onClick:n},a._t("MultiFactorAuthentication.GET_STARTED",u.default["MultiFactorAuthentication.GET_STARTED"]))),t&&o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-secondary",onClick:r},a._t("MultiFactorAuthentication.SETUP_LATER",u.default["MultiFactorAuthentication.SETUP_LATER"]))))};t.ActionList=d;const f=e=>{let{canSkip:t,onContinue:n,onSkip:r,resources:a,showTitle:i,TitleComponent:l}=e;const{ss:{i18n:s}}=window;return o.default.createElement("div",null,i&&o.default.createElement(l,null),o.default.createElement("h4",{className:"mfa-feature-list-title"},s._t("MultiFactorAuthentication.HOW_IT_WORKS",u.default["MultiFactorAuthentication.HOW_IT_WORKS"])),o.default.createElement("ul",{className:"mfa-feature-list"},o.default.createElement("li",{className:"mfa-feature-list-item"},a.extra_factor_image_url&&o.default.createElement("img",{alt:s._t("MultiFactorAuthentication.EXTRA_LAYER_IMAGE_ALT",u.default["MultiFactorAuthentication.EXTRA_LAYER_IMAGE_ALT"]),"aria-hidden":"true",className:"mfa-feature-list-item__icon",src:a.extra_factor_image_url}),o.default.createElement("div",{className:"mfa-feature-list-item__content"},o.default.createElement("h5",{className:"mfa-block-heading mfa-feature-list-item__title"},s._t("MultiFactorAuthentication.EXTRA_LAYER_TITLE",u.default["MultiFactorAuthentication.EXTRA_LAYER_TITLE"])),o.default.createElement("p",{className:"mfa-feature-list-item__description"},s._t("MultiFactorAuthentication.EXTRA_LAYER_DESCRIPTION",u.default["MultiFactorAuthentication.EXTRA_LAYER_DESCRIPTION"])," ",a.user_help_link&&o.default.createElement("a",{href:a.user_help_link},s._t("MultiFactorAuthentication.HOW_MFA_WORKS",u.default["MultiFactorAuthentication.HOW_MFA_WORKS"]))))),o.default.createElement("li",{className:"mfa-feature-list-item"},a.unique_image_url&&o.default.createElement("img",{alt:s._t("MultiFactorAuthentication.UNIQUE_IMAGE_ALT",u.default["MultiFactorAuthentication.UNIQUE_IMAGE_ALT"]),"aria-hidden":"true",className:"mfa-feature-list-item__icon",src:a.unique_image_url}),o.default.createElement("div",{className:"mfa-feature-list-item__content"},o.default.createElement("h5",{className:"mfa-block-heading mfa-feature-list-item__title"},s._t("MultiFactorAuthentication.UNIQUE_TITLE",u.default["MultiFactorAuthentication.UNIQUE_TITLE"])),o.default.createElement("p",{className:"mfa-feature-list-item__description"},s._t("MultiFactorAuthentication.UNIQUE_DESCRIPTION",u.default["MultiFactorAuthentication.UNIQUE_DESCRIPTION"]))))),o.default.createElement(d,{canSkip:t,onContinue:n,onSkip:r}))};t.Component=f,f.propTypes={canSkip:r.default.bool,onContinue:r.default.func.isRequired,onSkip:r.default.func,resources:r.default.shape({user_help_link:r.default.string,extra_factor_image_url:r.default.string,unique_image_url:r.default.string}).isRequired,showTitle:r.default.bool,TitleComponent:r.default.oneOfType([r.default.object,r.default.func])},f.defaultProps={showTitle:!0,TitleComponent:s.default};var h=(0,i.connect)(null,(e=>({onContinue:()=>{e((0,a.chooseMethod)(null)),e((0,a.showScreen)(l.SCREEN_REGISTER_METHOD))}})))(f);t.default=h},3324:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=s(n(7086)),a=s(n(7820)),i=s(n(2949)),l=s(n(639));function s(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends o.Component{constructor(e){super(e),this.handleClick=this.handleClick.bind(this),this.handleKeyUp=this.handleKeyUp.bind(this)}handleClick(e){const{method:{isAvailable:t},onClick:n}=this.props;t&&n&&n(e)}handleKeyUp(e){13===e.keyCode&&this.handleClick(e)}renderSupportLink(e){const{ss:{i18n:t}}=window,{supportLink:n,supportText:r}=e;return n?o.default.createElement("a",{href:n,target:"_blank",rel:"noopener noreferrer",className:"mfa-method-tile__support-link"},r||t._t("MFARegister.HELP","Find out more.")):null}renderUnavailableMask(){const{ss:{i18n:e}}=window,{isAvailable:t,getUnavailableMessage:n}=this.props;if(t())return null;const r=n();return o.default.createElement("div",{className:"mfa-method-tile__unavailable-mask"},o.default.createElement("h3",{className:"mfa-method-tile__unavailable-title"},e._t("MFAMethodTile.UNAVAILABLE","Unsupported: ")),r&&o.default.createElement("p",{className:"mfa-method-tile__unavailable-text"},r))}render(){const{isActive:e,method:t}=this.props,{ss:{i18n:n}}=window,r=(0,a.default)("mfa-method-tile",{"mfa-method-tile--active":e,"mfa-method-tile--unsupported":!t.isAvailable}),i=(0,a.default)("mfa-method-tile__thumbnail-container",{"mfa-method-tile__thumbnail-container--unsupported":!t.isAvailable}),l=n.inject(n._t("MFARegister.REGISTER_WITH","Register with {method}"),{method:t.name.toLowerCase()});return o.default.createElement("li",{className:r},o.default.createElement("div",{className:"mfa-method-tile__content",onClick:this.handleClick,onKeyUp:this.handleKeyUp,tabIndex:"0",role:"button"},t.thumbnail&&o.default.createElement("div",{className:i},o.default.createElement("img",{src:t.thumbnail,className:"mfa-method-tile__thumbnail",alt:t.name})),o.default.createElement("h3",{className:"mfa-method-tile__title"},l),o.default.createElement("p",{className:"mfa-method-tile__description"},t.description&&`${t.description}. `,this.renderSupportLink(t))),this.renderUnavailableMask())}}t.Component=c,c.propTypes={getUnavailableMessage:r.default.func.isRequired,isActive:r.default.bool,isAvailable:r.default.func.isRequired,method:i.default.isRequired,onClick:r.default.func.isRequired},c.defaultProps={isActive:!1};var d=(0,l.default)(c);t.default=d},1824:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=m(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=p(n(7086)),a=p(n(2949)),i=p(n(7820)),l=n(8631),s=n(2827),u=n(1624),c=p(n(639)),d=n(440),f=p(n(3324)),h=p(n(1196));function p(e){return e&&e.__esModule?e:{default:e}}function m(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(m=function(e){return e?n:t})(e)}class E extends o.Component{constructor(e){super(e);let t=null;1===e.methods.length&&e.isAvailable&&e.isAvailable(e.methods[0])&&(t=e.methods[0]),this.state={highlightedMethod:t},this.handleGoToNext=this.handleGoToNext.bind(this),this.handleBack=this.handleBack.bind(this)}componentDidMount(){const{highlightedMethod:e}=this.state;e&&this.handleGoToNext()}handleGoToNext(){const{highlightedMethod:e}=this.state;this.props.onSelectMethod(e)}handleClick(e){this.setState({highlightedMethod:e})}handleBack(){this.props.onClickBack&&this.props.onClickBack()}renderActions(){const{ss:{i18n:e}}=window,{highlightedMethod:t}=this.state;return o.default.createElement("ul",{className:"mfa-action-list"},o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-primary",disabled:null===t,onClick:this.handleGoToNext},e._t("MFARegister.NEXT","Next"))),o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-secondary",onClick:this.handleBack},e._t("MFARegister.BACK","Back"))))}render(){const{methods:e,showTitle:t,TitleComponent:n,MethodTileComponent:r}=this.props,{highlightedMethod:a}=this.state,l=(0,i.default)("mfa-method-tile-group",{"mfa-method-tile-group--three-columns":e.length%3==0});return o.default.createElement("div",null,t&&o.default.createElement(n,null),o.default.createElement("ul",{className:l},e.map((e=>o.default.createElement(r,{isActive:a===e,key:e.urlSegment,method:e,onClick:()=>this.handleClick(e)})))),this.renderActions())}}t.Component=E,E.propTypes={methods:r.default.arrayOf(a.default),onSelectMethod:r.default.func,onClickBack:r.default.func,showTitle:r.default.bool,TitleComponent:r.default.oneOfType([r.default.object,r.default.func]),MethodTileComponent:r.default.oneOfType([r.default.object,r.default.func])},E.defaultProps={showTitle:!0,TitleComponent:h.default,MethodTileComponent:f.default};var M=(0,s.compose)((0,u.connect)(null,(e=>({onClickBack:()=>e((0,l.showScreen)(d.SCREEN_INTRODUCTION)),onSelectMethod:t=>{e((0,l.chooseMethod)(t)),e((0,l.showScreen)(d.SCREEN_REGISTER_METHOD))}}))),c.default)(E);t.default=M},1196:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=l(n(7363)),r=n(1624),a=n(440),i=l(n(7462));function l(e){return e&&e.__esModule?e:{default:e}}const s=e=>{let{screen:t,method:n,Tag:r="h2",className:l="mfa-section-title"}=e;const{ss:{i18n:s}}=window;let u;switch(t){case a.SCREEN_INTRODUCTION:u=s._t("MultiFactorAuthentication.TITLE",i.default["MultiFactorAuthentication.TITLE"]);break;case a.SCREEN_CHOOSE_METHOD:u=s._t("MultiFactorAuthentication.SELECT_METHOD",i.default["MultiFactorAuthentication.SELECT_METHOD"]);break;case a.SCREEN_COMPLETE:u=s._t("MultiFactorAuthentication.SETUP_COMPLETE_TITLE",i.default["MultiFactorAuthentication.SETUP_COMPLETE_TITLE"]);break;case a.SCREEN_REGISTER_METHOD:u=n&&s.inject(s._t("MFARegister.REGISTER_WITH","Register with {method}"),{method:n.name.toLowerCase()});break;default:u=!1}if(!u||!u.length)return null;const c=r||"span";return o.default.createElement(c,{className:l},u)};t.Component=s;var u=(0,r.connect)((e=>{const t=e.mfaRegister||e;return{screen:t.screen,method:t.method}}))(s);t.default=u},7442:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=m(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=p(n(7086)),a=n(8127),i=n(6648),l=n(2827),s=n(1624),u=p(n(1196)),c=n(9861),d=p(n(5695)),f=n(440),h=p(n(7462));function p(e){return e&&e.__esModule?e:{default:e}}function m(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(m=function(e){return e?n:t})(e)}class E extends o.Component{constructor(e){super(e),this.handleRegister=this.handleRegister.bind(this)}componentDidUpdate(){const{disallowedScreens:e,isOpen:t,registrationScreen:n,toggle:o}=this.props;t&&e.length&&e.includes(n)&&o()}handleRegister(e){const{onAddRegisteredMethod:t,onSetDefaultMethod:n,registeredMethods:o}=this.props;o.length||n(e.urlSegment),t(e)}render(){const{backupMethod:e,endpoints:t,isOpen:n,toggle:r,registeredMethods:i,registrationScreen:l,resources:s,RegisterComponent:c}=this.props;return o.default.createElement(a.Modal,{isOpen:n,toggle:r,className:"registered-mfa-method-list-field-register-modal"},o.default.createElement(a.ModalHeader,{toggle:r},o.default.createElement(u.default,{Tag:null})),o.default.createElement(a.ModalBody,{className:"registered-mfa-method-list-field-register-modal__content"},l!==f.SCREEN_INTRODUCTION&&o.default.createElement(c,{backupMethod:e,registeredMethods:i,onCompleteRegistration:r,onRegister:this.handleRegister,resources:s,endpoints:t,showTitle:!1,showSubTitle:!1,completeMessage:window.ss.i18n._t("MultiFactorAuthentication.ADMIN_SETUP_COMPLETE_CONTINUE",h.default["MultiFactorAuthentication.ADMIN_SETUP_COMPLETE_CONTINUE"])})))}}t.Component=E,E.propTypes={isOpen:r.default.bool,toggle:r.default.func,disallowedScreens:r.default.arrayOf(r.default.number),backupMethod:d.default,resources:r.default.object,endpoints:r.default.shape({register:r.default.string}),registrationScreen:r.default.number,registeredMethods:r.default.arrayOf(d.default),onAddRegisteredMethod:r.default.func,onSetDefaultMethod:r.default.func,RegisterComponent:r.default.oneOfType([r.default.element,r.default.func,r.default.elementType])},E.defaultProps={isOpen:!1,disallowedScreens:[]};var M=(0,l.compose)((0,i.inject)(["MFARegister"],(e=>({RegisterComponent:e})),(()=>"MFARegisterModal")),(0,s.connect)((e=>({registrationScreen:e.mfaRegister.screen,registeredMethods:e.mfaAdministration.registeredMethods})),(e=>({onAddRegisteredMethod:t=>{e((0,c.registerMethod)(t))},onSetDefaultMethod:t=>e((0,c.setDefaultMethod)(t))}))))(E);t.default=M},830:function(e,t,n){"use strict";var o,r=(o=n(7363))&&o.__esModule?o:{default:o},a=n(9691),i=n(6648);window.jQuery.entwine("ss",(e=>{e('.js-injector-boot [data-field-type="registered-mfa-method-list-field"]').entwine({ReactRoot:null,onmatch(){const e=(0,i.loadComponent)("RegisteredMFAMethodListField"),{readOnly:t,schema:{backupMethod:n,defaultMethod:o,registeredMethods:l,availableMethods:s,allAvailableMethods:u,resources:c,endpoints:d,backupCreatedDate:f,resetEndpoint:h,isMFARequired:p}}=this.data("schema");let m=this.getReactRoot();m||(m=(0,a.createRoot)(this[0]),this.setReactRoot(m)),m.render(r.default.createElement(e,{backupMethod:n,readOnly:t,initialDefaultMethod:o,initialRegisteredMethods:l,initialAvailableMethods:s,allAvailableMethods:u,resources:c,endpoints:d,backupCreatedDate:f,resetEndpoint:h,isMFARequired:p}))},onunmatch(){const e=this.getReactRoot();e&&(e.unmount(),this.setReactRoot(null))}})}))},6388:function(){"use strict";window.jQuery.entwine("ss",(e=>{e('[name="MFARequired"]').entwine({onchange(){parseInt(this.val(),10)?e(".mfa-settings__grace-period").removeAttr("disabled"):e(".mfa-settings__grace-period").attr("disabled","disabled")},onmatch(){this.onchange()}})}))},1924:function(e,t,n){"use strict";n(830),n(6388)},42:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=function(e){return fetch(e,{body:arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,credentials:"same-origin",headers:arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},method:arguments.length>1&&void 0!==arguments[1]?arguments[1]:"GET"})};t.default=n},1661:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatCode=void 0;t.formatCode=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:" ";if(e.length<6)return e;if(e.length%4==0)return e.split(/(.{4})/g).filter((e=>e)).join(t).trim();if(e.length%3==0)return e.split(/(.{3})/g).filter((e=>e)).join(t).trim();const n=4-e.length%4,o=(e.length-3*n)/4,r=[...[...Array(o).keys()].map((()=>4)),...[...Array(n).keys()].map((()=>3))];let a=0;return r.map((t=>e.substring(a,a+=t))).join(t).trim()}},639:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hoc=t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=i(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var l=r?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(o,a,l):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=n(1624),a=n(2827);function i(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(i=function(e){return e?n:t})(e)}function l(){return l=Object.assign?Object.assign.bind():function(e){for(var t=1;t{const t=class extends o.Component{constructor(e){super(e),this.getAvailabilityOverride=this.getAvailabilityOverride.bind(this),this.isAvailable=this.isAvailable.bind(this),this.getUnavailableMessage=this.getUnavailableMessage.bind(this)}getAvailabilityOverride(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;const{availableMethodOverrides:t}=this.props,n=e||this.props.method,{urlSegment:o}=n;return void 0!==t[o]?t[o]:{}}getUnavailableMessage(){const e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:null)||this.props.method;return this.getAvailabilityOverride(e).unavailableMessage||e.unavailableMessage}isAvailable(){const e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:null)||this.props.method,t=this.getAvailabilityOverride(e);let n=e.isAvailable;return void 0!==t.isAvailable&&(n=t.isAvailable),n}render(){return o.default.createElement(e,l({},this.props,{isAvailable:this.isAvailable,getUnavailableMessage:this.getUnavailableMessage}))}},n=(e=>e.displayName||e.name||"Component")(e);return t.displayName=`WithMethodAvailability(${n})`,t};t.hoc=s;var u=(0,a.compose)((0,r.connect)((e=>{const t=[...e.mfaRegister.availableMethods,...e.mfaVerify.allMethods],n={};return Object.values(t).forEach((t=>{const{urlSegment:o}=t,r=`${o}Availability`;void 0!==e[r]&&(n[o]=e[r])})),{availableMethodOverrides:n}})),s);t.default=u},2017:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["ADD_REGISTERED_METHOD","REMOVE_REGISTERED_METHOD","SET_DEFAULT_METHOD","SET_REGISTERED_METHODS"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_ADMINISTRATION.${t}`})),{});t.default=n},9861:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setRegisteredMethods=t.setDefaultMethod=t.registerMethod=t.deregisterMethod=void 0;var o,r=(o=n(2017))&&o.__esModule?o:{default:o};t.registerMethod=e=>({type:r.default.ADD_REGISTERED_METHOD,payload:{method:e}});t.deregisterMethod=e=>({type:r.default.REMOVE_REGISTERED_METHOD,payload:{method:e}});t.setDefaultMethod=e=>({type:r.default.SET_DEFAULT_METHOD,payload:{defaultMethod:e}});t.setRegisteredMethods=e=>({type:r.default.SET_REGISTERED_METHODS,payload:{methods:e}})},6683:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:a,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=e=>t=>t.urlSegment===e.urlSegment,{registeredMethods:i}=e;switch(t){case r.default.ADD_REGISTERED_METHOD:{const{method:t}=n;return Array.isArray(i)?i.find(o(t))?e:(i.push(t),{...e,registeredMethods:i}):{...e,registeredMethods:[t]}}case r.default.REMOVE_REGISTERED_METHOD:{const{method:t}=n,r=i.findIndex(o(t));if(r<0)return e;i.splice(r,1);const a=2===i.length?{defaultMethod:i.find((()=>!0)).urlSegment}:{};return{...e,...a,registeredMethods:[...i]}}case r.default.SET_DEFAULT_METHOD:return{...e,defaultMethod:n.defaultMethod};case r.default.SET_REGISTERED_METHODS:return{...e,registeredMethods:n.methods};default:return e}};var o,r=(o=n(2017))&&o.__esModule?o:{default:o};const a={defaultMethod:null,registeredMethods:[]}},3529:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["ADD_AVAILABLE_METHOD","REMOVE_AVAILABLE_METHOD","SET_AVAILABLE_METHODS","SET_SCREEN","SET_METHOD"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_REGISTER.${t}`})),{});t.default=n},8631:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.showScreen=t.setAvailableMethods=t.removeAvailableMethod=t.chooseMethod=t.addAvailableMethod=void 0;var o,r=(o=n(3529))&&o.__esModule?o:{default:o};t.showScreen=e=>({type:r.default.SET_SCREEN,payload:{screen:e}});t.chooseMethod=e=>({type:r.default.SET_METHOD,payload:{method:e}});t.setAvailableMethods=e=>({type:r.default.SET_AVAILABLE_METHODS,payload:{availableMethods:e}});t.addAvailableMethod=e=>({type:r.default.ADD_AVAILABLE_METHOD,payload:{method:e}});t.removeAvailableMethod=e=>({type:r.default.REMOVE_AVAILABLE_METHOD,payload:{method:e}})},7286:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};switch(t){case a.default.SET_SCREEN:{const{screen:t}=n;return null===e.method&&t===r.SCREEN_REGISTER_METHOD?{...e,screen:r.SCREEN_CHOOSE_METHOD}:{...e,screen:t}}case a.default.SET_METHOD:return{...e,method:n.method};case a.default.SET_AVAILABLE_METHODS:return{...e,availableMethods:n.availableMethods};case a.default.ADD_AVAILABLE_METHOD:return{...e,availableMethods:[...e.availableMethods,n.method]};case a.default.REMOVE_AVAILABLE_METHOD:return{...e,availableMethods:e.availableMethods.filter((e=>e.urlSegment!==n.method.urlSegment))};default:return e}};var o,r=n(440),a=(o=n(3529))&&o.__esModule?o:{default:o};const i={screen:r.SCREEN_INTRODUCTION,method:null,availableMethods:[]}},7282:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["SET_ALL_METHODS"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_VERIFY.${t}`})),{});t.default=n},23:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:a,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t===r.default.SET_ALL_METHODS)return{...e,allMethods:n.allMethods};return e};var o,r=(o=n(7282))&&o.__esModule?o:{default:o};const a={allMethods:[]}},2949:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7086))&&o.__esModule?o:{default:o};var a=r.default.shape({urlSegment:r.default.string,name:r.default.string,description:r.default.string,supportLink:r.default.string,supportText:r.default.string,thumbnail:r.default.string,component:r.default.string,isAvailable:r.default.bool,unavailableMessage:r.default.string});t.default=a},5695:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7086))&&o.__esModule?o:{default:o};var a=r.default.shape({name:r.default.string,urlSegment:r.default.string,isAvailable:r.default.bool,unavailableMessage:r.default.string,component:r.default.string,supportLink:r.default.string,thumbnail:r.default.string});t.default=a},640:function(e,t,n){"use strict";var o=n(1742),r={"text/plain":"Text","text/html":"Url",default:"Text"};e.exports=function(e,t){var n,a,i,l,s,u,c=!1;t||(t={}),n=t.debug||!1;try{if(i=o(),l=document.createRange(),s=document.getSelection(),(u=document.createElement("span")).textContent=e,u.ariaHidden="true",u.style.all="unset",u.style.position="fixed",u.style.top=0,u.style.clip="rect(0, 0, 0, 0)",u.style.whiteSpace="pre",u.style.webkitUserSelect="text",u.style.MozUserSelect="text",u.style.msUserSelect="text",u.style.userSelect="text",u.addEventListener("copy",(function(o){if(o.stopPropagation(),t.format)if(o.preventDefault(),void 0===o.clipboardData){n&&console.warn("unable to use e.clipboardData"),n&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var a=r[t.format]||r.default;window.clipboardData.setData(a,e)}else o.clipboardData.clearData(),o.clipboardData.setData(t.format,e);t.onCopy&&(o.preventDefault(),t.onCopy(o.clipboardData))})),document.body.appendChild(u),l.selectNodeContents(u),s.addRange(l),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");c=!0}catch(o){n&&console.error("unable to copy using execCommand: ",o),n&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),c=!0}catch(o){n&&console.error("unable to copy using clipboardData: ",o),n&&console.error("falling back to prompt"),a=function(e){var t=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}("message"in t?t.message:"Copy to clipboard: #{key}, Enter"),window.prompt(a,e)}}finally{s&&("function"==typeof s.removeRange?s.removeRange(l):s.removeAllRanges()),u&&document.body.removeChild(u),i()}return c}},9768:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Printd=t.createIFrame=t.createLinkStyle=t.createStyle=void 0;var n=/^(((http[s]?)|file):)?(\/\/)+([0-9a-zA-Z-_.=?&].+)$/,o=/^((\.|\.\.)?\/)([0-9a-zA-Z-_.=?&]+\/)*([0-9a-zA-Z-_.=?&]+)$/,r=function(e){return n.test(e)||o.test(e)};function a(e,t){var n=e.createElement("style");return n.appendChild(e.createTextNode(t)),n}function i(e,t){var n=e.createElement("link");return n.type="text/css",n.rel="stylesheet",n.href=t,n}function l(e){var t=window.document.createElement("iframe");return t.setAttribute("src","about:blank"),t.setAttribute("style","visibility:hidden;width:0;height:0;position:absolute;z-index:-9999;bottom:0;"),t.setAttribute("width","0"),t.setAttribute("height","0"),t.setAttribute("wmode","opaque"),e.appendChild(t),t}t.createStyle=a,t.createLinkStyle=i,t.createIFrame=l;var s={parent:window.document.body,headElements:[],bodyElements:[]},u=function(){function e(e){this.isLoading=!1,this.hasEvents=!1,this.opts=[s,e||{}].reduce((function(e,t){return Object.keys(t).forEach((function(n){return e[n]=t[n]})),e}),{}),this.iframe=l(this.opts.parent)}return e.prototype.getIFrame=function(){return this.iframe},e.prototype.print=function(e,t,n,o){if(!this.isLoading){var l=this.iframe,s=l.contentDocument,u=l.contentWindow;if(s&&u&&(this.iframe.src="about:blank",this.elCopy=e.cloneNode(!0),this.elCopy)){this.isLoading=!0,this.callback=o;var c=u.document;c.open(),c.write(''),this.addEvents();var d=this.opts,f=d.headElements,h=d.bodyElements;Array.isArray(f)&&f.forEach((function(e){return c.head.appendChild(e)})),Array.isArray(h)&&h.forEach((function(e){return c.body.appendChild(e)})),Array.isArray(t)&&t.forEach((function(e){e&&c.head.appendChild(r(e)?i(c,e):a(c,e))})),c.body.appendChild(this.elCopy),Array.isArray(n)&&n.forEach((function(e){if(e){var t=c.createElement("script");r(e)?t.src=e:t.innerText=e,c.body.appendChild(t)}})),c.close()}}},e.prototype.printURL=function(e,t){this.isLoading||(this.addEvents(),this.isLoading=!0,this.callback=t,this.iframe.src=e)},e.prototype.onBeforePrint=function(e){this.onbeforeprint=e},e.prototype.onAfterPrint=function(e){this.onafterprint=e},e.prototype.launchPrint=function(e){this.isLoading||e.print()},e.prototype.addEvents=function(){var e=this;if(!this.hasEvents){this.hasEvents=!0,this.iframe.addEventListener("load",(function(){return e.onLoad()}),!1);var t=this.iframe.contentWindow;t&&(this.onbeforeprint&&t.addEventListener("beforeprint",this.onbeforeprint),this.onafterprint&&t.addEventListener("afterprint",this.onafterprint))}},e.prototype.onLoad=function(){var e=this;if(this.iframe){this.isLoading=!1;var t=this.iframe,n=t.contentDocument,o=t.contentWindow;if(!n||!o)return;"function"==typeof this.callback?this.callback({iframe:this.iframe,element:this.elCopy,launchPrint:function(){return e.launchPrint(o)}}):this.launchPrint(o)}},e}();t.Printd=u,t.default=u},4300:function(e,t,n){"use strict";function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.CopyToClipboard=void 0;var r=l(n(7363)),a=l(n(640)),i=["text","onCopy","options","children"];function l(e){return e&&e.__esModule?e:{default:e}}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function u(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}function d(e,t){for(var n=0;n=0;--a){var i=this.tryEntries[a],l=i.completion;if("root"===i.tryLoc)return r("end");if(i.tryLoc<=this.prev){var s=o.call(i,"catchLoc"),u=o.call(i,"finallyLoc");if(s&&u){if(this.prev=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),w(n),E}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var o=n.completion;if("throw"===o.type){var r=o.arg;w(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(e,n,o){return this.delegate={iterator:D(e),resultName:n,nextLoc:o},"next"===this.method&&(this.arg=t),E}},e}(e.exports);try{regeneratorRuntime=t}catch(e){"object"==typeof globalThis?globalThis.regeneratorRuntime=t:Function("r","regeneratorRuntime = r")(t)}},1742:function(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],o=0;o{(0,o.default)(),(0,r.default)(),(0,a.default)()}))},460:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=l(n(6648)),r=l(n(440)),a=l(n(6021)),i=l(n(9521));function l(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{(0,i.default)(),o.default.component.registerMany({MFARegister:r.default,RegisteredMFAMethodListField:a.default})}},7355:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(6648)),r=i(n(6683)),a=i(n(4180));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{(0,a.default)(),o.default.reducer.register("mfaAdministration",r.default)}},941:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(n(6648)),r=a(n(3311));function a(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{o.default.transform("apply-sudo-mode-to-mfa",(e=>{e.component("RegisteredMFAMethodListField",r.default)}))}},9521:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(9487)),r=i(n(1284)),a=i(n(6648));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{a.default.component.registerMany({BackupCodeRegister:o.default,BackupCodeVerify:r.default})}},4180:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(6648)),r=i(n(7286)),a=i(n(23));function i(e){return e&&e.__esModule?e:{default:e}}t.default=()=>{o.default.reducer.register("mfaRegister",r.default),o.default.reducer.register("mfaVerify",a.default)}},9487:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=s(n(7086)),a=s(n(9768)),i=n(4855),l=n(1661);function s(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends o.Component{constructor(e){super(e),this.state={recentlyCopied:!1},this.printRef=null,this.setPrintRef=e=>{this.printRef=e},this.copyMessageTimeout=null,this.handlePrint=this.handlePrint.bind(this),this.handleCopy=this.handleCopy.bind(this)}getFormattedCodes(){const{codes:e}=this.props;return e.map((e=>(0,l.formatCode)(e)))}handlePrint(e){e.preventDefault(),(new a.default).print(this.printRef,['body { font-family: "Helvetica Neue", Helvetica, Arial, sans-serif }'])}handleCopy(e){e.preventDefault();const{copyFeedbackDuration:t}=this.props;this.setState({recentlyCopied:!0}),this.copyMessageTimeout&&clearTimeout(this.copyMessageTimeout),this.copyMessageTimeout=setTimeout((()=>{this.setState({recentlyCopied:!1})}),t)}renderCodes(){return o.default.createElement("pre",{ref:this.setPrintRef,className:"mfa-register-backup-codes__code-grid"},this.getFormattedCodes().map((e=>o.default.createElement("div",{key:e},e))))}renderDescription(){const{ss:{i18n:e}}=window,{method:{supportLink:t,supportText:n}}=this.props;return o.default.createElement("p",null,e._t("MFABackupCodesRegister.DESCRIPTION","Recovery codes enable you to log into your account in the event your primary authentication is not available. Each code can only be used once. Store these codes somewhere safe, as they will not be viewable after leaving this page.")," ",t&&o.default.createElement("a",{href:t,target:"_blank",rel:"noopener noreferrer"},n||e._t("MFARegister.RECOVERY_HELP","Learn more about recovery codes.")))}renderPrintAction(){const{ss:{i18n:e}}=window;return o.default.createElement("button",{type:"button",onClick:this.handlePrint,className:"btn btn-link"},e._t("MFABackupCodesRegister.PRINT","Print codes"))}renderDownloadAction(){const{codes:e,method:t}=this.props,{Blob:n,URL:r,ss:{i18n:a},navigator:i}=window,l=`${t.name}.txt`,s=new n([e.join("\r\n")],{type:"text/plain;charset=UTF-8"}),u=r.createObjectURL(s);return o.default.createElement("a",{download:l,href:u,className:"btn btn-link",onClick:e=>{i.msSaveBlob&&(e.preventDefault(),i.msSaveBlob(s,l))}},a._t("MFABackupCodesRegister.DOWNLOAD","Download"))}renderCopyAction(){const{codes:e}=this.props,{recentlyCopied:t}=this.state,{ss:{i18n:n}}=window,r=t?n._t("MFABackupCodesRegister.COPY_RECENT","Copied!"):n._t("MFABackupCodesRegister.COPY","Copy codes");return o.default.createElement(i.CopyToClipboard,{text:e.join("\n")},o.default.createElement("button",{type:"button",className:"mfa-register-backup-codes__copy-to-clipboard btn btn-link",onClick:this.handleCopy},r))}render(){const{onCompleteRegistration:e}=this.props,{ss:{i18n:t}}=window;return o.default.createElement("div",{className:"mfa-register-backup-codes__container"},this.renderDescription(),this.renderCodes(),o.default.createElement("div",{className:"mfa-register-backup-codes__helper-links"},this.renderPrintAction(),this.renderDownloadAction(),this.renderCopyAction()),o.default.createElement("button",{className:"btn btn-primary",onClick:()=>e()},t._t("MFABackupCodesRegister.FINISH","Finish")))}}c.propTypes={codes:r.default.arrayOf(r.default.string),copyFeedbackDuration:r.default.number},c.defaultProps={copyFeedbackDuration:3e3};var d=c;t.default=d},1284:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=i(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var l=r?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(o,a,l):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=(o=n(7820))&&o.__esModule?o:{default:o};function i(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(i=function(e){return e?n:t})(e)}class l extends r.Component{constructor(e){super(e),this.state={value:""},this.codeInput=r.default.createRef(),this.handleChange=this.handleChange.bind(this),this.handleCompleteVerification=this.handleCompleteVerification.bind(this)}componentDidMount(){this.codeInput.current&&this.codeInput.current.focus()}handleChange(e){this.setState({value:e.target.value})}handleCompleteVerification(e){e.preventDefault();const{onCompleteVerification:t}=this.props;t({code:this.state.value})}renderControls(){const{moreOptionsControl:e}=this.props,{ss:{i18n:t}}=window;return r.default.createElement("ul",{className:"mfa-action-list mfa-action-list--backup-codes"},r.default.createElement("li",{className:"mfa-action-list__item"},r.default.createElement("button",{className:"btn btn-primary",disabled:0===this.state.value.length,onClick:this.handleCompleteVerification},t._t("MFABackupCodesVerify.NEXT","Next"))),e&&r.default.createElement("li",{className:"mfa-action-list__item"},e))}renderDescription(){const{ss:{i18n:e}}=window,{method:t}=this.props;return r.default.createElement("p",null,e._t("MFABackupCodesVerify.DESCRIPTION","Use one of the recovery codes you received")," ",t&&t.supportLink&&r.default.createElement("a",{href:t.supportLink,target:"_blank",rel:"noopener noreferrer"},e._t("MFARegister.RECOVERY_HELP","How to use recovery codes.")))}renderInput(){const{error:e}=this.props,{ss:{i18n:t}}=window,n=t._t("MFABackupCodesVerify.LABEL","Enter recovery code"),o=(0,a.default)("mfa-verify-backup-codes__input-container",{"has-error":!!e});return r.default.createElement("div",{className:o},r.default.createElement("label",{htmlFor:"backup-code",className:"control-label"},n),r.default.createElement("input",{className:"mfa-verify-backup-codes__input text form-control",type:"text",placeholder:n,id:"backup-code",ref:this.codeInput,onChange:this.handleChange}),e&&r.default.createElement("div",{className:"help-block"},e))}render(){const{graphic:e,name:t}=this.props;return r.default.createElement("form",{className:"mfa-verify-backup-codes__container"},r.default.createElement("div",{className:"mfa-verify-backup-codes__content"},this.renderDescription(),this.renderInput()),r.default.createElement("div",{className:"mfa-verify-backup-codes__image-holder"},r.default.createElement("img",{className:"mfa-verify-backup-codes__image",src:e,alt:t})),this.renderControls())}}var s=l;t.default=s},2469:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=h(n(7086)),r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=h(n(4510)),i=h(n(42)),l=h(n(3141)),s=h(n(5292)),u=h(n(1820)),c=h(n(3947)),d=(h(n(5666)),h(n(7462)));function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}function h(e){return e&&e.__esModule?e:{default:e}}class p extends r.Component{constructor(e){super(e),this.state={complete:!1,failed:!1,submitting:!1},this.handleSendReset=this.handleSendReset.bind(this)}async handleSendReset(){const{ss:{i18n:e}}=window,t=e._t("MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION"]),n=e._t("MultiFactorAuthentication.CONFIRMATION_TITLE",d.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=e._t("MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION_BUTTON",d.default["MultiFactorAuthentication.ACCOUNT_RESET_CONFIRMATION_BUTTON"]);if(!await(0,l.default)({title:n,message:t,confirmText:o}))return;this.setState({submitting:!0});const r=JSON.stringify({csrf_token:a.default.get("SecurityID")});(0,i.default)(this.props.resetEndpoint,"POST",r).then((e=>e.json())).then((e=>{const t=!!e.error;this.setState({complete:!0,failed:t,submitting:!1})})).catch((()=>{this.setState({complete:!0,failed:!0,submitting:!1})}))}renderAction(){const{ss:{i18n:e}}=window,{resetEndpoint:t}=this.props,{complete:n,submitting:o}=this.state;return n||o?null:r.default.createElement("p",{className:"account-reset-action"},r.default.createElement("button",{className:"btn btn-outline-secondary",disabled:!t,onClick:this.handleSendReset,type:"button"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_ACTION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_ACTION"])))}renderSending(){const{ss:{i18n:e}}=window,{LoadingIndicatorComponent:t}=this.props;return r.default.createElement("p",{className:"account-reset-action account-reset-action--sending"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(t,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING"])))}renderFailure(){const{ss:{i18n:e}}=window;return r.default.createElement("p",{className:"account-reset-action account-reset-action--failure"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(u.default,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING_FAILURE"])))}renderSuccess(){const{ss:{i18n:e}}=window;return r.default.createElement("p",{className:"account-reset-action account-reset-action--success"},r.default.createElement("span",{className:"account-reset-action__icon"},r.default.createElement(c.default,{size:"32px"})),r.default.createElement("span",{className:"account-reset-action__message"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_SENDING_SUCCESS",d.default["MultiFactorAuthentication.ACCOUNT_RESET_SENDING_SUCCESS"])))}renderStatusMessage(){const{complete:e,failed:t,submitting:n}=this.state;return n?this.renderSending():e?t?this.renderFailure():this.renderSuccess():null}render(){const{ss:{i18n:e}}=window;return r.default.createElement("div",{className:"account-reset"},r.default.createElement("h5",{className:"account-reset__title"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_TITLE",d.default["MultiFactorAuthentication.ACCOUNT_RESET_TITLE"])),r.default.createElement("p",{className:"account-reset__description"},e._t("MultiFactorAuthentication.ACCOUNT_RESET_DESCRIPTION",d.default["MultiFactorAuthentication.ACCOUNT_RESET_DESCRIPTION"])),this.renderAction(),this.renderStatusMessage())}}p.propTypes={resetEndpoint:o.default.string,LoadingIndicatorComponent:o.default.oneOfType([o.default.object,o.default.func])},p.defaultProps={LoadingIndicatorComponent:s.default};var m=p;t.default=m},1509:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=p(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=h(n(3141)),a=h(n(7086)),i=h(n(7820)),l=h(n(8488)),s=h(n(5695)),u=h(n(2468)),c=h(n(9831)),d=h(n(8628)),f=h(n(7462));function h(e){return e&&e.__esModule?e:{default:e}}function p(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(p=function(e){return e?n:t})(e)}class m extends o.PureComponent{getStatusMessage(){const{isBackupMethod:e,isDefaultMethod:t}=this.props,{ss:{i18n:n}}=window;return t?n._t("MultiFactorAuthentication.DEFAULT_REGISTERED",f.default["MultiFactorAuthentication.DEFAULT_REGISTERED"]):e?n._t("MultiFactorAuthentication.BACKUP_REGISTERED",f.default["MultiFactorAuthentication.BACKUP_REGISTERED"]):n._t("MultiFactorAuthentication.REGISTERED",f.default["MultiFactorAuthentication.REGISTERED"])}renderRemove(){const{canRemove:e,method:t,RemoveComponent:n}=this.props;return e?o.default.createElement(n,{method:t}):null}renderReset(){const{canReset:e,isBackupMethod:t,method:n}=this.props;if(!e)return null;const a={method:n};if(t){const{ss:{i18n:e}}=window,t=e._t("MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION",f.default["MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION"]),n=e._t("MultiFactorAuthentication.CONFIRMATION_TITLE",f.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=e._t("MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION_BUTTON",f.default["MultiFactorAuthentication.RESET_BACKUP_CONFIRMATION_BUTTON"]);a.onReset=async e=>{await(0,r.default)({title:n,message:t,confirmText:o})&&e()}}return o.default.createElement(c.default,a)}renderSetAsDefault(){const{isDefaultMethod:e,isBackupMethod:t,method:n,SetDefaultComponent:r}=this.props;return e||t?null:o.default.createElement(r,{method:n})}renderControls(){const{canRemove:e,canReset:t}=this.props;return e||t?o.default.createElement("div",null,this.renderRemove(),this.renderReset(),this.renderSetAsDefault()):null}renderNameAndStatus(){const{method:e,createdDate:t}=this.props,{ss:{i18n:n}}=window,o=this.getStatusMessage();return l.default.locale(n.detectLocale()),n.inject(o,{method:e.name,date:(0,l.default)(t).format("L")})}render(){const{tag:e,className:t}=this.props,n=(0,i.default)(t,"registered-method-list-item");return o.default.createElement(e,{className:n},this.renderNameAndStatus(),this.renderControls())}}m.propTypes={method:s.default.isRequired,isDefaultMethod:a.default.bool,isBackupMethod:a.default.bool,canRemove:a.default.bool,canReset:a.default.bool,onRemove:a.default.func,onReset:a.default.func,createdDate:a.default.string,className:a.default.string,tag:a.default.string,RemoveComponent:a.default.oneOfType([a.default.object,a.default.func]),SetDefaultComponent:a.default.oneOfType([a.default.object,a.default.func])},m.defaultProps={isDefaultMethod:!1,isBackupMethod:!1,canRemove:!1,canReset:!1,tag:"li",RemoveComponent:u.default,SetDefaultComponent:d.default};var E=m;t.default=E},2468:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=h(n(7363)),r=h(n(7086)),a=n(1624),i=h(n(3141)),l=h(n(4510)),s=h(n(42)),u=n(8631),c=n(9861),d=h(n(5695)),f=h(n(7462));function h(e){return e&&e.__esModule?e:{default:e}}const p=(e,t)=>{let{method:n,onRemove:r,defaultMethod:a,registeredMethods:u,onDeregisterMethod:c,onAddAvailableMethod:d,onSetDefaultMethod:h}=e,{backupMethod:p,endpoints:{remove:m}}=t;const{ss:{i18n:E}}=window,M=async()=>{const e=E._t("MultiFactorAuthentication.DELETE_CONFIRMATION",f.default["MultiFactorAuthentication.DELETE_CONFIRMATION"]),t=E._t("MultiFactorAuthentication.CONFIRMATION_TITLE",f.default["MultiFactorAuthentication.CONFIRMATION_TITLE"]),o=E._t("MultiFactorAuthentication.DELETE_CONFIRMATION_BUTTON",f.default["MultiFactorAuthentication.DELETE_CONFIRMATION_BUTTON"]);if(!await(0,i.default)({title:t,message:e,confirmText:o}))return;const r=l.default.get("SecurityID"),M=`${m.replace("{urlSegment}",n.urlSegment)}?SecurityID=${r}`;(0,s.default)(M,"DELETE").then((e=>e.json().then((t=>{if(200===e.status)return c(n),d(t.availableMethod),n.urlSegment===a&&h(null),void(!t.hasBackupMethod&&p&&u.find((e=>e.urlSegment===p.urlSegment))&&c(p));const o=t.errors&&` Errors: \n - ${t.errors.join("\n -")}`||"";throw Error(`Could not delete method. Error code ${e.status}.${o}`)}))))};return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:r?r(M):M},E._t("MultiFactorAuthentication.REMOVE_METHOD",f.default["MultiFactorAuthentication.REMOVE_METHOD"]))};p.propTypes={method:d.default.isRequired,onRemove:r.default.func,defaultMethod:r.default.string.isRequired,registeredMethods:r.default.arrayOf(d.default).isRequired,onDeregisterMethod:r.default.func.isRequired,onAddAvailableMethod:r.default.func.isRequired,onSetDefaultMethod:r.default.func.isRequired},p.contextTypes={backupMethod:d.default,endpoints:r.default.shape({register:r.default.string,remove:r.default.string})};var m=(0,a.connect)((e=>{let{mfaAdministration:{defaultMethod:t,registeredMethods:n}}=e;return{defaultMethod:t,registeredMethods:n}}),(e=>({onDeregisterMethod:t=>{e((0,c.deregisterMethod)(t))},onAddAvailableMethod:t=>{e((0,u.addAvailableMethod)(t))},onSetDefaultMethod:t=>e((0,c.setDefaultMethod)(t))})))(p);t.default=m},9831:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=h(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=f(n(7086)),a=n(1624),i=n(440),l=n(8631),s=f(n(5695)),u=f(n(2949)),c=f(n(7442)),d=f(n(7462));function f(e){return e&&e.__esModule?e:{default:e}}function h(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(h=function(e){return e?n:t})(e)}class p extends o.Component{constructor(e){super(e),this.state={modalOpen:!1},this.handleReset=this.handleReset.bind(this),this.handleToggleModal=this.handleToggleModal.bind(this)}handleToggleModal(){this.setState((e=>({modalOpen:!e.modalOpen})))}handleReset(){const{onResetMethod:e,method:t}=this.props,{allAvailableMethods:n}=this.context,o=n.find((e=>e.urlSegment===t.urlSegment));if(!o)throw Error(`Cannot register the method given: ${t.name} (${t.urlSegment}).`);e(o),this.handleToggleModal()}render(){const{onReset:e}=this.props,{backupMethod:t,endpoints:n,resources:r}=this.context,a=e?()=>e(this.handleReset):this.handleReset;return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:a},window.ss.i18n._t("MultiFactorAuthentication.RESET_METHOD",d.default["MultiFactorAuthentication.RESET_METHOD"]),o.default.createElement(c.default,{backupMethod:t,isOpen:this.state.modalOpen,toggle:this.handleToggleModal,resources:r,endpoints:n,disallowedScreens:[i.SCREEN_CHOOSE_METHOD,i.SCREEN_INTRODUCTION]}))}}p.propTypes={method:s.default.isRequired,onReset:r.default.func},p.contextTypes={allAvailableMethods:r.default.arrayOf(u.default),backupMethod:s.default,endpoints:r.default.shape({register:r.default.string}),resources:r.default.object};var m=(0,a.connect)(null,(e=>({onResetMethod:t=>{e((0,l.chooseMethod)(t)),e((0,l.showScreen)(i.SCREEN_REGISTER_METHOD))}})))(p);t.default=m},8628:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=f(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=d(n(7086)),a=d(n(5695)),i=d(n(4510)),l=n(1624),s=d(n(42)),u=n(9861),c=d(n(7462));function d(e){return e&&e.__esModule?e:{default:e}}function f(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(f=function(e){return e?n:t})(e)}class h extends o.Component{constructor(e){super(e),this.handleSetDefault=this.handleSetDefault.bind(this)}handleSetDefault(){const{method:e,onSetDefaultMethod:t}=this.props,{endpoints:{setDefault:n}}=this.context,o=i.default.get("SecurityID"),r=`${n.replace("{urlSegment}",e.urlSegment)}?SecurityID=${o}`;(0,s.default)(r,"PUT").then((n=>n.json().then((o=>{if(200===n.status)return void t(e.urlSegment);const r=o.errors&&` Errors: \n - ${o.errors.join("\n -")}`||"";throw Error(`Could not set default method. Error code ${n.status}.${r}`)}))))}render(){const{ss:{i18n:e}}=window;return o.default.createElement("button",{className:"registered-method-list-item__control",type:"button",onClick:this.handleSetDefault},e._t("MultiFactorAuthentication.SET_AS_DEFAULT",c.default["MultiFactorAuthentication.SET_AS_DEFAULT"]))}}t.Component=h,h.propTypes={method:a.default.isRequired},h.contextTypes={endpoints:r.default.shape({setDefault:r.default.string})};var p=(0,l.connect)(null,(e=>({onSetDefaultMethod:t=>e((0,u.setDefaultMethod)(t))})))(h);t.default=p},6021:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=_(n(7086)),r=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=M(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),a=n(8127),i=n(1624),l=_(n(7820)),s=_(n(5695)),u=_(n(2949)),c=n(8631),d=n(9861),f=n(440),h=_(n(1509)),p=_(n(2469)),m=_(n(7442)),E=_(n(7462));function M(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(M=function(e){return e?n:t})(e)}function _(e){return e&&e.__esModule?e:{default:e}}class g extends r.Component{constructor(e){super(e),this.state={modalOpen:!1},this.handleToggleModal=this.handleToggleModal.bind(this)}getChildContext(){const{allAvailableMethods:e,backupMethod:t,endpoints:n,resources:o}=this.props;return{allAvailableMethods:e,backupMethod:t,endpoints:n,resources:o}}componentDidMount(){const{onSetDefaultMethod:e,initialDefaultMethod:t,onSetRegisteredMethods:n,initialRegisteredMethods:o,onUpdateAvailableMethods:r,initialAvailableMethods:a}=this.props;n(o),r(a),e(t)}getBaseMethods(){const{backupMethod:e}=this.props;let{registeredMethods:t}=this.props;return t?(e&&(t=t.filter((t=>t.urlSegment!==e.urlSegment))),t):[]}handleToggleModal(){this.setState((e=>({modalOpen:!e.modalOpen})))}renderNoMethodsMessage(){if(this.getBaseMethods().length)return null;const{readOnly:e}=this.props,{ss:{i18n:t}}=window,n=e?"MultiFactorAuthentication.NO_METHODS_REGISTERED_READONLY":"MultiFactorAuthentication.NO_METHODS_REGISTERED";return r.default.createElement("div",{className:"registered-mfa-method-list-field__no-methods"},t._t(n,E.default[n]))}renderBackupMethod(){const{backupMethod:e,backupCreatedDate:t,registeredMethods:n,readOnly:o,MethodListItemComponent:a}=this.props;if(!e)return null;const i=n.find((t=>t.urlSegment===e.urlSegment));return i?r.default.createElement(a,{method:i,createdDate:t,canReset:!o,isBackupMethod:!0,tag:"div",className:"registered-method-list-item--backup"}):null}renderBaseMethods(){const{isMFARequired:e}=this.props,t=this.getBaseMethods();if(!t.length)return[];const{defaultMethod:n,readOnly:o,MethodListItemComponent:a}=this.props;return t.map((i=>{const l={method:i,key:i.urlSegment,isDefaultMethod:n&&i.urlSegment===n,canRemove:!(o||e&&1===t.length),canReset:!o};return r.default.createElement(a,l)}))}renderModal(){const{backupMethod:e,endpoints:t,resources:n,RegisterModalComponent:o}=this.props;return r.default.createElement(o,{backupMethod:e,isOpen:this.state.modalOpen,toggle:this.handleToggleModal,resources:n,endpoints:t,disallowedScreens:[f.SCREEN_INTRODUCTION]})}renderAddButton(){const{availableMethods:e,registeredMethods:t,readOnly:n,onResetRegister:o}=this.props;if(n||!e||0===e.length)return null;const{ss:{i18n:i}}=window,l=t.length?i._t("MultiFactorAuthentication.ADD_ANOTHER_METHOD",E.default["MultiFactorAuthentication.ADD_ANOTHER_METHOD"]):i._t("MultiFactorAuthentication.ADD_FIRST_METHOD",E.default["MultiFactorAuthentication.ADD_FIRST_METHOD"]);return r.default.createElement(a.Button,{className:"registered-mfa-method-list-field__button",outline:!0,type:"button",onClick:()=>{this.handleToggleModal(),o()}},l)}render(){const{readOnly:e,resetEndpoint:t}=this.props,n=(0,l.default)({"registered-mfa-method-list-field":!0,"registered-mfa-method-list-field--read-only":e});return r.default.createElement("div",{className:n},r.default.createElement("ul",{className:"method-list"},this.renderBaseMethods()),this.renderNoMethodsMessage(),this.renderAddButton(),this.renderBackupMethod(),e&&r.default.createElement("hr",null),e&&r.default.createElement(p.default,{resetEndpoint:t}),this.renderModal())}}t.Component=g,g.propTypes={backupMethod:s.default,defaultMethod:o.default.string,readOnly:o.default.bool,isMFARequired:o.default.bool,initialDefaultMethod:o.default.string,initialRegisteredMethods:o.default.arrayOf(s.default),initialAvailableMethods:o.default.arrayOf(u.default),allAvailableMethods:o.default.arrayOf(u.default),resetEndpoint:o.default.string,endpoints:o.default.shape({register:o.default.string,remove:o.default.string}),resources:o.default.object,availableMethods:o.default.arrayOf(u.default),registeredMethods:o.default.arrayOf(s.default),registrationScreen:o.default.number,MethodListItemComponent:o.default.oneOfType([o.default.object,o.default.func]),RegisterModalComponent:o.default.oneOfType([o.default.object,o.default.func])},g.defaultProps={initialAvailableMethods:[],MethodListItemComponent:h.default,RegisterModalComponent:m.default},g.childContextTypes={allAvailableMethods:o.default.arrayOf(u.default),backupMethod:s.default,endpoints:o.default.shape({register:o.default.string,remove:o.default.string,setDefault:o.default.string}),resources:o.default.object};var y=(0,i.connect)((e=>{const{availableMethods:t,screen:n}=e.mfaRegister,{defaultMethod:o,registeredMethods:r}=e.mfaAdministration;return{availableMethods:t,defaultMethod:o,registeredMethods:r||[],registrationScreen:n}}),(e=>({onResetRegister:()=>{e((0,c.chooseMethod)(null)),e((0,c.showScreen)(f.SCREEN_CHOOSE_METHOD))},onUpdateAvailableMethods:t=>{e((0,c.setAvailableMethods)(t))},onSetDefaultMethod:t=>{e((0,d.setDefaultMethod)(t))},onSetRegisteredMethods:t=>{e((0,d.setRegisteredMethods)(t))}})))(g);t.default=y},1820:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7363))&&o.__esModule?o:{default:o};t.default=e=>{let{color:t="currentColor",size:n="3em"}=e;return r.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:n,width:n},r.default.createElement("g",{fill:t},r.default.createElement("path",{d:"M256 8C119 8 8 119 8 256s111 248 248 248 248-111 248-248S393 8 256 8zM124 296c-6.6 0-12-5.4-12-12v-56c0-6.6 5.4-12 12-12h264c6.6 0 12 5.4 12 12v56c0 6.6-5.4 12-12 12H124z"})))}},3947:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7363))&&o.__esModule?o:{default:o};t.default=e=>{let{color:t="currentColor",size:n="3em"}=e;return r.default.createElement("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 512 512",height:n,width:n},r.default.createElement("g",{fill:t},r.default.createElement("path",{d:"M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zM227.314 387.314l184-184c6.248-6.248 6.248-16.379 0-22.627l-22.627-22.627c-6.248-6.249-16.379-6.249-22.628 0L216 308.118l-70.059-70.059c-6.248-6.248-16.379-6.248-22.628 0l-22.627 22.627c-6.248 6.248-6.248 16.379 0 22.627l104 104c6.249 6.249 16.379 6.249 22.628.001z"})))}},5292:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=a(n(7363)),r=a(n(7820));function a(e){return e&&e.__esModule?e:{default:e}}t.default=e=>{let{block:t=!1,size:n="6em"}=e;return o.default.createElement("div",{style:{height:n,width:n},className:(0,r.default)({"mfa-loading-indicator":!0,"mfa-loading-indicator--block":t})})}},440:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.SCREEN_REGISTER_METHOD=t.SCREEN_INTRODUCTION=t.SCREEN_COMPLETE=t.SCREEN_CHOOSE_METHOD=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=M(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=E(n(7086)),a=E(n(42)),i=n(6648),l=E(n(2949)),s=E(n(5695)),u=E(n(5292)),c=E(n(6910)),d=E(n(3954)),f=E(n(1824)),h=n(1624),p=n(8631),m=E(n(1196));function E(e){return e&&e.__esModule?e:{default:e}}function M(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(M=function(e){return e?n:t})(e)}function _(){return _=Object.assign?Object.assign.bind():function(e){for(var t=1;te.json().then((e=>{const{SecurityID:t,...n}=e;this.setState({registerProps:n,token:t})}))))}handleBack(){const{availableMethods:e,onShowIntroduction:t,onShowChooseMethod:n}=this.props;return 1===e.length&&t?t():(this.setState({registerProps:null}),n())}handleCompleteRegistration(e){const{endpoints:{register:t},selectedMethod:n,onRemoveAvailableMethod:o,onRegister:r}=this.props,{token:i}=this.state,l=i?`?SecurityID=${i}`:"";(0,a.default)(`${t.replace("{urlSegment}",n.urlSegment)}${l}`,"POST",JSON.stringify(e)).then((e=>201===e.status?(this.setState({registerProps:null}),"function"==typeof r&&r(n),o(n),this.setupBackupMethod(),null):e.json())).then((e=>{if(e&&e.errors){const t=e.errors.join(", ");this.setState((e=>({registerProps:{...e.registerProps,error:t}})))}}))}shouldSetupBackupMethod(){const{backupMethod:e,registeredMethods:t}=this.props;return!!e&&!t.find((t=>t.urlSegment===e.urlSegment))}handleSkip(){const{skip:e}=this.props.endpoints;e&&(window.location=this.props.endpoints.skip)}renderIntroduction(){const{canSkip:e,resources:t,endpoints:{skip:n},showSubTitle:r,IntroductionComponent:a}=this.props;return o.default.createElement(a,{canSkip:n&&e,onSkip:this.handleSkip,resources:t,showTitle:r})}renderMethod(){const{selectedMethod:e,showSubTitle:t,TitleComponent:n}=this.props,{registerProps:r}=this.state;if(!e)return null;if(!r)return o.default.createElement(u.default,{block:!0});const a=(0,i.loadComponent)(e.component);return o.default.createElement("div",null,t&&o.default.createElement(n,null),o.default.createElement(a,_({},r,{method:e,onBack:this.handleBack,onCompleteRegistration:this.handleCompleteRegistration})))}renderOptions(){const{availableMethods:e,showSubTitle:t,SelectMethodComponent:n}=this.props;return o.default.createElement(n,{methods:e,showTitle:t})}render(){const{screen:e,onCompleteRegistration:t,showTitle:n,showSubTitle:r,completeMessage:a,CompleteComponent:i}=this.props,{ss:{i18n:l}}=window;if(4===e)return o.default.createElement(i,{showTitle:r,onComplete:t,message:a});let s;switch(e){case 3:s=this.renderOptions();break;case 2:s=this.renderMethod();break;default:s=this.renderIntroduction()}return o.default.createElement("div",null,n&&o.default.createElement("h1",{className:"mfa-app-title"},l._t("MFARegister.TITLE","Multi-factor authentication")),s)}}t.Component=g,g.propTypes={availableMethods:r.default.arrayOf(l.default),backupMethod:l.default,canSkip:r.default.bool,endpoints:r.default.shape({register:r.default.string.isRequired,skip:r.default.string}),onRegister:r.default.func,onCompleteRegistration:r.default.func.isRequired,registeredMethods:r.default.arrayOf(s.default),resources:r.default.object,showTitle:r.default.bool,showSubTitle:r.default.bool,IntroductionComponent:r.default.oneOfType([r.default.object,r.default.func]),SelectMethodComponent:r.default.oneOfType([r.default.object,r.default.func]),CompleteComponent:r.default.oneOfType([r.default.object,r.default.func]),TitleComponent:r.default.oneOfType([r.default.object,r.default.func])},g.defaultProps={resources:{},showTitle:!0,showSubTitle:!0,showIntroduction:!0,IntroductionComponent:c.default,SelectMethodComponent:f.default,CompleteComponent:d.default,TitleComponent:m.default};var y=(0,h.connect)((e=>{const t=e.mfaRegister||e;return{screen:t.screen,selectedMethod:t.method,availableMethods:t.availableMethods}}),(e=>({onShowIntroduction:()=>e((0,p.showScreen)(1)),onShowComplete:()=>e((0,p.showScreen)(4)),onSelectMethod:t=>e((0,p.chooseMethod)(t)),onShowChooseMethod:()=>{e((0,p.chooseMethod)(null)),e((0,p.showScreen)(3))},onRemoveAvailableMethod:t=>e((0,p.removeAvailableMethod)(t))})))(g);t.default=y},3954:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=i(n(7363)),r=i(n(7086)),a=i(n(1196));function i(e){return e&&e.__esModule?e:{default:e}}const l=e=>{let{onComplete:t,showTitle:n,message:r}=e;return o.default.createElement("div",{className:"mfa-register-confirmation"},o.default.createElement("i",{className:"font-icon-check-mark mfa-register-confirmation__icon"}),n&&o.default.createElement(a.default,{className:"mfa-register-confirmation__title"}),o.default.createElement("p",{className:"mfa-register-confirmation__description"},r||window.ss.i18n._t("MFARegister.SETUP_COMPLETE_DESCRIPTION","You will be able to edit these settings later from your profile area.")),o.default.createElement("button",{onClick:t,className:"mfa-register-confirmation__continue btn btn-primary"},window.ss.i18n._t("MFARegister.SETUP_COMPLETE_CONTINUE","Continue")))};l.propTypes={onComplete:r.default.func.isRequired,showTitle:r.default.bool},l.defaultProps={showTitle:!0};var s=l;t.default=s},6910:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=t.ActionList=void 0;var o=c(n(7363)),r=c(n(7086)),a=n(8631),i=n(1624),l=n(440),s=c(n(1196)),u=c(n(7462));function c(e){return e&&e.__esModule?e:{default:e}}const d=e=>{let{canSkip:t,onContinue:n,onSkip:r}=e;const{ss:{i18n:a}}=window;return o.default.createElement("ul",{className:"mfa-action-list"},o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-primary",onClick:n},a._t("MultiFactorAuthentication.GET_STARTED",u.default["MultiFactorAuthentication.GET_STARTED"]))),t&&o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-secondary",onClick:r},a._t("MultiFactorAuthentication.SETUP_LATER",u.default["MultiFactorAuthentication.SETUP_LATER"]))))};t.ActionList=d;const f=e=>{let{canSkip:t,onContinue:n,onSkip:r,resources:a,showTitle:i,TitleComponent:l}=e;const{ss:{i18n:s}}=window;return o.default.createElement("div",null,i&&o.default.createElement(l,null),o.default.createElement("h4",{className:"mfa-feature-list-title"},s._t("MultiFactorAuthentication.HOW_IT_WORKS",u.default["MultiFactorAuthentication.HOW_IT_WORKS"])),o.default.createElement("ul",{className:"mfa-feature-list"},o.default.createElement("li",{className:"mfa-feature-list-item"},a.extra_factor_image_url&&o.default.createElement("img",{alt:s._t("MultiFactorAuthentication.EXTRA_LAYER_IMAGE_ALT",u.default["MultiFactorAuthentication.EXTRA_LAYER_IMAGE_ALT"]),"aria-hidden":"true",className:"mfa-feature-list-item__icon",src:a.extra_factor_image_url}),o.default.createElement("div",{className:"mfa-feature-list-item__content"},o.default.createElement("h5",{className:"mfa-block-heading mfa-feature-list-item__title"},s._t("MultiFactorAuthentication.EXTRA_LAYER_TITLE",u.default["MultiFactorAuthentication.EXTRA_LAYER_TITLE"])),o.default.createElement("p",{className:"mfa-feature-list-item__description"},s._t("MultiFactorAuthentication.EXTRA_LAYER_DESCRIPTION",u.default["MultiFactorAuthentication.EXTRA_LAYER_DESCRIPTION"])," ",a.user_help_link&&o.default.createElement("a",{href:a.user_help_link},s._t("MultiFactorAuthentication.HOW_MFA_WORKS",u.default["MultiFactorAuthentication.HOW_MFA_WORKS"]))))),o.default.createElement("li",{className:"mfa-feature-list-item"},a.unique_image_url&&o.default.createElement("img",{alt:s._t("MultiFactorAuthentication.UNIQUE_IMAGE_ALT",u.default["MultiFactorAuthentication.UNIQUE_IMAGE_ALT"]),"aria-hidden":"true",className:"mfa-feature-list-item__icon",src:a.unique_image_url}),o.default.createElement("div",{className:"mfa-feature-list-item__content"},o.default.createElement("h5",{className:"mfa-block-heading mfa-feature-list-item__title"},s._t("MultiFactorAuthentication.UNIQUE_TITLE",u.default["MultiFactorAuthentication.UNIQUE_TITLE"])),o.default.createElement("p",{className:"mfa-feature-list-item__description"},s._t("MultiFactorAuthentication.UNIQUE_DESCRIPTION",u.default["MultiFactorAuthentication.UNIQUE_DESCRIPTION"]))))),o.default.createElement(d,{canSkip:t,onContinue:n,onSkip:r}))};t.Component=f,f.propTypes={canSkip:r.default.bool,onContinue:r.default.func.isRequired,onSkip:r.default.func,resources:r.default.shape({user_help_link:r.default.string,extra_factor_image_url:r.default.string,unique_image_url:r.default.string}).isRequired,showTitle:r.default.bool,TitleComponent:r.default.oneOfType([r.default.object,r.default.func])},f.defaultProps={showTitle:!0,TitleComponent:s.default};var h=(0,i.connect)(null,(e=>({onContinue:()=>{e((0,a.chooseMethod)(null)),e((0,a.showScreen)(l.SCREEN_REGISTER_METHOD))}})))(f);t.default=h},3324:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=u(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=s(n(7086)),a=s(n(7820)),i=s(n(2949)),l=s(n(639));function s(e){return e&&e.__esModule?e:{default:e}}function u(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(u=function(e){return e?n:t})(e)}class c extends o.Component{constructor(e){super(e),this.handleClick=this.handleClick.bind(this),this.handleKeyUp=this.handleKeyUp.bind(this)}handleClick(e){const{method:{isAvailable:t},onClick:n}=this.props;t&&n&&n(e)}handleKeyUp(e){13===e.keyCode&&this.handleClick(e)}renderSupportLink(e){const{ss:{i18n:t}}=window,{supportLink:n,supportText:r}=e;return n?o.default.createElement("a",{href:n,target:"_blank",rel:"noopener noreferrer",className:"mfa-method-tile__support-link"},r||t._t("MFARegister.HELP","Find out more.")):null}renderUnavailableMask(){const{ss:{i18n:e}}=window,{isAvailable:t,getUnavailableMessage:n}=this.props;if(t())return null;const r=n();return o.default.createElement("div",{className:"mfa-method-tile__unavailable-mask"},o.default.createElement("h3",{className:"mfa-method-tile__unavailable-title"},e._t("MFAMethodTile.UNAVAILABLE","Unsupported: ")),r&&o.default.createElement("p",{className:"mfa-method-tile__unavailable-text"},r))}render(){const{isActive:e,method:t}=this.props,{ss:{i18n:n}}=window,r=(0,a.default)("mfa-method-tile",{"mfa-method-tile--active":e,"mfa-method-tile--unsupported":!t.isAvailable}),i=(0,a.default)("mfa-method-tile__thumbnail-container",{"mfa-method-tile__thumbnail-container--unsupported":!t.isAvailable}),l=n.inject(n._t("MFARegister.REGISTER_WITH","Register with {method}"),{method:t.name.toLowerCase()});return o.default.createElement("li",{className:r},o.default.createElement("div",{className:"mfa-method-tile__content",onClick:this.handleClick,onKeyUp:this.handleKeyUp,tabIndex:"0",role:"button"},t.thumbnail&&o.default.createElement("div",{className:i},o.default.createElement("img",{src:t.thumbnail,className:"mfa-method-tile__thumbnail",alt:t.name})),o.default.createElement("h3",{className:"mfa-method-tile__title"},l),o.default.createElement("p",{className:"mfa-method-tile__description"},t.description&&`${t.description}. `,this.renderSupportLink(t))),this.renderUnavailableMask())}}t.Component=c,c.propTypes={getUnavailableMessage:r.default.func.isRequired,isActive:r.default.bool,isAvailable:r.default.func.isRequired,method:i.default.isRequired,onClick:r.default.func.isRequired},c.defaultProps={isActive:!1};var d=(0,l.default)(c);t.default=d},1824:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=m(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=p(n(7086)),a=p(n(2949)),i=p(n(7820)),l=n(8631),s=n(2827),u=n(1624),c=p(n(639)),d=n(440),f=p(n(3324)),h=p(n(1196));function p(e){return e&&e.__esModule?e:{default:e}}function m(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(m=function(e){return e?n:t})(e)}class E extends o.Component{constructor(e){super(e);let t=null;1===e.methods.length&&e.isAvailable&&e.isAvailable(e.methods[0])&&(t=e.methods[0]),this.state={highlightedMethod:t},this.handleGoToNext=this.handleGoToNext.bind(this),this.handleBack=this.handleBack.bind(this)}componentDidMount(){const{highlightedMethod:e}=this.state;e&&this.handleGoToNext()}handleGoToNext(){const{highlightedMethod:e}=this.state;this.props.onSelectMethod(e)}handleClick(e){this.setState({highlightedMethod:e})}handleBack(){this.props.onClickBack&&this.props.onClickBack()}renderActions(){const{ss:{i18n:e}}=window,{highlightedMethod:t}=this.state;return o.default.createElement("ul",{className:"mfa-action-list"},o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-primary",disabled:null===t,onClick:this.handleGoToNext},e._t("MFARegister.NEXT","Next"))),o.default.createElement("li",{className:"mfa-action-list__item"},o.default.createElement("button",{className:"btn btn-secondary",onClick:this.handleBack},e._t("MFARegister.BACK","Back"))))}render(){const{methods:e,showTitle:t,TitleComponent:n,MethodTileComponent:r}=this.props,{highlightedMethod:a}=this.state,l=(0,i.default)("mfa-method-tile-group",{"mfa-method-tile-group--three-columns":e.length%3==0});return o.default.createElement("div",null,t&&o.default.createElement(n,null),o.default.createElement("ul",{className:l},e.map((e=>o.default.createElement(r,{isActive:a===e,key:e.urlSegment,method:e,onClick:()=>this.handleClick(e)})))),this.renderActions())}}t.Component=E,E.propTypes={methods:r.default.arrayOf(a.default),onSelectMethod:r.default.func,onClickBack:r.default.func,showTitle:r.default.bool,TitleComponent:r.default.oneOfType([r.default.object,r.default.func]),MethodTileComponent:r.default.oneOfType([r.default.object,r.default.func])},E.defaultProps={showTitle:!0,TitleComponent:h.default,MethodTileComponent:f.default};var M=(0,s.compose)((0,u.connect)(null,(e=>({onClickBack:()=>e((0,l.showScreen)(d.SCREEN_INTRODUCTION)),onSelectMethod:t=>{e((0,l.chooseMethod)(t)),e((0,l.showScreen)(d.SCREEN_REGISTER_METHOD))}}))),c.default)(E);t.default=M},1196:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=l(n(7363)),r=n(1624),a=n(440),i=l(n(7462));function l(e){return e&&e.__esModule?e:{default:e}}const s=e=>{let{screen:t,method:n,Tag:r="h2",className:l="mfa-section-title"}=e;const{ss:{i18n:s}}=window;let u;switch(t){case a.SCREEN_INTRODUCTION:u=s._t("MultiFactorAuthentication.TITLE",i.default["MultiFactorAuthentication.TITLE"]);break;case a.SCREEN_CHOOSE_METHOD:u=s._t("MultiFactorAuthentication.SELECT_METHOD",i.default["MultiFactorAuthentication.SELECT_METHOD"]);break;case a.SCREEN_COMPLETE:u=s._t("MultiFactorAuthentication.SETUP_COMPLETE_TITLE",i.default["MultiFactorAuthentication.SETUP_COMPLETE_TITLE"]);break;case a.SCREEN_REGISTER_METHOD:u=n&&s.inject(s._t("MFARegister.REGISTER_WITH","Register with {method}"),{method:n.name.toLowerCase()});break;default:u=!1}if(!u||!u.length)return null;const c=r||"span";return o.default.createElement(c,{className:l},u)};t.Component=s;var u=(0,r.connect)((e=>{const t=e.mfaRegister||e;return{screen:t.screen,method:t.method}}))(s);t.default=u},7442:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.Component=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=m(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var i=r?Object.getOwnPropertyDescriptor(e,a):null;i&&(i.get||i.set)?Object.defineProperty(o,a,i):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=p(n(7086)),a=n(8127),i=n(6648),l=n(2827),s=n(1624),u=p(n(1196)),c=n(9861),d=p(n(5695)),f=n(440),h=p(n(7462));function p(e){return e&&e.__esModule?e:{default:e}}function m(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(m=function(e){return e?n:t})(e)}class E extends o.Component{constructor(e){super(e),this.handleRegister=this.handleRegister.bind(this)}componentDidUpdate(){const{disallowedScreens:e,isOpen:t,registrationScreen:n,toggle:o}=this.props;t&&e.length&&e.includes(n)&&o()}handleRegister(e){const{onAddRegisteredMethod:t,onSetDefaultMethod:n,registeredMethods:o}=this.props;o.length||n(e.urlSegment),t(e)}render(){const{backupMethod:e,endpoints:t,isOpen:n,toggle:r,registeredMethods:i,registrationScreen:l,resources:s,RegisterComponent:c}=this.props;return o.default.createElement(a.Modal,{isOpen:n,toggle:r,className:"registered-mfa-method-list-field-register-modal"},o.default.createElement(a.ModalHeader,{toggle:r},o.default.createElement(u.default,{Tag:null})),o.default.createElement(a.ModalBody,{className:"registered-mfa-method-list-field-register-modal__content"},l!==f.SCREEN_INTRODUCTION&&o.default.createElement(c,{backupMethod:e,registeredMethods:i,onCompleteRegistration:r,onRegister:this.handleRegister,resources:s,endpoints:t,showTitle:!1,showSubTitle:!1,completeMessage:window.ss.i18n._t("MultiFactorAuthentication.ADMIN_SETUP_COMPLETE_CONTINUE",h.default["MultiFactorAuthentication.ADMIN_SETUP_COMPLETE_CONTINUE"])})))}}t.Component=E,E.propTypes={isOpen:r.default.bool,toggle:r.default.func,disallowedScreens:r.default.arrayOf(r.default.number),backupMethod:d.default,resources:r.default.object,endpoints:r.default.shape({register:r.default.string}),registrationScreen:r.default.number,registeredMethods:r.default.arrayOf(d.default),onAddRegisteredMethod:r.default.func,onSetDefaultMethod:r.default.func,RegisterComponent:r.default.oneOfType([r.default.element,r.default.func,r.default.elementType])},E.defaultProps={isOpen:!1,disallowedScreens:[]};var M=(0,l.compose)((0,i.inject)(["MFARegister"],(e=>({RegisterComponent:e})),(()=>"MFARegisterModal")),(0,s.connect)((e=>({registrationScreen:e.mfaRegister.screen,registeredMethods:e.mfaAdministration.registeredMethods})),(e=>({onAddRegisteredMethod:t=>{e((0,c.registerMethod)(t))},onSetDefaultMethod:t=>e((0,c.setDefaultMethod)(t))}))))(E);t.default=M},830:function(e,t,n){"use strict";var o,r=(o=n(7363))&&o.__esModule?o:{default:o},a=n(9691),i=n(6648);window.jQuery.entwine("ss",(e=>{e('.js-injector-boot [data-field-type="registered-mfa-method-list-field"]').entwine({ReactRoot:null,onmatch(){const e=(0,i.loadComponent)("RegisteredMFAMethodListField"),{readOnly:t,schema:{backupMethod:n,defaultMethod:o,registeredMethods:l,availableMethods:s,allAvailableMethods:u,resources:c,endpoints:d,backupCreatedDate:f,resetEndpoint:h,isMFARequired:p}}=this.data("schema");let m=this.getReactRoot();m||(m=(0,a.createRoot)(this[0]),this.setReactRoot(m)),m.render(r.default.createElement(e,{backupMethod:n,readOnly:t,initialDefaultMethod:o,initialRegisteredMethods:l,initialAvailableMethods:s,allAvailableMethods:u,resources:c,endpoints:d,backupCreatedDate:f,resetEndpoint:h,isMFARequired:p}))},onunmatch(){const e=this.getReactRoot();e&&(e.unmount(),this.setReactRoot(null))}})}))},6388:function(){"use strict";window.jQuery.entwine("ss",(e=>{e('[name="MFARequired"]').entwine({setGraceFieldState(){parseInt(this.val(),10)?e(".mfa-settings__grace-period").removeAttr("disabled"):e(".mfa-settings__grace-period").attr("disabled","disabled")},onchange(){this.setGraceFieldState()},onmatch(){this.setGraceFieldState()}}),e('[name="MFAAppliesTo"]').entwine({setGroupFieldVisibility(){if(!this.is(":checked"))return;const t=e(".js-mfa-group-restrictions");"everyone"===this.val()?t.hide():t.show()},onchange(){this.setGroupFieldVisibility()},onmatch(){this.setGroupFieldVisibility()}})}))},1924:function(e,t,n){"use strict";n(830),n(6388)},42:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=function(e){return fetch(e,{body:arguments.length>2&&void 0!==arguments[2]?arguments[2]:void 0,credentials:"same-origin",headers:arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},method:arguments.length>1&&void 0!==arguments[1]?arguments[1]:"GET"})};t.default=n},1661:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.formatCode=void 0;t.formatCode=function(e){let t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:" ";if(e.length<6)return e;if(e.length%4==0)return e.split(/(.{4})/g).filter((e=>e)).join(t).trim();if(e.length%3==0)return e.split(/(.{3})/g).filter((e=>e)).join(t).trim();const n=4-e.length%4,o=(e.length-3*n)/4,r=[...[...Array(o).keys()].map((()=>4)),...[...Array(n).keys()].map((()=>3))];let a=0;return r.map((t=>e.substring(a,a+=t))).join(t).trim()}},639:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.hoc=t.default=void 0;var o=function(e,t){if(!t&&e&&e.__esModule)return e;if(null===e||"object"!=typeof e&&"function"!=typeof e)return{default:e};var n=i(t);if(n&&n.has(e))return n.get(e);var o={},r=Object.defineProperty&&Object.getOwnPropertyDescriptor;for(var a in e)if("default"!==a&&Object.prototype.hasOwnProperty.call(e,a)){var l=r?Object.getOwnPropertyDescriptor(e,a):null;l&&(l.get||l.set)?Object.defineProperty(o,a,l):o[a]=e[a]}o.default=e,n&&n.set(e,o);return o}(n(7363)),r=n(1624),a=n(2827);function i(e){if("function"!=typeof WeakMap)return null;var t=new WeakMap,n=new WeakMap;return(i=function(e){return e?n:t})(e)}function l(){return l=Object.assign?Object.assign.bind():function(e){for(var t=1;t{const t=class extends o.Component{constructor(e){super(e),this.getAvailabilityOverride=this.getAvailabilityOverride.bind(this),this.isAvailable=this.isAvailable.bind(this),this.getUnavailableMessage=this.getUnavailableMessage.bind(this)}getAvailabilityOverride(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;const{availableMethodOverrides:t}=this.props,n=e||this.props.method,{urlSegment:o}=n;return void 0!==t[o]?t[o]:{}}getUnavailableMessage(){const e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:null)||this.props.method;return this.getAvailabilityOverride(e).unavailableMessage||e.unavailableMessage}isAvailable(){const e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:null)||this.props.method,t=this.getAvailabilityOverride(e);let n=e.isAvailable;return void 0!==t.isAvailable&&(n=t.isAvailable),n}render(){return o.default.createElement(e,l({},this.props,{isAvailable:this.isAvailable,getUnavailableMessage:this.getUnavailableMessage}))}},n=(e=>e.displayName||e.name||"Component")(e);return t.displayName=`WithMethodAvailability(${n})`,t};t.hoc=s;var u=(0,a.compose)((0,r.connect)((e=>{const t=[...e.mfaRegister.availableMethods,...e.mfaVerify.allMethods],n={};return Object.values(t).forEach((t=>{const{urlSegment:o}=t,r=`${o}Availability`;void 0!==e[r]&&(n[o]=e[r])})),{availableMethodOverrides:n}})),s);t.default=u},2017:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["ADD_REGISTERED_METHOD","REMOVE_REGISTERED_METHOD","SET_DEFAULT_METHOD","SET_REGISTERED_METHODS"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_ADMINISTRATION.${t}`})),{});t.default=n},9861:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.setRegisteredMethods=t.setDefaultMethod=t.registerMethod=t.deregisterMethod=void 0;var o,r=(o=n(2017))&&o.__esModule?o:{default:o};t.registerMethod=e=>({type:r.default.ADD_REGISTERED_METHOD,payload:{method:e}});t.deregisterMethod=e=>({type:r.default.REMOVE_REGISTERED_METHOD,payload:{method:e}});t.setDefaultMethod=e=>({type:r.default.SET_DEFAULT_METHOD,payload:{defaultMethod:e}});t.setRegisteredMethods=e=>({type:r.default.SET_REGISTERED_METHODS,payload:{methods:e}})},6683:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:a,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};const o=e=>t=>t.urlSegment===e.urlSegment,{registeredMethods:i}=e;switch(t){case r.default.ADD_REGISTERED_METHOD:{const{method:t}=n;return Array.isArray(i)?i.find(o(t))?e:(i.push(t),{...e,registeredMethods:i}):{...e,registeredMethods:[t]}}case r.default.REMOVE_REGISTERED_METHOD:{const{method:t}=n,r=i.findIndex(o(t));if(r<0)return e;i.splice(r,1);const a=2===i.length?{defaultMethod:i.find((()=>!0)).urlSegment}:{};return{...e,...a,registeredMethods:[...i]}}case r.default.SET_DEFAULT_METHOD:return{...e,defaultMethod:n.defaultMethod};case r.default.SET_REGISTERED_METHODS:return{...e,registeredMethods:n.methods};default:return e}};var o,r=(o=n(2017))&&o.__esModule?o:{default:o};const a={defaultMethod:null,registeredMethods:[]}},3529:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["ADD_AVAILABLE_METHOD","REMOVE_AVAILABLE_METHOD","SET_AVAILABLE_METHODS","SET_SCREEN","SET_METHOD"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_REGISTER.${t}`})),{});t.default=n},8631:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.showScreen=t.setAvailableMethods=t.removeAvailableMethod=t.chooseMethod=t.addAvailableMethod=void 0;var o,r=(o=n(3529))&&o.__esModule?o:{default:o};t.showScreen=e=>({type:r.default.SET_SCREEN,payload:{screen:e}});t.chooseMethod=e=>({type:r.default.SET_METHOD,payload:{method:e}});t.setAvailableMethods=e=>({type:r.default.SET_AVAILABLE_METHODS,payload:{availableMethods:e}});t.addAvailableMethod=e=>({type:r.default.ADD_AVAILABLE_METHOD,payload:{method:e}});t.removeAvailableMethod=e=>({type:r.default.REMOVE_AVAILABLE_METHOD,payload:{method:e}})},7286:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:i,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};switch(t){case a.default.SET_SCREEN:{const{screen:t}=n;return null===e.method&&t===r.SCREEN_REGISTER_METHOD?{...e,screen:r.SCREEN_CHOOSE_METHOD}:{...e,screen:t}}case a.default.SET_METHOD:return{...e,method:n.method};case a.default.SET_AVAILABLE_METHODS:return{...e,availableMethods:n.availableMethods};case a.default.ADD_AVAILABLE_METHOD:return{...e,availableMethods:[...e.availableMethods,n.method]};case a.default.REMOVE_AVAILABLE_METHOD:return{...e,availableMethods:e.availableMethods.filter((e=>e.urlSegment!==n.method.urlSegment))};default:return e}};var o,r=n(440),a=(o=n(3529))&&o.__esModule?o:{default:o};const i={screen:r.SCREEN_INTRODUCTION,method:null,availableMethods:[]}},7282:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var n=["SET_ALL_METHODS"].reduce(((e,t)=>Object.assign(e,{[t]:`MFA_VERIFY.${t}`})),{});t.default=n},23:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(){let e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:a,{type:t,payload:n}=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};if(t===r.default.SET_ALL_METHODS)return{...e,allMethods:n.allMethods};return e};var o,r=(o=n(7282))&&o.__esModule?o:{default:o};const a={allMethods:[]}},2949:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7086))&&o.__esModule?o:{default:o};var a=r.default.shape({urlSegment:r.default.string,name:r.default.string,description:r.default.string,supportLink:r.default.string,supportText:r.default.string,thumbnail:r.default.string,component:r.default.string,isAvailable:r.default.bool,unavailableMessage:r.default.string});t.default=a},5695:function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o,r=(o=n(7086))&&o.__esModule?o:{default:o};var a=r.default.shape({name:r.default.string,urlSegment:r.default.string,isAvailable:r.default.bool,unavailableMessage:r.default.string,component:r.default.string,supportLink:r.default.string,thumbnail:r.default.string});t.default=a},640:function(e,t,n){"use strict";var o=n(1742),r={"text/plain":"Text","text/html":"Url",default:"Text"};e.exports=function(e,t){var n,a,i,l,s,u,c=!1;t||(t={}),n=t.debug||!1;try{if(i=o(),l=document.createRange(),s=document.getSelection(),(u=document.createElement("span")).textContent=e,u.ariaHidden="true",u.style.all="unset",u.style.position="fixed",u.style.top=0,u.style.clip="rect(0, 0, 0, 0)",u.style.whiteSpace="pre",u.style.webkitUserSelect="text",u.style.MozUserSelect="text",u.style.msUserSelect="text",u.style.userSelect="text",u.addEventListener("copy",(function(o){if(o.stopPropagation(),t.format)if(o.preventDefault(),void 0===o.clipboardData){n&&console.warn("unable to use e.clipboardData"),n&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var a=r[t.format]||r.default;window.clipboardData.setData(a,e)}else o.clipboardData.clearData(),o.clipboardData.setData(t.format,e);t.onCopy&&(o.preventDefault(),t.onCopy(o.clipboardData))})),document.body.appendChild(u),l.selectNodeContents(u),s.addRange(l),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");c=!0}catch(o){n&&console.error("unable to copy using execCommand: ",o),n&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(t.format||"text",e),t.onCopy&&t.onCopy(window.clipboardData),c=!0}catch(o){n&&console.error("unable to copy using clipboardData: ",o),n&&console.error("falling back to prompt"),a=function(e){var t=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C";return e.replace(/#{\s*key\s*}/g,t)}("message"in t?t.message:"Copy to clipboard: #{key}, Enter"),window.prompt(a,e)}}finally{s&&("function"==typeof s.removeRange?s.removeRange(l):s.removeAllRanges()),u&&document.body.removeChild(u),i()}return c}},9768:function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.Printd=t.createIFrame=t.createLinkStyle=t.createStyle=void 0;var n=/^(((http[s]?)|file):)?(\/\/)+([0-9a-zA-Z-_.=?&].+)$/,o=/^((\.|\.\.)?\/)([0-9a-zA-Z-_.=?&]+\/)*([0-9a-zA-Z-_.=?&]+)$/,r=function(e){return n.test(e)||o.test(e)};function a(e,t){var n=e.createElement("style");return n.appendChild(e.createTextNode(t)),n}function i(e,t){var n=e.createElement("link");return n.type="text/css",n.rel="stylesheet",n.href=t,n}function l(e){var t=window.document.createElement("iframe");return t.setAttribute("src","about:blank"),t.setAttribute("style","visibility:hidden;width:0;height:0;position:absolute;z-index:-9999;bottom:0;"),t.setAttribute("width","0"),t.setAttribute("height","0"),t.setAttribute("wmode","opaque"),e.appendChild(t),t}t.createStyle=a,t.createLinkStyle=i,t.createIFrame=l;var s={parent:window.document.body,headElements:[],bodyElements:[]},u=function(){function e(e){this.isLoading=!1,this.hasEvents=!1,this.opts=[s,e||{}].reduce((function(e,t){return Object.keys(t).forEach((function(n){return e[n]=t[n]})),e}),{}),this.iframe=l(this.opts.parent)}return e.prototype.getIFrame=function(){return this.iframe},e.prototype.print=function(e,t,n,o){if(!this.isLoading){var l=this.iframe,s=l.contentDocument,u=l.contentWindow;if(s&&u&&(this.iframe.src="about:blank",this.elCopy=e.cloneNode(!0),this.elCopy)){this.isLoading=!0,this.callback=o;var c=u.document;c.open(),c.write(''),this.addEvents();var d=this.opts,f=d.headElements,h=d.bodyElements;Array.isArray(f)&&f.forEach((function(e){return c.head.appendChild(e)})),Array.isArray(h)&&h.forEach((function(e){return c.body.appendChild(e)})),Array.isArray(t)&&t.forEach((function(e){e&&c.head.appendChild(r(e)?i(c,e):a(c,e))})),c.body.appendChild(this.elCopy),Array.isArray(n)&&n.forEach((function(e){if(e){var t=c.createElement("script");r(e)?t.src=e:t.innerText=e,c.body.appendChild(t)}})),c.close()}}},e.prototype.printURL=function(e,t){this.isLoading||(this.addEvents(),this.isLoading=!0,this.callback=t,this.iframe.src=e)},e.prototype.onBeforePrint=function(e){this.onbeforeprint=e},e.prototype.onAfterPrint=function(e){this.onafterprint=e},e.prototype.launchPrint=function(e){this.isLoading||e.print()},e.prototype.addEvents=function(){var e=this;if(!this.hasEvents){this.hasEvents=!0,this.iframe.addEventListener("load",(function(){return e.onLoad()}),!1);var t=this.iframe.contentWindow;t&&(this.onbeforeprint&&t.addEventListener("beforeprint",this.onbeforeprint),this.onafterprint&&t.addEventListener("afterprint",this.onafterprint))}},e.prototype.onLoad=function(){var e=this;if(this.iframe){this.isLoading=!1;var t=this.iframe,n=t.contentDocument,o=t.contentWindow;if(!n||!o)return;"function"==typeof this.callback?this.callback({iframe:this.iframe,element:this.elCopy,launchPrint:function(){return e.launchPrint(o)}}):this.launchPrint(o)}},e}();t.Printd=u,t.default=u},4300:function(e,t,n){"use strict";function o(e){return o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o(e)}Object.defineProperty(t,"__esModule",{value:!0}),t.CopyToClipboard=void 0;var r=l(n(7363)),a=l(n(640)),i=["text","onCopy","options","children"];function l(e){return e&&e.__esModule?e:{default:e}}function s(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var o=Object.getOwnPropertySymbols(e);t&&(o=o.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,o)}return n}function u(e){for(var t=1;t=0||(r[n]=e[n]);return r}(e,t);if(Object.getOwnPropertySymbols){var a=Object.getOwnPropertySymbols(e);for(o=0;o=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(r[n]=e[n])}return r}function d(e,t){for(var n=0;n=0;--a){var i=this.tryEntries[a],l=i.completion;if("root"===i.tryLoc)return r("end");if(i.tryLoc<=this.prev){var s=o.call(i,"catchLoc"),u=o.call(i,"finallyLoc");if(s&&u){if(this.prev=0;--n){var r=this.tryEntries[n];if(r.tryLoc<=this.prev&&o.call(r,"finallyLoc")&&this.prev=0;--t){var n=this.tryEntries[t];if(n.finallyLoc===e)return this.complete(n.completion,n.afterLoc),w(n),E}},catch:function(e){for(var t=this.tryEntries.length-1;t>=0;--t){var n=this.tryEntries[t];if(n.tryLoc===e){var o=n.completion;if("throw"===o.type){var r=o.arg;w(n)}return r}}throw new Error("illegal catch attempt")},delegateYield:function(e,n,o){return this.delegate={iterator:D(e),resultName:n,nextLoc:o},"next"===this.method&&(this.arg=t),E}},e}(e.exports);try{regeneratorRuntime=t}catch(e){"object"==typeof globalThis?globalThis.regeneratorRuntime=t:Function("r","regeneratorRuntime = r")(t)}},1742:function(e){e.exports=function(){var e=document.getSelection();if(!e.rangeCount)return function(){};for(var t=document.activeElement,n=[],o=0;o { $('[name="MFARequired"]').entwine({ /** - * Enable or disable the associated "grace period" date field + * Set grace field enabled state based on whether it's enabled or not */ - onchange() { + setGraceFieldState() { const isRequired = parseInt(this.val(), 10); if (isRequired) { $('.mfa-settings__grace-period').removeAttr('disabled'); @@ -13,10 +13,51 @@ window.jQuery.entwine('ss', ($) => { }, /** - * Ensure the "grace period" hide/show handlers wake up when the page does + * Set correct grace field enabled state when value changes + */ + onchange() { + this.setGraceFieldState(); + }, + + /** + * Set correct grace field enabled state when form loads + */ + onmatch() { + this.setGraceFieldState(); + }, + }); + + $('[name="MFAAppliesTo"]').entwine({ + /** + * Set group field visibility based on which option is selected + */ + setGroupFieldVisibility() { + // Ignore radio buttons that aren't selected. + if (!this.is(':checked')) { + return; + } + + // Toggle display + const groupField = $('.js-mfa-group-restrictions'); + if (this.val() === 'everyone') { + groupField.hide(); + } else { + groupField.show(); + } + }, + + /** + * Set group field visibility when selection changes + */ + onchange() { + this.setGroupFieldVisibility(); + }, + + /** + * Set group field visibility when form loads */ onmatch() { - this.onchange(); + this.setGroupFieldVisibility(); }, }); }); diff --git a/src/Extension/SiteConfigExtension.php b/src/Extension/SiteConfigExtension.php index bfa3ff31..42fb6aa2 100644 --- a/src/Extension/SiteConfigExtension.php +++ b/src/Extension/SiteConfigExtension.php @@ -6,10 +6,12 @@ use SilverStripe\Forms\CompositeField; use SilverStripe\Forms\DateField; use SilverStripe\Forms\FieldList; -use SilverStripe\Forms\ListboxField; use SilverStripe\Forms\OptionsetField; +use SilverStripe\Forms\TreeMultiselectField; +use SilverStripe\MFA\Service\EnforcementManager; use SilverStripe\ORM\DataExtension; use SilverStripe\ORM\FieldType\DBField; +use SilverStripe\ORM\ValidationResult; use SilverStripe\Security\Group; use SilverStripe\View\Requirements; @@ -34,6 +36,9 @@ class SiteConfigExtension extends DataExtension private static $db = [ 'MFARequired' => 'Boolean', 'MFAGracePeriodExpires' => 'Date', + 'MFAAppliesTo' => 'Enum(["' + . EnforcementManager::APPLIES_TO_EVERYONE . '","' + . EnforcementManager::APPLIES_TO_GROUPS . '"])', ]; private static $many_many = [ @@ -53,8 +58,8 @@ public function updateCMSFields(FieldList $fields) 'MFARequired', '', [ - false => _t(__CLASS__ . '.MFA_OPTIONAL', 'MFA is optional for everyone'), - true => _t(__CLASS__ . '.MFA_REQUIRED', 'MFA is required for everyone'), + false => _t(__CLASS__ . '.MFA_OPTIONAL2', 'MFA is optional'), + true => _t(__CLASS__ . '.MFA_REQUIRED2', 'MFA is required'), ] ); $mfaOptions->addExtraClass('mfa-settings__required'); @@ -69,29 +74,28 @@ public function updateCMSFields(FieldList $fields) )); $mfaGraceEnd->addExtraClass('mfa-settings__grace-period'); - $groupsMap = []; - foreach (Group::get() as $group) { - // Listboxfield values are escaped, use ASCII char instead of » - $groupsMap[$group->ID] = $group->getBreadcrumbs(' > '); - } - asort($groupsMap); - - $mfaGroupRestrict = ListboxField::create( - "MFAGroupRestrictions", - _t(__CLASS__ . '.MFA_GROUP_RESTRICTIONS', "MFA Groups") - ) - ->setSource($groupsMap) - ->setAttribute( - 'data-placeholder', - _t(__CLASS__ . '.MFA_GROUP_RESTRICTIONS_PLACEHOLDER', 'Click to select group') - ) - ->setDescription(_t( - __CLASS__ . '.MFA_GROUP_RESTRICTIONS_DESCRIPTION', - 'MFA will only be enabled for members of these selected groups. ' . - 'If no groups are selected, MFA will be enabled for all users' - )); + $mfaAppliesToWho = OptionsetField::create( + 'MFAAppliesTo', + _t(__CLASS__ . '.MFA_APPLIES_TO_TITLE', 'Who do these MFA settings apply to?'), + [ + EnforcementManager::APPLIES_TO_EVERYONE => _t(__CLASS__ . '.EVERYONE', 'Everyone'), + EnforcementManager::APPLIES_TO_GROUPS => _t( + __CLASS__ . '.ONLY_GROUPS', + 'Only these groups (choose from list)' + ), + ] + ); - $mfaOptions = CompositeField::create($mfaOptions, $mfaGraceEnd, $mfaGroupRestrict) + $mfaGroupRestrict = TreeMultiselectField::create( + 'MFAGroupRestrictions', + _t(__CLASS__ . '.MFA_GROUP_RESTRICTIONS', 'MFA Groups'), + Group::class + )->setDescription(_t( + __CLASS__ . '.MFA_GROUP_RESTRICTIONS_DESCRIPTION', + 'MFA will only be enabled for members of these selected groups.' + ))->addExtraClass('js-mfa-group-restrictions'); + + $mfaOptions = CompositeField::create($mfaOptions, $mfaGraceEnd, $mfaAppliesToWho, $mfaGroupRestrict) ->setTitle(DBField::create_field( 'HTMLFragment', _t(__CLASS__ . '.MULTI_FACTOR_AUTHENTICATION', 'Multi-factor authentication (MFA)') @@ -101,6 +105,22 @@ public function updateCMSFields(FieldList $fields) $fields->addFieldToTab('Root.Access', $mfaOptions); } + public function validate(ValidationResult $validationResult) + { + if ( + $this->owner->MFAAppliesTo == EnforcementManager::APPLIES_TO_GROUPS + && !$this->owner->MFAGroupRestrictions()->exists() + ) { + $validationResult->addFieldError( + 'MFAGroupRestrictions', + _t( + __CLASS__ . '.MFA_GROUP_RESTRICTIONS_VALIDATION', + 'At least one group must be selected, or the MFA settings should apply to everyone.' + ) + ); + } + } + /** * Gets an anchor tag for CMS users to click to find out more about MFA in the SilverStripe CMS * diff --git a/src/Service/EnforcementManager.php b/src/Service/EnforcementManager.php index 3b6f6d4a..3ac9dcc2 100644 --- a/src/Service/EnforcementManager.php +++ b/src/Service/EnforcementManager.php @@ -23,6 +23,9 @@ class EnforcementManager use Configurable; use Injectable; + public const APPLIES_TO_EVERYONE = 'everyone'; + public const APPLIES_TO_GROUPS = 'groups'; + /** * Indicate how many MFA methods the user must authenticate with before they are considered logged in * @@ -72,7 +75,7 @@ public function canSkipMFA(Member $member): bool return true; } - if ($this->isMFARequired()) { + if ($this->isMFARequired() && $this->isUserInMFAEnabledGroup($member)) { return false; } @@ -108,14 +111,14 @@ public function shouldRedirectToMFA(Member $member): bool return false; } - if (!$this->isUserInMFAEnabledGroup($member) && !$this->hasCompletedRegistration($member)) { - return false; - } - if ($member->RegisteredMFAMethods()->exists()) { return true; } + if (!$this->isUserInMFAEnabledGroup($member) && !$this->hasCompletedRegistration($member)) { + return false; + } + if ($this->isGracePeriodInEffect()) { return true; } @@ -156,7 +159,9 @@ public function hasCompletedRegistration(Member $member): bool * Whether MFA is required for eligible users. This takes into account whether a grace period is set and whether * we're currently inside the window for it. * - * Note that in determining this, we ignore whether or not MFA is enabled for the site in general. + * Note that in determining this, we ignore whether or not MFA is enabled for the site in general. We also ignore + * whether any given member is in the list of groups for which MFA has been enabled - for that, call + * {@see isUserInMFAEnabledGroup()} * * @return bool */ @@ -276,17 +281,19 @@ protected function isUserInMFAEnabledGroup(Member $member): bool /** @var SiteConfig&SiteConfigExtension $siteConfig */ $siteConfig = SiteConfig::current_site_config(); + // If we aren't restricting by groups, then we pass this check and move on + // to any other applicable checks. + if ($siteConfig->MFAAppliesTo !== self::APPLIES_TO_GROUPS) { + return true; + } + $groups = $siteConfig->MFAGroupRestrictions(); - // If no groups are set in the Site Config MFAGroupRestrictions field, MFA is enabled for all users + // If no groups are set in the Site Config MFAGroupRestrictions field, MFA is enabled for all users. + // This should generally not be possible, but can happen if a group is deleted after being set in that field. if ($groups->count() === 0) { return true; } - foreach ($groups as $group) { - if ($member->inGroup($group)) { - return true; - } - } - return false; + return $member->inGroups($groups); } } diff --git a/tests/Behat/Context/LoginContext.php b/tests/Behat/Context/LoginContext.php index f337780f..fd561458 100644 --- a/tests/Behat/Context/LoginContext.php +++ b/tests/Behat/Context/LoginContext.php @@ -44,7 +44,7 @@ public function multiFactorAuthenticationIsOptional() */ public function iSelectFromTheMfaSettings($option) { - $value = $option === 'MFA is required for everyone' ? 1 : 0; + $value = $option === 'MFA is required' ? 1 : 0; $this->getMainContext()->selectOption('MFARequired', $value); } } diff --git a/tests/Behat/features/mfa-enabled.feature b/tests/Behat/features/mfa-enabled.feature index 3db7b49d..21315599 100644 --- a/tests/Behat/features/mfa-enabled.feature +++ b/tests/Behat/features/mfa-enabled.feature @@ -8,10 +8,46 @@ Feature: MFA is enabled for the site And I go to "/admin" Then I should see the CMS - Scenario: I can set MFA to be required + Scenario: I can set MFA to be required for all users Given I go to "/admin/settings" And I click the "Access" CMS tab Then I should see "Multi-factor authentication (MFA)" - When I select "MFA is required for everyone" from the MFA settings + When I select "MFA is required" from the MFA settings And I press "Save" Then I should see a "Saved" success toast + + # This scenario must be before any other "select a group" scenario, since the saved settings + # aren't reset between scenarios. + Scenario: I must add at least one group if requiring MFA for groups + Given I go to "/admin/settings" + And I click the "Access" CMS tab + Then I should see "Multi-factor authentication (MFA)" + When I select "MFA is required" from the MFA settings + And I select "Only these groups (choose from list)" from "Who do these MFA settings apply to?" input group + And I press "Save" + Then I should not see a "Saved" success toast + Then I should see "At least one group must be selected, or the MFA settings should apply to everyone." + + Scenario: I can set MFA to be required for a given group + Given I go to "/admin/settings" + And I click the "Access" CMS tab + Then I should see "Multi-factor authentication (MFA)" + When I select "MFA is required" from the MFA settings + Then I should not see "MFA Groups" + When I select "Only these groups (choose from list)" from "Who do these MFA settings apply to?" input group + Then I should see "MFA Groups" + When I select "ADMIN group" in the "#Form_EditForm_MFAGroupRestrictions_Holder" tree dropdown + And I press "Save" + Then I should see a "Saved" success toast + Then I should not see "At least one group must be selected, or the MFA settings should apply to everyone." + + Scenario: I can set MFA to be optional for a given group + Given I go to "/admin/settings" + And I click the "Access" CMS tab + Then I should see "Multi-factor authentication (MFA)" + When I select "MFA is optional" from the MFA settings + And I select "Only these groups (choose from list)" from "Who do these MFA settings apply to?" input group + And I select "ADMIN group" in the "#Form_EditForm_MFAGroupRestrictions_Holder" tree dropdown + And I press "Save" + Then I should see a "Saved" success toast + Then I should not see "At least one group must be selected, or the MFA settings should apply to everyone." diff --git a/tests/php/Authenticator/LoginHandlerTest.php b/tests/php/Authenticator/LoginHandlerTest.php index 8173b492..9b315330 100644 --- a/tests/php/Authenticator/LoginHandlerTest.php +++ b/tests/php/Authenticator/LoginHandlerTest.php @@ -26,6 +26,7 @@ use SilverStripe\MFA\Tests\Stub\Store\TestStore; use SilverStripe\MFA\Tests\Stub\BasicMath\Method; use SilverStripe\ORM\FieldType\DBDatetime; +use SilverStripe\ORM\ValidationException; use SilverStripe\Security\Group; use SilverStripe\Security\Member; use SilverStripe\Security\Security; @@ -573,42 +574,72 @@ public function testGetBackURL() $this->assertSame('foobar', $handler->getBackURL()); } + public function testMFAGroupRestrictionValidation() + { + $config = SiteConfig::current_site_config(); + $config->MFAAppliesTo = EnforcementManager::APPLIES_TO_GROUPS; + $this->expectException(ValidationException::class); + $config->write(); + } + + public function provideMFAGroupRestriction() + { + return [ + 'member in group, has registered method' => [ + 'memberFixture' => 'simon', + 'hasMFA' => true, + ], + 'member in group, with no registered method' => [ + 'memberFixture' => 'guy', + 'hasMFA' => true, + ], + 'member not in group, has registered method' => [ + 'memberFixture' => 'colin', + 'hasMFA' => true, + ], + 'member not in group, with no registered method' => [ + 'memberFixture' => 'carla', + 'hasMFA' => false, + ], + ]; + } - public function testMFAGroupRestriction() + /** + * @dataProvider provideMFAGroupRestriction + */ + public function testMFAGroupRestriction(string $memberFixture, bool $hasMFA) { $config = SiteConfig::current_site_config(); /** @var Group $group */ $group = $this->objFromFixture(Group::class, 'admingroup'); $config->MFAGroupRestrictions()->add($group); + $config->MFAAppliesTo = EnforcementManager::APPLIES_TO_GROUPS; + $config->write(); - // Test that MFA is required for a member of a group that has been set in SiteConfig /** @var Member&MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'guy'); + $member = $this->objFromFixture(Member::class, $memberFixture); $this->autoFollowRedirection = false; $response = $this->doLogin($member, 'Password123'); $this->autoFollowRedirection = true; + // Validate that MFA is only enabled for the relevant group, and for users who already registered an MFA method + $path = $hasMFA ? 'default/mfa' : 'default'; $this->assertSame(302, $response->getStatusCode()); $this->assertStringEndsWith( - Controller::join_links(Security::login_url(), 'default/mfa'), + Controller::join_links(Security::login_url(), $path), $response->getHeader('location') ); - // Test that MFA is not required for a member that does not belong to any of the selected groups - /** @var Member&MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'colin'); - - $this->autoFollowRedirection = false; - $response = $this->doLogin($member, 'Password123'); - $this->autoFollowRedirection = true; - - $this->assertSame(302, $response->getStatusCode()); - $this->assertStringEndsWith( - Security::login_url(), - $response->getHeader('location') - ); + // Validate that the member logged in successfully if MFA was not available. + if (!$hasMFA) { + $response = $this->get('/Security/login'); + $this->assertExactMatchBySelector( + '#MemberLoginForm_LoginForm_error', + "You're logged in as {$member->FirstName}." + ); + } } public function methodlessMemberFixtureProvider() diff --git a/tests/php/Authenticator/LoginHandlerTest.yml b/tests/php/Authenticator/LoginHandlerTest.yml index c85be77f..3f21a526 100644 --- a/tests/php/Authenticator/LoginHandlerTest.yml +++ b/tests/php/Authenticator/LoginHandlerTest.yml @@ -25,20 +25,25 @@ SilverStripe\Security\Group: SilverStripe\Security\Member: guy: + FirstName: Guy Email: guy@example.com Password: Password123 PasswordExpiry: 2030-01-01 Groups: =>SilverStripe\Security\Group.admingroup simon: + FirstName: Simon Email: simon@example.com + Password: Password123 RegisteredMFAMethods: =>SilverStripe\MFA\Model\RegisteredMethod.simon-math Groups: =>SilverStripe\Security\Group.admingroup robbie: + FirstName: Robbie Email: robbie@example.com RegisteredMFAMethods: =>SilverStripe\MFA\Model\RegisteredMethod.robbie-math DefaultRegisteredMethodID: =>SilverStripe\MFA\Model\RegisteredMethod.robbie-math Groups: =>SilverStripe\Security\Group.admingroup colin: + FirstName: Colin Email: colin@example.com Password: Password123 PasswordExpiry: 2030-01-01 @@ -46,9 +51,13 @@ SilverStripe\Security\Member: DefaultRegisteredMethodID: =>SilverStripe\MFA\Model\RegisteredMethod.colin-math Groups: =>SilverStripe\Security\Group.contentgroup carla: + FirstName: Carla Email: carla@example.com + Password: Password123 Groups: =>SilverStripe\Security\Group.contentgroup pete: + FirstName: Pete Email: pete@example.com + Password: Password123 PasswordExpiry: 1990-01-01 Groups: =>SilverStripe\Security\Group.contentgroup diff --git a/tests/php/Service/EnforcementManagerTest.php b/tests/php/Service/EnforcementManagerTest.php index fa7cd5e7..530c306a 100644 --- a/tests/php/Service/EnforcementManagerTest.php +++ b/tests/php/Service/EnforcementManagerTest.php @@ -31,190 +31,602 @@ protected function setUp(): void EnforcementManager::config()->set('enabled', true); } - public function testUserCanSkipWhenMFAIsDisabled() + public function provideCanSkipMFA() { - $this->setSiteConfig(['MFARequired' => true]); - EnforcementManager::config()->set('enabled', false); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sally_smith'); - $this->assertTrue(EnforcementManager::create()->canSkipMFA($member)); + $scenarios = [ + // User with registered MFA option can _never_ skip MFA + 'already registered, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + 'already registered, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + 'already registered, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + 'already registered, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + 'already registered, NOT in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + 'already registered, NOT in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sally_smith', + 'expected' => false, + ], + // User without registered MFA option can skip unless they're not in a specified group + 'not registered, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'john_smith', + 'expected' => false, + ], + 'not registered, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'john_smith', + 'expected' => false, + ], + 'not registered, NOT in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, NOT in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + // Always skip if user has no CMS access + // Note that this is altered by the "requires_admin_access" config, which is tested separately. + 'no cms access, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'no cms access, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'no cms access, not in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'no cms access, not in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'no cms access, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'no cms access, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + ]; + // Add scenarios with past and future expiry dates + // See the setUp method, which sets the current datetime to "2019-01-25 12:00:00" + foreach ($scenarios as $name => $scenario) { + // Past expiry dates + $pastScenario = $scenario; + $pastScenario['mfaGracePeriodExpires'] = '2018-12-25'; + $scenarios[$name . ' with past expiry'] = $pastScenario; + // Future expiry dates + $futureScenario = $scenario; + $futureScenario['mfaGracePeriodExpires'] = '2019-01-30'; + // Members who haven't registered MFA yet can skip if there's a currently-active grace period + if ($futureScenario['memberFixture'] === 'john_smith') { + $futureScenario['expected'] = true; + } + $scenarios[$name . ' with future expiry'] = $futureScenario; + } + return $scenarios; } - public function testUserCanSkipWhenNoMethodsAreAvailable() - { - $this->setSiteConfig(['MFARequired' => true]); - MethodRegistry::config()->set('methods', null); + /** + * @dataProvider provideCanSkipMFA + */ + public function testCanSkipMFA( + bool $mfaRequired, + string $mfaAppliesTo, + ?string $mfaGracePeriodExpires, + array $requiredGroupFixtures, + string $memberFixture, + bool $expected + ) { + $config = SiteConfig::current_site_config(); + foreach ($requiredGroupFixtures as $fixtureName) { + $group = $this->objFromFixture(Group::class, $fixtureName); + $config->MFAGroupRestrictions()->add($group); + } + $siteConfigUpdate = ['MFARequired' => $mfaRequired, 'MFAAppliesTo' => $mfaAppliesTo]; + if ($mfaGracePeriodExpires) { + $siteConfigUpdate['MFAGracePeriodExpires'] = $mfaGracePeriodExpires; + } + $this->setSiteConfig($siteConfigUpdate); /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sally_smith'); - $this->assertTrue(EnforcementManager::create()->canSkipMFA($member)); + $member = $this->objFromFixture(Member::class, $memberFixture); + $this->logInAs($member); + + $this->assertSame($expected, EnforcementManager::create()->canSkipMFA($member)); } - public function testUserWithoutCMSAccessCanSkipWhenCMSAccessIsRequired() + public function provideCanSkipMFAWithoutCMSAccess() { - $this->setSiteConfig(['MFARequired' => true]); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sammy_smith'); - $this->assertTrue(EnforcementManager::create()->canSkipMFA($member)); + return [ + 'optional, applies to everyone' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'required, applies to everyone' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'optional, not in group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'required, not in group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'optional, in group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'required, in group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + ]; } - public function testUserWithoutCMSAccessCannotSkipWhenCMSAccessIsNotRequired() - { - $this->setSiteConfig(['MFARequired' => true]); + /** + * @dataProvider provideCanSkipMFAWithoutCMSAccess + */ + public function testCanSkipMFAWithoutCMSAccess( + bool $mfaRequired, + string $mfaAppliesTo, + array $requiredGroupFixtures, + string $memberFixture, + bool $expected + ) { EnforcementManager::config()->set('requires_admin_access', false); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sammy_smith'); - $this->assertFalse(EnforcementManager::create()->canSkipMFA($member)); + $this->testCanSkipMFA($mfaRequired, $mfaAppliesTo, null, $requiredGroupFixtures, $memberFixture, $expected); } - public function testCannotSkipWhenMFAIsRequiredWithNoGracePeriod() + public function testCanSkipWhenMFAIsDisabled() { $this->setSiteConfig(['MFARequired' => true]); + EnforcementManager::config()->set('enabled', false); /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'reports_user'); - $this->assertFalse(EnforcementManager::create()->canSkipMFA($member)); - } - - public function testCanSkipWhenMFAIsRequiredWithGracePeriodExpiringInFuture() - { - $this->setSiteConfig(['MFARequired' => true, 'MFAGracePeriodExpires' => '2019-01-30']); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'reports_user'); + $member = $this->objFromFixture(Member::class, 'sally_smith'); $this->assertTrue(EnforcementManager::create()->canSkipMFA($member)); } - public function testCannotSkipWhenMFAIsRequiredWithGracePeriodExpiringInPast() + public function testCanSkipWhenNoMethodsAreAvailable() { - $this->setSiteConfig(['MFARequired' => true, 'MFAGracePeriodExpires' => '2018-12-25']); + $this->setSiteConfig(['MFARequired' => true]); + MethodRegistry::config()->set('methods', null); - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'reports_user'); - $this->assertFalse(EnforcementManager::create()->canSkipMFA($member)); - } - - public function testCannotSkipWhenMemberHasRegisteredAuthenticationMethodsSetUp() - { - $this->setSiteConfig(['MFARequired' => false]); - // Sally has "backup codes" as a registered authentication method already /** @var Member $member */ $member = $this->objFromFixture(Member::class, 'sally_smith'); - $this->logInAs($member); - - $this->assertFalse(EnforcementManager::create()->canSkipMFA($member)); - } - - public function testCanSkipWhenMFAIsOptional() - { - $this->setSiteConfig(['MFARequired' => false]); - // Anonymous admin user - $memberId = $this->logInWithPermission(); - /** @var Member $member */ - $member = Member::get()->byID($memberId); - $this->assertTrue(EnforcementManager::create()->canSkipMFA($member)); } - public function testShouldNotRedirectToMFAWhenUserDoesNotHaveCMSAccess() + public function provideShouldRedirectToMFA() { - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sammy_smith'); - $this->logInAs($member); - $this->assertFalse(EnforcementManager::create()->shouldRedirectToMFA($member)); + $scenarios = [ + // User with registered MFA option should _always_ redirect to MFA + 'already registered, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + 'already registered, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + 'already registered, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + 'already registered, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + 'already registered, NOT in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + 'already registered, NOT in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sally_smith', + 'expected' => true, + ], + // User without registered MFA option should only redirect if rules apply to them + 'not registered, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'john_smith', + 'expected' => true, + ], + 'not registered, NOT in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'john_smith', + 'expected' => false, + ], + 'not registered, NOT in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'john_smith', + 'expected' => false, + ], + // User who has skipped MFA registration has slightly different behaviour + 'skipped registration, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sully_smith', + 'expected' => false, + ], + 'skipped registration, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sully_smith', + 'expected' => true, + ], + 'skipped registration, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sully_smith', + 'expected' => false, + ], + 'skipped registration, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['reportsgroup'], + 'memberFixture' => 'sully_smith', + 'expected' => true, + ], + 'skipped registration, NOT in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sully_smith', + 'expected' => false, + ], + 'skipped registration, NOT in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sully_smith', + 'expected' => false, + ], + // Should never redirect to MFA if user has no CMS access + // Note that this is altered by the "requires_admin_access" config, which is tested separately. + 'no cms access, optional for all' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'no cms access, required for all' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'no cms access, not in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'no cms access, not in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'no cms access, in optional group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'no cms access, in required group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'mfaGracePeriodExpires' => null, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + ]; + // Add scenarios with past and future expiry dates + // See the setUp method, which sets the current datetime to "2019-01-25 12:00:00" + // Note that the grace period doesn't affect the expected return value. These scenarios are here + // to ensure that doesn't change unexpectedly. + foreach ($scenarios as $name => $scenario) { + // Past expiry dates + $pastScenario = $scenario; + $pastScenario['mfaGracePeriodExpires'] = '2018-12-25'; + $scenarios[$name . ' with past expiry'] = $pastScenario; + // Future expiry dates + $futureScenario = $scenario; + $futureScenario['mfaGracePeriodExpires'] = '2019-01-30'; + $scenarios[$name . ' with future expiry'] = $futureScenario; + } + return $scenarios; } - public function testShouldRedirectToMFAWhenUserDoesNotHaveCMSAccessButTheCheckIsDisabledWithConfig() - { - EnforcementManager::config()->set('requires_admin_access', false); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sammy_smith'); - $this->logInAs($member); - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldRedirectToMFAWhenUserHasAccessToReportsOnly() - { - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'reports_user'); - $this->logInAs($member); - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldRedirectToMFAForContentAuthors() - { - $memberID = $this->logInWithPermission('CMS_ACCESS_CMSMain'); - /** @var Member $member */ - $member = Member::get()->byID($memberID); - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldRedirectToMFAWhenUserHasRegisteredMFAMethod() - { - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sally_smith'); - $shouldRedirect = EnforcementManager::create()->shouldRedirectToMFA($member); - $this->assertTrue($shouldRedirect); - } + /** + * @dataProvider provideShouldRedirectToMFA + */ + public function testShouldRedirectToMFA( + bool $mfaRequired, + string $mfaAppliesTo, + ?string $mfaGracePeriodExpires, + array $requiredGroupFixtures, + string $memberFixture, + bool $expected + ) { + $config = SiteConfig::current_site_config(); + foreach ($requiredGroupFixtures as $fixtureName) { + $group = $this->objFromFixture(Group::class, $fixtureName); + $config->MFAGroupRestrictions()->add($group); + } + $siteConfigUpdate = ['MFARequired' => $mfaRequired, 'MFAAppliesTo' => $mfaAppliesTo]; + if ($mfaGracePeriodExpires) { + $siteConfigUpdate['MFAGracePeriodExpires'] = $mfaGracePeriodExpires; + } + $this->setSiteConfig($siteConfigUpdate); - public function testShouldRedirectToMFAWhenMFAIsRequired() - { - $this->setSiteConfig(['MFARequired' => true]); /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sully_smith'); + $member = $this->objFromFixture(Member::class, $memberFixture); $this->logInAs($member); - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); + $this->assertSame($expected, EnforcementManager::create()->shouldRedirectToMFA($member)); } - public function testShouldRedirectToMFAWhenMFAIsRequiredWithGracePeriodExpiringInFuture() + public function provideShouldRedirectToMFAWithoutCMSAccess() { - $this->setSiteConfig(['MFARequired' => true, 'MFAGracePeriodExpires' => '2019-01-30']); - - /** @var Member&MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'sully_smith'); - $this->logInAs($member); - - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); + return [ + 'optional, applies to everyone' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'required, applies to everyone' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_EVERYONE, + 'requiredGroupFixtures' => [], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'optional, not in group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'required, not in group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['admingroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => false, + ], + 'optional, in group' => [ + 'MFARequired' => false, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + 'required, in group' => [ + 'MFARequired' => true, + 'MFAAppliesTo' => EnforcementManager::APPLIES_TO_GROUPS, + 'requiredGroupFixtures' => ['nocmsgroup'], + 'memberFixture' => 'sammy_smith', + 'expected' => true, + ], + ]; } - public function testShouldRedirectToMFAWhenMFAIsRequiredWithGracePeriodExpiringInPast() - { - $this->setSiteConfig(['MFARequired' => true, 'MFAGracePeriodExpires' => '2018-12-25']); - - /** @var Member&MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'sully_smith'); - $this->logInAs($member); - - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldRedirectToMFAWhenMFAIsOptionalAndHasNotBeenSkipped() - { - $this->setSiteConfig(['MFARequired' => false]); - - /** @var Member|MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'sally_smith'); - $member->HasSkippedMFARegistration = false; - $member->write(); - $this->logInAs($member); - - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldNotRedirectToMFAWhenMFAIsOptionalAndHasBeenSkipped() - { - $this->setSiteConfig(['MFARequired' => false]); - - /** @var Member&MemberExtension $member */ - $member = $this->objFromFixture(Member::class, 'sully_smith'); - $this->logInAs($member); - - $this->assertFalse(EnforcementManager::create()->shouldRedirectToMFA($member)); + /** + * @dataProvider provideShouldRedirectToMFAWithoutCMSAccess + */ + public function testShouldRedirectToMFAWithoutCMSAccess( + bool $mfaRequired, + string $mfaAppliesTo, + array $requiredGroupFixtures, + string $memberFixture, + bool $expected + ) { + EnforcementManager::config()->set('requires_admin_access', false); + $this->testShouldRedirectToMFA( + $mfaRequired, + $mfaAppliesTo, + null, + $requiredGroupFixtures, + $memberFixture, + $expected + ); } public function testShouldNotRedirectToMFAWhenConfigIsDisabled() @@ -254,34 +666,6 @@ public function testUserHasCompletedRegistrationWhenBackupMethodIsDisabled() $this->assertTrue(EnforcementManager::create()->hasCompletedRegistration($member)); } - public function testShouldRedirectToMFAWhenUserIsInMFARestrictedGroup() - { - $this->setSiteConfig(['MFARequired' => true]); - $config = SiteConfig::current_site_config(); - $group = $this->objFromFixture(Group::class, 'admingroup'); - $config->MFAGroupRestrictions()->add($group); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sally_smith'); - $this->logInAs($member); - - $this->assertTrue(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - - public function testShouldNotRedirectToMFAWhenUserIsNotInMFARestrictedGroup() - { - $this->setSiteConfig(['MFARequired' => true]); - $config = SiteConfig::current_site_config(); - $group = $this->objFromFixture(Group::class, 'admingroup'); - $config->MFAGroupRestrictions()->add($group); - - /** @var Member $member */ - $member = $this->objFromFixture(Member::class, 'sully_smith'); - $this->logInAs($member); - - $this->assertFalse(EnforcementManager::create()->shouldRedirectToMFA($member)); - } - /** * Helper method for changing the current SiteConfig values * diff --git a/tests/php/Service/EnforcementManagerTest.yml b/tests/php/Service/EnforcementManagerTest.yml index 3c56e75c..aefe3e3e 100644 --- a/tests/php/Service/EnforcementManagerTest.yml +++ b/tests/php/Service/EnforcementManagerTest.yml @@ -17,6 +17,9 @@ SilverStripe\Security\Group: Title: View reports Code: reportsgroup Permissions: =>SilverStripe\Security\Permission.reports + nocmsgroup: + Title: No CMS Access + Code: nocmsgroup SilverStripe\Security\Member: sally_smith: @@ -27,10 +30,16 @@ SilverStripe\Security\Member: - =>SilverStripe\MFA\Model\RegisteredMethod.codes DefaultRegisteredMethodID: =>SilverStripe\MFA\Model\RegisteredMethod.codes Groups: =>SilverStripe\Security\Group.admingroup + john_smith: + FirstName: John + Surname: Smith + Email: john.smith@example.com + Groups: =>SilverStripe\Security\Group.admingroup sammy_smith: FirstName: Sammy Surname: Smith Email: sammy.smith@example.com + Groups: =>SilverStripe\Security\Group.nocmsgroup sully_smith: FirstName: Sully Surname: Smith