@microsoft/windows-admin-center-sdk
Version:
Microsoft - Windows Admin Center Shell
1 lines • 7.62 kB
Source Map (JSON)
{"version":3,"sources":["../../../packages/core/data/asset-manager.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAE7D;;GAEG;AACH,qBAAa,YAAY;IAiBT,OAAO,CAAC,mBAAmB;IAA6B,OAAO,CAAC,MAAM,CAAC;IAAW,OAAO,CAAC,eAAe,CAAC;IAhBtH;;OAEG;IACH,IAAW,KAAK,YAEf;IAED;;OAEG;IACH,IAAW,cAAc,YAExB;IAED,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAW;gBAEpB,mBAAmB,EAAE,mBAAmB,CAAC,IAAI,CAAC,EAAU,MAAM,CAAC,EAAE,OAAO,EAAU,eAAe,CAAC,EAAE,OAAO;IAExH,QAAQ,CAAC,KAAK,EAAE,MAAM;IAQ7B;;;;;OAKG;IACI,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,aAAa,GAAG,IAAI;IAsFrE,SAAS,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,IAAI;IAyBjD;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;CAe5B","file":"asset-manager.d.ts","sourcesContent":["import { LogLevel } from '../diagnostics/log-level';\r\nimport { Logging } from '../diagnostics/logging';\r\nimport { LocalizationManager } from './localization-manager';\r\n\r\n/**\r\n * Class for asset manager\r\n */\r\nexport class AssetManager {\r\n /**\r\n * Getter for cssV2.\r\n */\r\n public get cssV2() {\r\n return !!this._cssV2;\r\n }\r\n\r\n /**\r\n * Getter for if the target is React.\r\n */\r\n public get reactExtension() {\r\n return !!this._reactExtension;\r\n }\r\n\r\n private readonly fontsKeyword = 'fonts';\r\n\r\n constructor(private localizationManager: LocalizationManager<void>, private _cssV2?: boolean, private _reactExtension?: boolean) { }\r\n\r\n public setTheme(theme: string) {\r\n const self = MsftSme.self();\r\n const oldTheme = self.Resources.theme;\r\n self.Resources.theme = theme;\r\n // apply the theme class to the body of the document\r\n document.body.classList.remove(`sme-theme-${oldTheme}`);\r\n document.body.classList.add(`sme-theme-${theme}`);\r\n }\r\n /**\r\n * Injects dynamic assets (css, js, etc..) from the shell\r\n * This is only meant to be called once during an extensions lifecycle (during init)\r\n * @param theme the current theme name\r\n * @param assets the assets to process\r\n */\r\n public loadAssets(theme: string, assets: MsftSme.MsftSmeAssets): void {\r\n const self = MsftSme.self();\r\n self.Resources.assets = assets;\r\n\r\n this.setTheme(theme);\r\n\r\n if (!assets) {\r\n return;\r\n }\r\n\r\n // Do not load css if it is a react extension.\r\n if (this.reactExtension) {\r\n Logging.log({\r\n level: LogLevel.Informational,\r\n message: 'React extension detected. Skip loading css from shell.',\r\n source: 'AssetManager.loadAssets'\r\n });\r\n return;\r\n }\r\n\r\n // inject css tags into header\r\n let cssAssets = assets.css;\r\n if (this._cssV2) {\r\n if (assets.cssV2) {\r\n cssAssets = assets.cssV2;\r\n Logging.log({\r\n level: LogLevel.Informational,\r\n message: 'Using cssV2',\r\n source: 'AssetManager.loadAssets'\r\n });\r\n } else if (assets.css) {\r\n // Backup solution for scenario where customer using GA release shell before publishing the cssV2 feature with\r\n // repository that has been using the cssV2.\r\n // In this case, we only allow fonts override to happen.\r\n cssAssets = this.updateCssV2Assets(assets.css);\r\n\r\n Logging.log({\r\n level: LogLevel.Warning,\r\n message: 'Empty assets warning. Using older assets for fonts. It is suggested to update the WAC to the latest(2211 release) GA build.',\r\n source: 'AssetManager.loadAssets'\r\n });\r\n } else {\r\n Logging.log({\r\n level: LogLevel.Critical,\r\n message: 'Empty assets. Try disable cache and refresh the browser or re-install the latest WAC build',\r\n source: 'AssetManager.loadAssets'\r\n });\r\n }\r\n }\r\n\r\n this.appendAssets(cssAssets);\r\n\r\n /**\r\n * The js injection mechanism below is subject to the following attack:\r\n *\r\n * 1. User visits malicious website (MW) from their workstation\r\n * 2. MW randomly or sequentially opens hidden iframes to localhost on various ports.\r\n * 3. once each iframe loads it send rpc init and impersonates the shell side of the communication channel\r\n * 4. The iframe will respond because it trusts * domains for onMessage requests.(this is a basic requirement of our infrastructure)\r\n * 5. The MW can then inject any javascript it wants into the module and presumably knows the gateway is running on the same port.\r\n * 6. Because we use windows authentication, the MW can execute powershell requests on any servers the user has access to.\r\n * 7. The MW has now compromised the server acting as the user.\r\n *\r\n * How to fix:\r\n * In order for this to work, we need an ironclad way of validating that our parent is the shell.\r\n * some possibilities are:\r\n *\r\n * 1. Three way handshake with gateway to discover the only acceptable shell origin.\r\n * a. this could be done with javascript or it could be a static file that the module always reads at startup\r\n * 2. certificate based authentication before rpc communication\r\n * 3. other methods?\r\n *\r\n * Disabling until we have a more solid use case and we know the most secure way to achieve this functionality.\r\n */\r\n\r\n // // inject js tags into header\r\n // if (assets.js) {\r\n // assets.js.forEach(href => {\r\n // let script = document.createElement('script');\r\n // script.setAttribute('type', 'text/javascript');\r\n // script.setAttribute('src', href);\r\n // head.appendChild(script);\r\n // });\r\n // }\r\n }\r\n\r\n protected appendAssets(cssAssets: string[]): void {\r\n if (!cssAssets) {\r\n return;\r\n }\r\n\r\n // get the page header\r\n const head = document.getElementsByTagName('head')[0];\r\n\r\n cssAssets.forEach(href => {\r\n const link: HTMLLinkElement = document.createElement('link');\r\n link.rel = 'stylesheet';\r\n link.type = 'text/css';\r\n link.crossOrigin = 'cors';\r\n link.href = href;\r\n\r\n Logging.log({\r\n level: LogLevel.Informational,\r\n message: link,\r\n source: 'AssetManager.loadAssets'\r\n });\r\n\r\n head.appendChild(link);\r\n });\r\n }\r\n\r\n /**\r\n * Only push the fonts and let the extension use cssV2.\r\n * @param cssAssets the input cssV1 assets.\r\n * @returns the cssAssetsV2 including fonts.css only.\r\n */\r\n private updateCssV2Assets(cssAssets: string[]): string[] {\r\n const cssAssetsV2 = [];\r\n\r\n if (!cssAssets) {\r\n return cssAssetsV2;\r\n }\r\n\r\n for (let i = 0; i < cssAssets.length; i++) {\r\n if (cssAssets[i] && cssAssets[i].includes(this.fontsKeyword)) {\r\n cssAssetsV2.push(cssAssets[i]);\r\n }\r\n }\r\n\r\n return cssAssetsV2;\r\n }\r\n}\r\n"]}