From d2a90c2d19d51937c968c3afd0b89e5226c5ed73 Mon Sep 17 00:00:00 2001 From: David Hofmann <65802756+david-04@users.noreply.github.com> Date: Fri, 15 Apr 2022 16:39:42 +1000 Subject: [PATCH] Addressed ESLint and SonarQube warnings --- CHANGELOG.md | 12 +- Makefile | 2 +- dist/aws-link-accountifier.js | 77 +-- dist/tampermonkey/aws-link-accountifier.js | 556 --------------------- docs/aws-accountified-redirect.html | 6 +- docs/index.html | 2 +- src/declarations/tampermonkey.d.ts | 4 +- src/modules/account-selection-hint.ts | 20 +- src/modules/aws-session-info.ts | 6 +- src/modules/main.ts | 12 +- src/modules/menu.ts | 4 +- src/modules/settings.ts | 19 +- src/modules/url-hint.ts | 4 +- src/modules/utils.ts | 9 +- src/wrapper/header.ts | 2 +- 15 files changed, 93 insertions(+), 642 deletions(-) delete mode 100644 dist/tampermonkey/aws-link-accountifier.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ef44cb..02e1bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,18 +1,22 @@ # Change Log -## [0.3](https://github.com/david-04/aws-link-accountifier/tree/v0.3) (2022-02-25) +## [1.0](https://github.com/david-04/aws-link-accountifier/releases/tag/v1.0) (2022-04-15) + +- Performed technical maintenance (ESLint and SonarQube) + +## [0.3](https://github.com/david-04/aws-link-accountifier/releases/tag/v0.3) (2022-02-25) - Added [documentation](https://github.com/david-04/aws-link-accountifier/blob/main/README.md) - Improved the login page flow for currently unauthenticated SSO users -- Made it easier to customis forks by moving config presets to a [separate file](https://github.com/david-04/aws-link-accountifier/blob/main/src/modules/presets.ts) +- Made it easier to customize forks by moving config presets to a [separate file](https://github.com/david-04/aws-link-accountifier/blob/main/src/modules/presets.ts) - Fixed an issue with the role-switch that could initiate a second account-switch -## [0.2](https://github.com/david-04/aws-link-accountifier/tree/v0.2) (2022-02-23) +## [0.2](https://github.com/david-04/aws-link-accountifier/releases/tag/v0.2) (2022-02-23) - Improved link operability by adding a redirect service - Added the option to re-open the current page with a different role -## [0.1](https://github.com/david-04/aws-link-accountifier/tree/v0.1) (2022-01-26) +## [0.1](https://github.com/david-04/aws-link-accountifier/releases/tag/v0.1) (2022-01-26) - Added the ability to create "accountified" links - Added orchestrated redirect flows when opening accountified links diff --git a/Makefile b/Makefile index fc9dbad..b3a44f1 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ autorun : dist/tampermonkey/aws-link-accountifier.js -dist/tampermonkey/aws-link-accountifier.js : $(wildcard src/* src/*/* src/*/*/*) +dist/tampermonkey/aws-link-accountifier.js : $(wildcard src/*.ts src/*/*.ts src/*/*/*.ts) tsc diff --git a/dist/aws-link-accountifier.js b/dist/aws-link-accountifier.js index ecaee07..e93a92d 100644 --- a/dist/aws-link-accountifier.js +++ b/dist/aws-link-accountifier.js @@ -1,7 +1,7 @@ // ==UserScript== // @name AWS Link Accountifier // @namespace https://github.com/david-04/aws-link-accountifier -// @version 0.3 +// @version 1.0 // @author David Hofmann // @description Bind AWS console links to an account and - when opening such links - trigger an account change if required // @homepage https://github.com/david-04/aws-link-accountifier @@ -25,7 +25,7 @@ var AwsLinkAccountifier; const accountId = redirectState.requiredAccount.id; const accountName = getDescriptiveAccountName(redirectState); const banner = document.createElement("DIV"); - banner.innerHTML = `Please sign in to account ${AwsLinkAccountifier.sanitise(accountName)}`; + banner.innerHTML = `Please sign in to account ${AwsLinkAccountifier.sanitize(accountName)}`; const style = banner.style; style.backgroundColor = "yellow"; style.fontSize = "1.4em"; @@ -43,20 +43,23 @@ var AwsLinkAccountifier; //------------------------------------------------------------------------------------------------------------------ // Highlight the given account's login options //------------------------------------------------------------------------------------------------------------------ - function highlightAccount(accountId, colour) { + function highlightAccount(accountId, color) { document.querySelectorAll("* * .saml-account-name").forEach(node => { + var _a, _b; const element = node; const innerText = element.innerText; if (innerText.endsWith(` ${accountId}`) || innerText.endsWith(` (${accountId})`)) { - const style = element.parentElement.parentElement.style; - if (colour) { - style.backgroundColor = colour; + const style = (_b = (_a = element.parentElement) === null || _a === void 0 ? void 0 : _a.parentElement) === null || _b === void 0 ? void 0 : _b.style; + if (style) { + if (color) { + style.backgroundColor = color; + } + else { + style.removeProperty("background-color"); + } + style.paddingTop = "1.5em"; + style.paddingBottom = "0.5em"; } - else { - style.removeProperty("background-color"); - } - style.paddingTop = "1.5em"; - style.paddingBottom = "0.5em"; } }); } @@ -84,7 +87,7 @@ var AwsLinkAccountifier; //------------------------------------------------------------------------------------------------------------------ class AwsSession { //-------------------------------------------------------------------------------------------------------------- - // Initialisation + // Initialization //-------------------------------------------------------------------------------------------------------------- constructor(accountId, accountAlias, role) { this.accountId = accountId; @@ -142,7 +145,7 @@ var AwsLinkAccountifier; (function (AwsLinkAccountifier) { let getAwsSessionCount = 0; const isAwsConsole = window.location.host.toLowerCase().endsWith("aws.amazon.com"); - const isAwsSignin = window.location.host.toLowerCase().endsWith("signin.aws.amazon.com"); + const isAwsSignIn = window.location.host.toLowerCase().endsWith("signin.aws.amazon.com"); const isRedirectPage = 0 <= window.location.pathname.indexOf("aws-accountified-redirect.htm"); //------------------------------------------------------------------------------------------------------------------ // Extract the URL hint and start or schedule the redirect processing @@ -151,7 +154,7 @@ var AwsLinkAccountifier; if (isRedirectPage) { processRedirectPage(); } - if (isAwsSignin) { + if (isAwsSignIn) { const state = AwsLinkAccountifier.getRedirectState(); if (state && state.shouldAutoLogout) { AwsLinkAccountifier.setRedirectState(Object.assign(Object.assign({}, state), { shouldAutoLogout: false })); @@ -166,9 +169,9 @@ var AwsLinkAccountifier; AwsLinkAccountifier.extractUrlHint(); AwsLinkAccountifier.onDOMContentLoaded(processNotificationsAndRedirects); } - AwsLinkAccountifier.initialiseMenu({ - copyLink: isAwsConsole && !isAwsSignin, - switchRole: isAwsConsole && !isAwsSignin, + AwsLinkAccountifier.initializeMenu({ + copyLink: isAwsConsole && !isAwsSignIn, + switchRole: isAwsConsole && !isAwsSignIn, setAccountSwitchUrl: isAwsConsole || isRedirectPage, useThisPageForRedirects: isRedirectPage }); @@ -181,7 +184,7 @@ var AwsLinkAccountifier; document.removeEventListener("DOMContentLoaded", processNotificationsAndRedirects); const redirectState = AwsLinkAccountifier.getRedirectState(); if (redirectState) { - if (isAwsSignin) { + if (isAwsSignIn) { AwsLinkAccountifier.injectAccountSelectionHint(redirectState); } else if (isAwsConsole) { @@ -245,9 +248,9 @@ var AwsLinkAccountifier; var AwsLinkAccountifier; (function (AwsLinkAccountifier) { //------------------------------------------------------------------------------------------------------------------ - // Initialise the context menu + // Initialize the context menu //------------------------------------------------------------------------------------------------------------------ - function initialiseMenu(options) { + function initializeMenu(options) { if (options.copyLink) { GM_registerMenuCommand("Copy link (redirect)", () => copyLinkToClipboard(AwsLinkAccountifier.createRedirectLink), "c"); GM_registerMenuCommand("Copy link (direct)", () => copyLinkToClipboard(AwsLinkAccountifier.createDirectLink), "d"); @@ -262,7 +265,7 @@ var AwsLinkAccountifier; AwsLinkAccountifier.onDOMContentLoaded(setRedirectUrl); } } - AwsLinkAccountifier.initialiseMenu = initialiseMenu; + AwsLinkAccountifier.initializeMenu = initializeMenu; //------------------------------------------------------------------------------------------------------------------ // Copy link to clipboard //------------------------------------------------------------------------------------------------------------------ @@ -388,7 +391,8 @@ var AwsLinkAccountifier; // Retrieve settings //------------------------------------------------------------------------------------------------------------------ function getSettings() { - return migrateSettings(Object.assign(Object.assign({}, DEFAULT_SETTINGS), GM_getValue("settings", DEFAULT_SETTINGS))); + var _a; + return migrateSettings(Object.assign(Object.assign({}, DEFAULT_SETTINGS), ((_a = GM_getValue("settings", DEFAULT_SETTINGS)) !== null && _a !== void 0 ? _a : {}))); } AwsLinkAccountifier.getSettings = getSettings; //------------------------------------------------------------------------------------------------------------------ @@ -402,16 +406,15 @@ var AwsLinkAccountifier; // Migrate old settings //------------------------------------------------------------------------------------------------------------------ function migrateSettings(settings) { - const data = settings; - if (data && "object" === typeof data) { - if (data.redirectService) { - if (!data.redirectUrl) { - data.redirectUrl = data.redirectService; - } - delete data.redirectService; - } + var _a; + const redirectUrl = (_a = settings.redirectUrl) !== null && _a !== void 0 ? _a : settings.redirectService; + delete settings.redirectService; + if ("string" === typeof redirectUrl) { + return Object.assign(Object.assign({}, settings), { redirectUrl }); + } + else { + return settings; } - return settings; } })(AwsLinkAccountifier || (AwsLinkAccountifier = {})); var AwsLinkAccountifier; @@ -480,12 +483,12 @@ var AwsLinkAccountifier; try { const json = JSON.parse(decodeURIComponent(hint)); if (!json || "object" !== typeof json || "string" !== typeof ((_a = json === null || json === void 0 ? void 0 : json.account) === null || _a === void 0 ? void 0 : _a.id)) { - throw `Invalid URL hint: ${hint} (account/id is missing)`; + throw new Error(`account/id is missing`); } return json; } catch (exception) { - throw `Invalid URL hint: ${hint} (${exception})`; + throw new Error(`Invalid URL hint: ${hint} - (${exception})`); } } //------------------------------------------------------------------------------------------------------------------ @@ -553,19 +556,19 @@ var AwsLinkAccountifier; // Set a cookie //------------------------------------------------------------------------------------------------------------------ function setCookie(name, value, domain, path, ttlMs) { - var expires = new Date(new Date().getTime() + ttlMs); + const expires = new Date(new Date().getTime() + ttlMs); document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires};domain=${domain};path=${path}`; } AwsLinkAccountifier.setCookie = setCookie; //------------------------------------------------------------------------------------------------------------------ - // Sanitise HTML content + // Sanitize HTML content //------------------------------------------------------------------------------------------------------------------ - function sanitise(text) { + function sanitize(text) { return text.replace(//g, ">") .replace(/"/g, """); } - AwsLinkAccountifier.sanitise = sanitise; + AwsLinkAccountifier.sanitize = sanitize; //------------------------------------------------------------------------------------------------------------------ // Execute the given callback when the page has been loaded //------------------------------------------------------------------------------------------------------------------ diff --git a/dist/tampermonkey/aws-link-accountifier.js b/dist/tampermonkey/aws-link-accountifier.js deleted file mode 100644 index 2a8c849..0000000 --- a/dist/tampermonkey/aws-link-accountifier.js +++ /dev/null @@ -1,556 +0,0 @@ -// ==UserScript== -// @name AWS Link Accountifier -// @namespace https://github.com/david-04/aws-link-accountifier -// @version 0.2 -// @author David Hofmann -// @description Bind AWS console links to an account and - when opening such links - trigger an account change if required -// @homepage https://github.com/david-04/aws-link-accountifier -// @updateURL https://raw.githubusercontent.com/david-04/aws-link-accountifier/main/dist/aws-link-accountifier.js -// @downloadURL https://raw.githubusercontent.com/david-04/aws-link-accountifier/main/dist/aws-link-accountifier.js -// @match *://*.aws.amazon.com/* -// @match *://*/*aws-accountified-redirect.htm* -// @run-at document-start -// @grant GM_getValue -// @grant GM_setValue -// @grant GM_deleteValue -// @grant GM_registerMenuCommand -// @grant GM_setClipboard -// ==/UserScript== -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - //------------------------------------------------------------------------------------------------------------------ - // Highlight the account/roles that should be used for the login - //------------------------------------------------------------------------------------------------------------------ - function injectAccountSelectionHint(redirectState) { - const accountId = redirectState.requiredAccount.id; - const accountName = getDescriptiveAccountName(redirectState); - const banner = document.createElement("DIV"); - banner.innerHTML = `Please sign in to account ${AwsLinkAccountifier.sanitise(accountName)}`; - const style = banner.style; - style.backgroundColor = "yellow"; - style.fontSize = "1.4em"; - style.borderBottom = "1px solid black"; - style.padding = "0.75em"; - style.marginBottom = "1rem"; - style.width = "calc(100vw + 50px)"; - style.maxWidth = "calc(100vw + 50px)"; - style.marginLeft = "-50px"; - style.paddingLeft = "calc(50px + 0.75em)"; - document.body.insertBefore(banner, document.body.firstChild); - highlightAccount(accountId, "yellow"); - } - AwsLinkAccountifier.injectAccountSelectionHint = injectAccountSelectionHint; - //------------------------------------------------------------------------------------------------------------------ - // Highlight the given account's login options - //------------------------------------------------------------------------------------------------------------------ - function highlightAccount(accountId, colour) { - document.querySelectorAll("* * .saml-account-name").forEach(node => { - const element = node; - const innerText = element.innerText; - if (innerText.endsWith(` ${accountId}`) || innerText.endsWith(` (${accountId})`)) { - const style = element.parentElement.parentElement.style; - if (colour) { - style.backgroundColor = colour; - } - else { - style.removeProperty("background-color"); - } - style.paddingTop = "1.5em"; - style.paddingBottom = "0.5em"; - } - }); - } - //------------------------------------------------------------------------------------------------------------------ - // Get a descriptive name for the account - //------------------------------------------------------------------------------------------------------------------ - function getDescriptiveAccountName(redirectState) { - const account = redirectState.requiredAccount; - if (account.alias) { - return `${account.alias} (${account.id})`; - } - else if (account.exampleRole) { - return `${account.id} (e.g. ${account.exampleRole})`; - } - else { - return account.id; - } - } -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - AwsLinkAccountifier.AWS_USER_INFO_COOKIE_NAME = "aws-userInfo"; - //------------------------------------------------------------------------------------------------------------------ - // Details about an AWS session - //------------------------------------------------------------------------------------------------------------------ - class AwsSession { - //-------------------------------------------------------------------------------------------------------------- - // Initialisation - //-------------------------------------------------------------------------------------------------------------- - constructor(accountId, accountAlias, role) { - this.accountId = accountId; - this.accountAlias = accountAlias; - this.role = role; - } - //-------------------------------------------------------------------------------------------------------------- - // Create a URL hint for this session's account - //-------------------------------------------------------------------------------------------------------------- - toUrlHint() { - const hint = { account: { id: this.accountId } }; - if (this.accountAlias && this.accountAlias !== this.accountId) { - hint.account.alias = this.accountAlias; - } - if (this.role) { - hint.account.exampleRole = this.role; - } - return hint; - } - //-------------------------------------------------------------------------------------------------------------- - // Verify if this session's account matches the redirect requirements - //-------------------------------------------------------------------------------------------------------------- - matchesAccount(redirectState) { - const requiredAccount = redirectState.requiredAccount; - if (requiredAccount.id !== this.accountId) { - return false; - } - else if (requiredAccount.excludeExampleRole - && requiredAccount.exampleRole - && this.role === requiredAccount.exampleRole) { - return false; - } - else { - return true; - } - } - } - AwsLinkAccountifier.AwsSession = AwsSession; - //------------------------------------------------------------------------------------------------------------------ - // Retrieve information about the current session - //------------------------------------------------------------------------------------------------------------------ - function getCurrentAwsSession() { - const stringified = AwsLinkAccountifier.getCookie(AwsLinkAccountifier.AWS_USER_INFO_COOKIE_NAME); - if (stringified) { - const userInfo = JSON.parse(stringified); - const accountId = extractPropertyFragment(userInfo, "arn", /^arn:aws:sts:[^:]*:/, /:.*/); - if (accountId) { - return new AwsSession(accountId, extractPropertyFragment(userInfo, "alias", /^/, /$/), extractPropertyFragment(userInfo, "arn", /^arn:aws:sts:[^:]*:[^:]*:assumed-role\//, /\/.*/)); - } - } - return undefined; - } - AwsLinkAccountifier.getCurrentAwsSession = getCurrentAwsSession; - //------------------------------------------------------------------------------------------------------------------ - // Extract a piece of information from an object property - //------------------------------------------------------------------------------------------------------------------ - function extractPropertyFragment(object, propertyName, matchAndRemove, remove) { - const value = AwsLinkAccountifier.getStringProperty(object, propertyName); - if (value && value.match(matchAndRemove)) { - return value.replace(matchAndRemove, "").replace(remove, ""); - } - return undefined; - } -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - let getAwsSessionCount = 0; - //------------------------------------------------------------------------------------------------------------------ - // Extract the URL hint and start or schedule the redirect processing - //------------------------------------------------------------------------------------------------------------------ - function main() { - const isAwsConsole = window.location.host.toLowerCase().endsWith(".aws.amazon.com"); - const isRedirectPage = 0 <= window.location.pathname.indexOf("aws-accountified-redirect.htm"); - if (isAwsConsole) { - AwsLinkAccountifier.extractUrlHint(); - AwsLinkAccountifier.onDOMContentLoaded(processNotificationsAndRedirects); - } - if (isRedirectPage) { - processRedirectUrl(); - } - AwsLinkAccountifier.initialiseMenu({ - copyLink: isAwsConsole, - switchRole: isAwsConsole, - setAccountSwitchUrl: isAwsConsole || isRedirectPage, - useThisPageForRedirects: isRedirectPage - }); - } - AwsLinkAccountifier.main = main; - //------------------------------------------------------------------------------------------------------------------ - // Redirect or inject messages to log out and in again - //------------------------------------------------------------------------------------------------------------------ - function processNotificationsAndRedirects() { - document.removeEventListener("DOMContentLoaded", processNotificationsAndRedirects); - const redirectState = AwsLinkAccountifier.getRedirectState(); - if (redirectState) { - if ("signin.aws.amazon.com" === window.location.host) { - AwsLinkAccountifier.injectAccountSelectionHint(redirectState); - } - else if (window.location.host.endsWith(".console.aws.amazon.com")) { - const awsSession = AwsLinkAccountifier.getCurrentAwsSession(); - if (awsSession || 10 * 10 < ++getAwsSessionCount) { - redirectOrDecorateConsolePage(redirectState, awsSession); - } - else { - setTimeout(processNotificationsAndRedirects, 100); - } - } - } - } - //------------------------------------------------------------------------------------------------------------------ - // Augment the console page - //------------------------------------------------------------------------------------------------------------------ - function redirectOrDecorateConsolePage(redirectState, awsSession) { - if (!awsSession) { - AwsLinkAccountifier.deleteRedirectState(); - console.error(`Failed to retrieve AWS user info - cookie ${AwsLinkAccountifier.AWS_USER_INFO_COOKIE_NAME} not set or format has changed?`); - } - else if (awsSession.matchesAccount(redirectState)) { - AwsLinkAccountifier.deleteRedirectState(); - if (window.location.href !== redirectState.targetUrl) { - window.location.href = redirectState.targetUrl; - } - } - else if (redirectState.shouldAutoLogout) { - AwsLinkAccountifier.setRedirectState(Object.assign(Object.assign({}, redirectState), { shouldAutoLogout: false })); - AwsLinkAccountifier.initiateAccountSwitch(); - } - } - //------------------------------------------------------------------------------------------------------------------ - // Intercept redirect service page loads - //------------------------------------------------------------------------------------------------------------------ - function processRedirectUrl() { - var _a; - try { - const hash = decodeURIComponent(((_a = window.location.hash) !== null && _a !== void 0 ? _a : "").replace(/^#/, "").trim()); - if (hash) { - const parameters = JSON.parse(hash); - if (parameters - && "object" === typeof parameters - && "string" === typeof parameters.url - && parameters.url.match(/^http/) - && parameters.account - && "object" === typeof parameters.account) { - AwsLinkAccountifier.storeHint(parameters.url, { account: parameters.account }); - window.location.href = parameters.url; - } - else { - console.error("The hash does not contain a valid 'url'"); - } - } - } - catch (exception) { - console.error(exception); - } - } -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - //------------------------------------------------------------------------------------------------------------------ - // Initialise the context menu - //------------------------------------------------------------------------------------------------------------------ - function initialiseMenu(options) { - if (options.copyLink) { - GM_registerMenuCommand("Copy link (redirect)", () => copyLinkToClipboard(AwsLinkAccountifier.createRedirectLink), "c"); - GM_registerMenuCommand("Copy link (direct)", () => copyLinkToClipboard(AwsLinkAccountifier.createDirectLink), "d"); - } - if (options.switchRole) { - GM_registerMenuCommand("Switch role", switchRole, "s"); - } - if (options.setAccountSwitchUrl) { - GM_registerMenuCommand("Set account-switch URL", setAccountSwitchUrl, "u"); - } - if (options.useThisPageForRedirects) { - AwsLinkAccountifier.onDOMContentLoaded(setRedirectUrl); - } - } - AwsLinkAccountifier.initialiseMenu = initialiseMenu; - //------------------------------------------------------------------------------------------------------------------ - // Copy link to clipboard - //------------------------------------------------------------------------------------------------------------------ - function copyLinkToClipboard(generateLink) { - var _a; - const urlHint = (_a = AwsLinkAccountifier.getCurrentAwsSession()) === null || _a === void 0 ? void 0 : _a.toUrlHint(); - const url = urlHint ? generateLink(window.location.href, urlHint) : undefined; - if (url) { - GM_setClipboard(url); - } - else { - GM_notification({ - title: "Error", - text: "Failed to retrieve AWS account details", - silent: true - }); - } - } - //------------------------------------------------------------------------------------------------------------------ - // Trigger an account switch - //------------------------------------------------------------------------------------------------------------------ - function switchRole() { - try { - const account = AwsLinkAccountifier.getCurrentAwsSession(); - if (account === null || account === void 0 ? void 0 : account.role) { - AwsLinkAccountifier.setRedirectState({ - targetUrl: window.location.href, - requiredAccount: { - id: account.accountId, - alias: account.accountAlias, - exampleRole: account.role, - excludeExampleRole: true - }, - shouldAutoLogout: true, - expiresAt: new Date().getTime() + 10 * 60 * 1000 - }); - AwsLinkAccountifier.initiateAccountSwitch(); - } - } - catch (exception) { - console.error(exception); - } - } - //------------------------------------------------------------------------------------------------------------------ - // Set account switch URL - //------------------------------------------------------------------------------------------------------------------ - function setAccountSwitchUrl() { - const accountSwitchUrl = prompt(` - Enter the URL to trigger an account change. - It can include these placeholders: - - \${ACCOUNT_ID} - - \${ACCOUNT_ALIAS} - - \${ROLE_NAME} - `.trim().replace(/[ \t]*\r?\n[ \t]*/g, "\n"), AwsLinkAccountifier.getSettings().accountSwitchUrl); - if (accountSwitchUrl) { - AwsLinkAccountifier.updateSettings({ accountSwitchUrl }); - } - } - //------------------------------------------------------------------------------------------------------------------ - // Use this page for redirects - //------------------------------------------------------------------------------------------------------------------ - function setRedirectUrl() { - const redirectVersion = document.body.dataset.awsAccountifiedRedirectVersion; - if (redirectVersion && "string" === typeof redirectVersion) { - const callback = () => AwsLinkAccountifier.updateSettings({ redirectService: window.location.href.replace(/#.*/, "") }); - GM_registerMenuCommand("Use this page for redirects", callback, "s"); - } - } -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - const REDIRECT_STATE_KEY = "redirectState"; - //------------------------------------------------------------------------------------------------------------------ - // Set the redirect state - //------------------------------------------------------------------------------------------------------------------ - function setRedirectState(state) { - GM_setValue(REDIRECT_STATE_KEY, state); - } - AwsLinkAccountifier.setRedirectState = setRedirectState; - //------------------------------------------------------------------------------------------------------------------ - // Delete the redirect state - //------------------------------------------------------------------------------------------------------------------ - function deleteRedirectState() { - GM_deleteValue(REDIRECT_STATE_KEY); - } - AwsLinkAccountifier.deleteRedirectState = deleteRedirectState; - //------------------------------------------------------------------------------------------------------------------ - // Retrieve the current redirect state - //------------------------------------------------------------------------------------------------------------------ - function getRedirectState() { - const state = GM_getValue(REDIRECT_STATE_KEY, undefined); - if (state) { - if (new Date().getTime() <= state.expiresAt) { - return state; - } - deleteRedirectState(); - } - return undefined; - } - AwsLinkAccountifier.getRedirectState = getRedirectState; -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - const SETTINGS_KEY = "settings"; - //------------------------------------------------------------------------------------------------------------------ - // Default settings - //------------------------------------------------------------------------------------------------------------------ - const DEFAULT_SETTINGS = { - accountSwitchUrl: "https://signin.aws.amazon.com/switchrole?account=${ACCOUNT_ID}&roleName=${ROLE_NAME}", - redirectService: "https://david-04.github.io/aws-link-accountifier/aws-accountified-redirect.html" - }; - //------------------------------------------------------------------------------------------------------------------ - // Retrieve settings - //------------------------------------------------------------------------------------------------------------------ - function getSettings() { - return Object.assign(Object.assign({}, DEFAULT_SETTINGS), GM_getValue("settings", DEFAULT_SETTINGS)); - } - AwsLinkAccountifier.getSettings = getSettings; - //------------------------------------------------------------------------------------------------------------------ - // Update the settings - //------------------------------------------------------------------------------------------------------------------ - function updateSettings(settings) { - GM_setValue(SETTINGS_KEY, Object.assign(Object.assign({}, getSettings()), settings)); - } - AwsLinkAccountifier.updateSettings = updateSettings; -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - AwsLinkAccountifier.URL_HINT_PREFIX = "#aws-link-accountifier="; - //------------------------------------------------------------------------------------------------------------------ - // Extract the hint from the URL, store the re-direct state, and go to the non-hinted original URL - //------------------------------------------------------------------------------------------------------------------ - function extractUrlHint() { - try { - const { url, hint } = splitUrlAndHint(window.location.href); - if (undefined !== hint) { - AwsLinkAccountifier.deleteRedirectState(); - if (hint) { - storeHint(url, parseHint(hint)); - } - window.location.replace(url); - } - } - catch (exception) { - console.error(exception); - } - } - AwsLinkAccountifier.extractUrlHint = extractUrlHint; - //------------------------------------------------------------------------------------------------------------------ - // Split the URL into the original URL and the appended hint - //------------------------------------------------------------------------------------------------------------------ - function splitUrlAndHint(url) { - const index = url.indexOf(AwsLinkAccountifier.URL_HINT_PREFIX); - if (0 < index) { - return { - url: url.substring(0, index), - hint: url.substring(index + AwsLinkAccountifier.URL_HINT_PREFIX.length) - }; - } - else { - return { url }; - } - } - //------------------------------------------------------------------------------------------------------------------ - // Store the hint to trigger redirects later on - //------------------------------------------------------------------------------------------------------------------ - function storeHint(targetUrl, hint) { - try { - AwsLinkAccountifier.setRedirectState({ - targetUrl, - requiredAccount: { - id: hint.account.id, - alias: hint.account.alias, - exampleRole: hint.account.exampleRole - }, - shouldAutoLogout: true, - expiresAt: new Date().getTime() + 10 * 60 * 1000 - }); - } - catch (exception) { - console.error(exception); - } - } - AwsLinkAccountifier.storeHint = storeHint; - //------------------------------------------------------------------------------------------------------------------ - // Extract the details from the hint - //------------------------------------------------------------------------------------------------------------------ - function parseHint(hint) { - var _a; - try { - const json = JSON.parse(decodeURIComponent(hint)); - if (!json || "object" !== typeof json || "string" !== typeof ((_a = json === null || json === void 0 ? void 0 : json.account) === null || _a === void 0 ? void 0 : _a.id)) { - throw `Invalid URL hint: ${hint} (account/id is missing)`; - } - return json; - } - catch (exception) { - throw `Invalid URL hint: ${hint} (${exception})`; - } - } - //------------------------------------------------------------------------------------------------------------------ - // Generate a direct link with an embedded hint - //------------------------------------------------------------------------------------------------------------------ - function createDirectLink(url, hint) { - return splitUrlAndHint(url).url + AwsLinkAccountifier.URL_HINT_PREFIX + encodeURIComponent(JSON.stringify(hint)); - } - AwsLinkAccountifier.createDirectLink = createDirectLink; - //------------------------------------------------------------------------------------------------------------------ - // Generate a redirecting link - //------------------------------------------------------------------------------------------------------------------ - function createRedirectLink(url, hint) { - return `${AwsLinkAccountifier.getSettings().redirectService}#${encodeURIComponent(JSON.stringify(Object.assign(Object.assign({}, hint), { url })))}`; - } - AwsLinkAccountifier.createRedirectLink = createRedirectLink; - //------------------------------------------------------------------------------------------------------------------ - // Trigger an account switch based on the current redirect state - //------------------------------------------------------------------------------------------------------------------ - function initiateAccountSwitch() { - var _a, _b, _c; - const account = (_a = AwsLinkAccountifier.getRedirectState()) === null || _a === void 0 ? void 0 : _a.requiredAccount; - if (account) { - const url = AwsLinkAccountifier.getSettings().accountSwitchUrl - .replace(/\$\{ACCOUNT_ID\}/g, encodeURIComponent(account.id)) - .replace(/\$\{ACCOUNT_ALIAS\}/g, encodeURIComponent((_b = account.alias) !== null && _b !== void 0 ? _b : account.id)) - .replace(/\$\{ROLE_NAME\}/g, encodeURIComponent((_c = account.exampleRole) !== null && _c !== void 0 ? _c : "")); - if (url !== window.location.href) { - window.location.href = url; - } - } - } - AwsLinkAccountifier.initiateAccountSwitch = initiateAccountSwitch; -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -var AwsLinkAccountifier; -(function (AwsLinkAccountifier) { - //------------------------------------------------------------------------------------------------------------------ - // Get a string property from an object - //------------------------------------------------------------------------------------------------------------------ - function getStringProperty(object, key) { - if (object && "object" === typeof object && "string" === typeof (object[key])) { - return object[key]; - } - else { - return undefined; - } - } - AwsLinkAccountifier.getStringProperty = getStringProperty; - //------------------------------------------------------------------------------------------------------------------ - // Get a cookie - //------------------------------------------------------------------------------------------------------------------ - function getCookie(cName) { - const name = cName + "="; - const cDecoded = decodeURIComponent(document.cookie); - const array = cDecoded.split('; '); - let result; - array.forEach(value => { - if (value.indexOf(name) === 0) - result = value.substring(name.length); - }); - return result; - } - AwsLinkAccountifier.getCookie = getCookie; - //------------------------------------------------------------------------------------------------------------------ - // Set a cookie - //------------------------------------------------------------------------------------------------------------------ - function setCookie(name, value, domain, path, ttlMs) { - var expires = new Date(new Date().getTime() + ttlMs); - document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires};domain=${domain};path=${path}`; - } - AwsLinkAccountifier.setCookie = setCookie; - //------------------------------------------------------------------------------------------------------------------ - // Sanitise HTML content - //------------------------------------------------------------------------------------------------------------------ - function sanitise(text) { - return text.replace(//g, ">") - .replace(/"/g, """); - } - AwsLinkAccountifier.sanitise = sanitise; - //------------------------------------------------------------------------------------------------------------------ - // Execute the given callback when the page has been loaded - //------------------------------------------------------------------------------------------------------------------ - function onDOMContentLoaded(callback) { - if (document.readyState === "complete" || document.readyState === "interactive") { - callback(); - } - else { - document.addEventListener("DOMContentLoaded", callback); - } - } - AwsLinkAccountifier.onDOMContentLoaded = onDOMContentLoaded; -})(AwsLinkAccountifier || (AwsLinkAccountifier = {})); -AwsLinkAccountifier.main(); diff --git a/docs/aws-accountified-redirect.html b/docs/aws-accountified-redirect.html index 3ff3ffd..6dd259b 100644 --- a/docs/aws-accountified-redirect.html +++ b/docs/aws-accountified-redirect.html @@ -1,5 +1,5 @@ - + @@ -41,12 +41,12 @@

