Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support prism mode #362

Merged
merged 8 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
Changelog
=========

## 6.0.0 (2025/01/22)

- Add support for **multi-session** on the AWS Management Console
- Add support for **multi-level source profile references** to enable role chaining
- Add experimental feature: **Automatic tab grouping for multi-session** for supporters

## 5.0.2 (2024/10/27)

- Fix to highlight the relevant part when validation fails in the configuration textarea (thanks to @brandonkgarner)
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ This extension shows a menu of switchable roles that you can configure manually.

- Supports the Sync feature on all sorts of browsers
- Not support switching between AWS accounts you sign into with AWS SSO or SAML solution providers directly
- Experimental support for **multi-session** on the AWS Management Console

## Large Supporters

Expand Down Expand Up @@ -153,6 +154,7 @@ The 'Show only matching roles' setting is for use with more sophisticated accoun

- **Hide account id** hides the account_id for each profile.
- **Show only matching roles** filters to only show profiles with roles that match your role in your master account.
- **Automatic tab grouping for multi-session (Experimental, Supporters only)** automatically organizes tabs from the same AWS Management Console multi-session into tab groups. The tab group name will be the corresponding profile name. When a tab group is removed, the corresponding session will be automatically signed out.
- **Sign-in endpoint in current region (Experimental, Supporters only)** instead of *signin.aws.amazon.com* when you browse a non-global page in AWS Management Console. For those working geographically far from Virginia, the switch role may be a little faster.
- ~~**Automatically assume last assumed role (Experimental)** automatically assumes last assumed role on the next sign-in if did not back to the base account and signed out.~~ **temporarily disabled**
- **Configuration storage** specifies which storage to save to. 'Sync' can automatically share it between browsers with your account but cannot store many profiles. 'Local' is the exact opposite of 'Sync.'
Expand Down
2 changes: 1 addition & 1 deletion bin/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ browsers=("chrome" "firefox")
for brw in ${browsers[@]}
do
\cp src/js/content.js dist/$brw/js/
\cp src/js/attach_target.js dist/$brw/js/
\cp -r src/js/war dist/$brw/js/
\cp -r src/*.html dist/$brw/
\cp -r icons dist/$brw/
done
Expand Down
5 changes: 2 additions & 3 deletions manifest.json
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
{
"version": "5.0.2",
"version": "6.0.0",
"name": "AWS Extend Switch Roles",
"description": "Extend your AWS IAM switching roles. You can set the configuration like aws config format",
"short_name": "Extend SwitchRole",
"permissions": ["activeTab", "storage"],
"icons" : {
"48": "icons/Icon_48x48.png",
"128": "icons/Icon_128x128.png"
Expand Down Expand Up @@ -43,7 +42,7 @@
"open_in_tab": true
},
"web_accessible_resources": [{
"resources": ["js/attach_target.js"],
"resources": ["js/war/attach_target.js", "js/war/prism_switch_dest.js"],
"matches": [
"https://*.console.aws.amazon.com/*",
"https://health.aws.amazon.com/*",
Expand Down
4 changes: 3 additions & 1 deletion manifest_chrome.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
{
"minimum_chrome_version": "88.0",
"permissions": ["activeTab", "storage"],
"minimum_chrome_version": "89.0",
"optional_permissions": ["tabGroups"],
"optional_host_permissions": ["https://*.aesr.dev/*"],
"background": {
"service_worker": "js/background.js",
Expand Down
1 change: 1 addition & 0 deletions manifest_firefox.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"permissions": ["activeTab", "storage"],
"browser_specific_settings": {
"gecko": {
"id": "aws-extend-switch-roles@toshi.tilfin.com",
Expand Down
21 changes: 11 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "aws-extend-switch-roles",
"version": "5.0.2",
"version": "6.0.0",
"description": "Extend your AWS IAM switching roles by Chrome extension",
"main": "index.js",
"directories": {
Expand All @@ -27,7 +27,7 @@
},
"homepage": "https://github.com/tilfinltd/aws-extend-switch-roles#readme",
"dependencies": {
"aesr-config": "^0.5.1"
"aesr-config": "^0.6.0"
},
"devDependencies": {
"@playwright/test": "^1.49.1",
Expand Down
112 changes: 100 additions & 12 deletions src/js/background.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,16 @@ import { updateProfilesTable } from './handlers/update_profiles.js'
const syncStorageRepo = new SyncStorageRepository(chrome || browser)
const sessionMemory = new SessionMemory(chrome || browser)

function initScript() {
sessionMemory.set({ switchCount: 0 }).then(() => {});

syncStorageRepo.get(['goldenKeyExpire'])
.then(data => {
const { goldenKeyExpire } = data;
if ((new Date().getTime() / 1000) < Number(goldenKeyExpire)) {
return sessionMemory.set({ hasGoldenKey: 't' }).then(() => {
return setIcon('/icons/Icon_48x48_g.png');
});
}
})
async function initScript() {
await sessionMemory.set({ switchCount: 0 });

const { goldenKeyExpire } = await syncStorageRepo.get(['goldenKeyExpire']);
if ((new Date().getTime() / 1000) < Number(goldenKeyExpire)) {
await sessionMemory.set({ hasGoldenKey: 't' });
return setIcon('/icons/Icon_48x48_g.png');
} else {
await syncStorageRepo.set({ autoTabGrouping: false, signinEndpointInHere: false });
}
}

chrome.runtime.onStartup.addListener(function () {
Expand Down Expand Up @@ -59,3 +57,93 @@ chrome.runtime.onMessageExternal.addListener(function (message, sender, sendResp
}, 1000); // delay to prevent to try scanning id
});
});

function createTabGroupKey(title) {
return encodeURIComponent(`tabGroup/${title}`);
}

let listeningTabGroupsRemove = false;

chrome.runtime.onMessage.addListener(async (message, sender, sendResponse) => {
if (message.action === 'listenTabGroupsRemove' && !listeningTabGroupsRemove) {
chrome.tabGroups.onRemoved.addListener(async function (group) {
const key = createTabGroupKey(group.title);
const result = await sessionMemory.get([key]);
const { [key]: url } = result;
if (url) {
await sessionMemory.delete([key]);
const tab = await chrome.tabs.create({ url, active: false });
setTimeout(() => {
chrome.tabs.remove(tab.id);
}, 1000);
console.info('Logout', group.title, url);
}
});
listeningTabGroupsRemove = true;
} else if (message.action === 'openTab') {
const { url, signinHost, tabGroup } = message;
const tab = await chrome.tabs.create({ url });

if (tabGroup) {
const uRL = new URL(url);
const params = new URLSearchParams(uRL.search);
const sessionId = params.get('login_hint');

const { title, color } = tabGroup;

const [group] = await chrome.tabGroups.query({ title });
if (group) {
await chrome.tabs.group({ groupId: group.id, tabIds: tab.id });
} else {
const newGroupId = await chrome.tabs.group({ tabIds: tab.id });
await chrome.tabGroups.update(newGroupId, { title, color: getTabGroupColor(color) });
}

const key = createTabGroupKey(title);
await sessionMemory.set({ [key]: `https://${signinHost}/sessions/${sessionId}/v1/logout` });
}
}
sendResponse({});
});

function getTabGroupColor(hexColor) {
if (!hexColor) return 'grey';

const tabGroupColors = {
grey: [128, 128, 128],
blue: [0, 0, 255],
red: [255, 0, 0],
yellow: [255, 255, 0],
green: [0, 128, 0],
pink: [255, 192, 203],
purple: [128, 0, 128],
cyan: [0, 255, 255],
orange: [255, 165, 0],
};

const inputRgb = (() => {
const result = /^([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hexColor);
return result ? [
parseInt(result[1], 16),
parseInt(result[2], 16),
parseInt(result[3], 16)
] : null;
})();

const calcDistance = (rgb1, rgb2) => {
if (!rgb1) return Infinity;
return rgb1.reduce((dis, val, i) => dis + (val - rgb2[i]) ** 2, 0);
};

let closestColor = 'grey';
let minDistance = Infinity;
for (const tgColor in tabGroupColors) {
const distance = calcDistance(inputRgb, tabGroupColors[tgColor]);
if (distance < minDistance) {
minDistance = distance;
closestColor = tgColor;
}
}

return closestColor;
}
Loading
Loading