diff --git a/src/lib/content.js b/src/lib/content.js index 7b91348a..d251fd12 100644 --- a/src/lib/content.js +++ b/src/lib/content.js @@ -102,6 +102,14 @@ function loadProfiles(profileSet, list, csrf, hidesHistory, hidesAccountId) { input = li.querySelector('input[type="submit"]'); let name = input.value; name = name.replace(/\s+\|\s+\d+$/, ''); + let profile = profileSet.destProfiles.find(function (profile) { + return profile.profile === name; + }); + if (profile && profile.imagedata) { + li.querySelector('label.awsc-role-color').innerHTML = Sanitizer.escapeHTML` + + `; + } if (profileSet.excludedNames.includes(name)) { const nextLi = li.nextElementSibling; list.removeChild(li); @@ -124,7 +132,7 @@ function loadProfiles(profileSet, list, csrf, hidesHistory, hidesAccountId) { var color = item.color || 'aaaaaa'; var actionHost = window.location.host.endsWith('.amazonaws-us-gov.com') ? 'signin.amazonaws-us-gov.com' : 'signin.aws.amazon.com'; - if (!item.image) { + if (!item.imagedata) { list.insertAdjacentHTML('beforeend', Sanitizer.escapeHTML`
  • @@ -150,7 +158,7 @@ function loadProfiles(profileSet, list, csrf, hidesHistory, hidesAccountId) { - +
  • `); @@ -221,8 +229,8 @@ function attachColorLine(profiles) { const color = found && found.color || null; var label = usernameMenu.querySelector('.nav-elt-label'); - if (found && found.image) { - label.insertAdjacentHTML('beforebegin', Sanitizer.escapeHTML``); + if (found && found.imagedata) { + label.insertAdjacentHTML('beforebegin', Sanitizer.escapeHTML``); } if (color) { diff --git a/src/options.js b/src/options.js index 42f4b01f..3485d79f 100644 --- a/src/options.js +++ b/src/options.js @@ -2,6 +2,35 @@ function elById(id) { return document.getElementById(id); } +// taken from: https://davidwalsh.name/convert-image-data-uri-javascript +// converted to return a promise +function getDataUri(profile) { + return new Promise(function(resolve, reject) { + var image = new Image(); + image.setAttribute('crossOrigin', 'anonymous'); + + image.onload = function() { + var canvas = document.createElement('canvas'); + canvas.width = 64; // or 'width' if you want a special/scaled size + canvas.height = 64; // or 'height' if you want a special/scaled size + + canvas.getContext('2d').drawImage(this, 0, 0, 64, 64); + + // get as Data URI + profile.imagedata = canvas.toDataURL('image/png') + console.log(`Got data uri for: ${profile.image}: ${profile.imagedata}`); + resolve(profile); + }; + image.onerror = function() { + console.error(`Failed to load image: ${profile.image}`); + reject(profile) + } + + console.log(`Getting data uri for: ${profile.image}`); + image.src = profile.image.replace(/"/g, ''); + }) +} + window.onload = function() { var colorPicker = new ColorPicker(document); @@ -34,27 +63,86 @@ window.onload = function() { msgSpan.innerHTML = 'Failed to save bacause the number of profiles exceeded maximum 200!'; return; } + // map the profiles to promises. if there is an image specification but no + // imagedata attribute then generate the data-uri otherwise resolve to the + // original profile + Promise.all(profiles.map(function(profile) { + if (profile.image && !profile.imagedata) { + return getDataUri(profile) + } + return new Promise(function(resolve, reject) { + resolve(profile) + }); + })).then(values => { + // parse the rawstr into a list of lines or profiles (where each profile + // is a list of lines) preserving comments and formatting so that we can + // just add the imagedata lines. NOTE: the data parser turns comments + // and empty lines into profile separators + const lines = rawstr.split('\n'); + const profileLines = []; + let output = ""; + let currentProfile = undefined; + lines.forEach(function(line) { + if (r = line.match(/^\[(.+)\]$/)) { + var pname = r[1].trim(); + pname = pname.replace(/^profile\s+/i, ''); + currentProfile = { + profile: pname, + lines: [line] + }; + profileLines.push(currentProfile); + } else { + if (currentProfile) { + currentProfile.lines.push(line); + } else { + output += line; + } + } + }); - localStorage['rawdata'] = rawstr; + // re-render the profiles as string to update the UI and local storage + output += profileLines.map(function(profile) { + let match = values.find(function(value) { + return value.profile === profile.profile + }); + // only add an imagedata line if there isn't one + if (!profile.lines.find(function(line) { return line.startsWith('imagedata'); })) { + console.log('no imagedata'); + // add it after the image line if there is one + const index = profile.lines.findIndex(function(line) { return line.startsWith('image'); }); + if (index > -1) { + profile.lines = profile.lines.slice(0, index + 1) + .concat([`imagedata = ${match.imagedata}`]) + .concat(profile.lines.slice(index + 1)); + } + } + return profile.lines.join('\n'); + }).join('\n'); - const dps = new DataProfilesSplitter(); - const dataSet = dps.profilesToDataSet(profiles); - dataSet.lztext = LZString.compressToUTF16(rawstr); + localStorage['rawdata'] = output; + textArea.value = output; - chrome.storage.sync.set(dataSet, - function() { - const { lastError } = chrome.runtime || browser.runtime; - if (lastError) { - msgSpan.innerHTML = Sanitizer.escapeHTML`${lastError.message}`; - return; - } + const dps = new DataProfilesSplitter(); + const dataSet = dps.profilesToDataSet(values); + dataSet.lztext = LZString.compressToUTF16(output); - msgSpan.innerHTML = 'Configuration has been updated!'; - setTimeout(function() { - msgSpan.innerHTML = ''; - }, 2500); - }); - } catch (e) { + chrome.storage.sync.set(dataSet, + function() { + const { lastError } = chrome.runtime || browser.runtime; + if (lastError) { + msgSpan.innerHTML = Sanitizer.escapeHTML`${lastError.message}`; + return; + } + + msgSpan.innerHTML = 'Configuration has been updated!'; + setTimeout(function() { + msgSpan.innerHTML = ''; + }, 2500); + }); + }).catch(error => { + console.log(error.message); + }); + } catch(e) { msgSpan.innerHTML = 'Failed to save because of invalid format!'; } } diff --git a/test/fixtures/data.json b/test/fixtures/data.json index 1c6ec4cc..73cbf59d 100644 --- a/test/fixtures/data.json +++ b/test/fixtures/data.json @@ -9,7 +9,7 @@ { "profile": "b-stg", "aws_account_id": "666611113333", "role_name": "stg-role", "source_profile": "base-b" }, { "profile": "b-prod", "aws_account_id": "666611114444", "role_name": "prod-role", "source_profile": "base-b", "color": "ffcc333" }, { "profile": "b-renpou", "aws_account_id": "666611115555", "role_name": "renpou", "source_profile": "base-b" }, - { "profile": "a-stg-image", "aws_account_id": "555511113333", "role_name": "stg-role-image", "source_profile": "base-a", "image": "not-found.png" }, - { "profile": "b-prod-image", "aws_account_id": "666611114444", "role_name": "prod-role-image", "source_profile": "base-b", "image": "not-found.png" } + { "profile": "a-stg-image", "aws_account_id": "555511113333", "role_name": "stg-role-image", "source_profile": "base-a", "image": "not-found.png", "imagedata": "imagedata" }, + { "profile": "b-prod-image", "aws_account_id": "666611114444", "role_name": "prod-role-image", "source_profile": "base-b", "image": "not-found.png", imagedata: "imagedata" } ] }