AWS Accountified Redirect

try { const url = JSON.parse(decodeURIComponent(hash)).url; if ("string" !== typeof url || !url.match(/^http/)) { - throw "Invalid hash - property 'url' is missing or not a valid URL"; + throw new Error("Invalid hash - property 'url' is missing or not a valid URL"); } window.addEventListener("DOMContentLoaded", () => setTimeout(() => window.location.href = url, 1500)); } catch (exception) { console.error(exception); - warning.innerText = "Error: Invalid URL" + warning.innerText = "Error: Invalid URL"; warning.style.display="block"; instructions.style.display="block"; } diff --git a/docs/index.html b/docs/index.html index 7dc0492..43ba0b4 100644 --- a/docs/index.html +++ b/docs/index.html @@ -1,5 +1,5 @@ - + diff --git a/src/declarations/tampermonkey.d.ts b/src/declarations/tampermonkey.d.ts index d0fc19a..43a6116 100644 --- a/src/declarations/tampermonkey.d.ts +++ b/src/declarations/tampermonkey.d.ts @@ -1,7 +1,7 @@ -declare function GM_setValue(name: string, value: any): void; +declare function GM_setValue(name: string, value: unknown): void; declare function GM_getValue(name: string, defaultValue: T): T | undefined | null; declare function GM_deleteValue(name: string): void; -declare function GM_registerMenuCommand(name: string, fn: () => void, accessKey?: any): number; +declare function GM_registerMenuCommand(name: string, fn: () => void, accessKey?: unknown): number; declare function GM_setClipboard(data: string, info?: string): void; declare function GM_notification(details: { text?: string, diff --git a/src/modules/account-selection-hint.ts b/src/modules/account-selection-hint.ts index 478461f..10dd916 100644 --- a/src/modules/account-selection-hint.ts +++ b/src/modules/account-selection-hint.ts @@ -8,7 +8,7 @@ namespace AwsLinkAccountifier { const accountId = redirectState.requiredAccount.id; const accountName = getDescriptiveAccountName(redirectState); const banner = document.createElement("DIV"); - banner.innerHTML = `Please sign in to account ${sanitise(accountName)}`; + banner.innerHTML = `Please sign in to account ${sanitize(accountName)}`; const style = banner.style; style.backgroundColor = "yellow"; @@ -30,19 +30,21 @@ namespace AwsLinkAccountifier { // Highlight the given account's login options //------------------------------------------------------------------------------------------------------------------ - function highlightAccount(accountId: string, colour: string | null) { + function highlightAccount(accountId: string, color: string | null) { document.querySelectorAll("* * .saml-account-name").forEach(node => { const element = node as HTMLElement; const innerText = element.innerText; if (innerText.endsWith(` ${accountId}`) || innerText.endsWith(` (${accountId})`)) { - const style = element.parentElement!.parentElement!.style; - if (colour) { - style.backgroundColor = colour; - } else { - style.removeProperty("background-color"); + const style = element.parentElement?.parentElement?.style; + if (style) { + if (color) { + style.backgroundColor = color; + } else { + style.removeProperty("background-color"); + } + style.paddingTop = "1.5em"; + style.paddingBottom = "0.5em"; } - style.paddingTop = "1.5em"; - style.paddingBottom = "0.5em"; } }); } diff --git a/src/modules/aws-session-info.ts b/src/modules/aws-session-info.ts index 997d5b9..de35b57 100644 --- a/src/modules/aws-session-info.ts +++ b/src/modules/aws-session-info.ts @@ -9,7 +9,7 @@ namespace AwsLinkAccountifier { export class AwsSession { //-------------------------------------------------------------------------------------------------------------- - // Initialisation + // Initialization //-------------------------------------------------------------------------------------------------------------- public constructor( @@ -66,7 +66,9 @@ namespace AwsLinkAccountifier { // Extract a piece of information from an object property //------------------------------------------------------------------------------------------------------------------ - function extractPropertyFragment(object: any, propertyName: string, matchAndRemove: RegExp, remove: RegExp) { + function extractPropertyFragment( + object: { [key: string]: unknown }, propertyName: string, matchAndRemove: RegExp, remove: RegExp + ) { const value = getStringProperty(object, propertyName); if (value && value.match(matchAndRemove)) { return value.replace(matchAndRemove, "").replace(remove, ""); diff --git a/src/modules/main.ts b/src/modules/main.ts index 6affafc..bad51d5 100644 --- a/src/modules/main.ts +++ b/src/modules/main.ts @@ -3,7 +3,7 @@ namespace AwsLinkAccountifier { let getAwsSessionCount = 0; const isAwsConsole = window.location.host.toLowerCase().endsWith("aws.amazon.com"); - const isAwsSignin = window.location.host.toLowerCase().endsWith("signin.aws.amazon.com"); + const isAwsSignIn = window.location.host.toLowerCase().endsWith("signin.aws.amazon.com"); const isRedirectPage = 0 <= window.location.pathname.indexOf("aws-accountified-redirect.htm"); //------------------------------------------------------------------------------------------------------------------ @@ -14,7 +14,7 @@ namespace AwsLinkAccountifier { if (isRedirectPage) { processRedirectPage(); } - if (isAwsSignin) { + if (isAwsSignIn) { const state = getRedirectState(); if (state && state.shouldAutoLogout) { setRedirectState({ ...state, shouldAutoLogout: false }); @@ -29,9 +29,9 @@ namespace AwsLinkAccountifier { extractUrlHint(); onDOMContentLoaded(processNotificationsAndRedirects); } - initialiseMenu({ - copyLink: isAwsConsole && !isAwsSignin, - switchRole: isAwsConsole && !isAwsSignin, + initializeMenu({ + copyLink: isAwsConsole && !isAwsSignIn, + switchRole: isAwsConsole && !isAwsSignIn, setAccountSwitchUrl: isAwsConsole || isRedirectPage, useThisPageForRedirects: isRedirectPage }); @@ -45,7 +45,7 @@ namespace AwsLinkAccountifier { document.removeEventListener("DOMContentLoaded", processNotificationsAndRedirects); const redirectState = getRedirectState(); if (redirectState) { - if (isAwsSignin) { + if (isAwsSignIn) { injectAccountSelectionHint(redirectState); } else if (isAwsConsole) { const awsSession = getCurrentAwsSession(); diff --git a/src/modules/menu.ts b/src/modules/menu.ts index 686d37d..d2bdd6a 100644 --- a/src/modules/menu.ts +++ b/src/modules/menu.ts @@ -1,10 +1,10 @@ namespace AwsLinkAccountifier { //------------------------------------------------------------------------------------------------------------------ - // Initialise the context menu + // Initialize the context menu //------------------------------------------------------------------------------------------------------------------ - export function initialiseMenu(options: { + export function initializeMenu(options: { copyLink: boolean, switchRole: boolean, setAccountSwitchUrl: boolean, useThisPageForRedirects: boolean }) { if (options.copyLink) { diff --git a/src/modules/settings.ts b/src/modules/settings.ts index 3f275b2..2e56ae9 100644 --- a/src/modules/settings.ts +++ b/src/modules/settings.ts @@ -25,7 +25,7 @@ namespace AwsLinkAccountifier { //------------------------------------------------------------------------------------------------------------------ export function getSettings() { - return migrateSettings({ ...DEFAULT_SETTINGS, ...GM_getValue("settings", DEFAULT_SETTINGS) as Settings }); + return migrateSettings({ ...DEFAULT_SETTINGS, ...(GM_getValue("settings", DEFAULT_SETTINGS) ?? {}) }); } //------------------------------------------------------------------------------------------------------------------ @@ -40,16 +40,13 @@ namespace AwsLinkAccountifier { // Migrate old settings //------------------------------------------------------------------------------------------------------------------ - function migrateSettings(settings: Settings) { - const data: any = settings; - if (data && "object" === typeof data) { - if (data.redirectService) { - if (!data.redirectUrl) { - data.redirectUrl = data.redirectService; - } - delete data.redirectService; - } + function migrateSettings(settings: Settings & { redirectService?: string }) { + const redirectUrl = settings.redirectUrl ?? settings.redirectService; + delete settings.redirectService; + if ("string" === typeof redirectUrl) { + return { ...settings, redirectUrl }; + } else { + return settings; } - return settings; } } diff --git a/src/modules/url-hint.ts b/src/modules/url-hint.ts index 58da99f..934f958 100644 --- a/src/modules/url-hint.ts +++ b/src/modules/url-hint.ts @@ -78,11 +78,11 @@ namespace AwsLinkAccountifier { try { const json = JSON.parse(decodeURIComponent(hint)); if (!json || "object" !== typeof json || "string" !== typeof json?.account?.id) { - throw `Invalid URL hint: ${hint} (account/id is missing)`; + throw new Error(`account/id is missing`); } return json as UrlHint; } catch (exception) { - throw `Invalid URL hint: ${hint} (${exception})`; + throw new Error(`Invalid URL hint: ${hint} - (${exception})`); } } diff --git a/src/modules/utils.ts b/src/modules/utils.ts index 22e3747..0ce30f3 100644 --- a/src/modules/utils.ts +++ b/src/modules/utils.ts @@ -4,7 +4,7 @@ namespace AwsLinkAccountifier { // Get a string property from an object //------------------------------------------------------------------------------------------------------------------ - export function getStringProperty(object: any, key: string) { + export function getStringProperty(object: { [key: string]: unknown }, key: string) { if (object && "object" === typeof object && "string" === typeof (object[key])) { return object[key] as string; } else { @@ -32,15 +32,15 @@ namespace AwsLinkAccountifier { //------------------------------------------------------------------------------------------------------------------ export function setCookie(name: string, value: string, domain: string, path: string, ttlMs: number) { - var expires = new Date(new Date().getTime() + ttlMs); + const expires = new Date(new Date().getTime() + ttlMs); document.cookie = `${name}=${encodeURIComponent(value)};expires=${expires};domain=${domain};path=${path}`; } //------------------------------------------------------------------------------------------------------------------ - // Sanitise HTML content + // Sanitize HTML content //------------------------------------------------------------------------------------------------------------------ - export function sanitise(text: string) { + export function sanitize(text: string) { return text.replace(//g, ">") .replace(/"/g, """) @@ -57,5 +57,4 @@ namespace AwsLinkAccountifier { document.addEventListener("DOMContentLoaded", callback); } } - } diff --git a/src/wrapper/header.ts b/src/wrapper/header.ts index 38dadbc..4b96688 100644 --- a/src/wrapper/header.ts +++ b/src/wrapper/header.ts @@ -1,7 +1,7 @@ // ==UserScript== // @name AWS Link Accountifier // @namespace https://github.com/david-04/aws-link-accountifier -// @version 0.3 +// @version 1.0 // @author David Hofmann // @description Bind AWS console links to an account and - when opening such links - trigger an account change if required // @homepage https://github.com/david-04/aws-link-accountifier