Last active
February 2, 2021 23:19
-
-
Save DinoChiesa/85e694358137f5c324a0c49c2c448e28 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* tweak-expiry-display.js */ | |
/* jshint esversion:9, browser:true, strict:implied */ | |
/* global window, navigator, console, fetch, Buffer */ | |
/* | |
Instructions | |
Add this as a "custom script" in the "Settings" dialog for the portal. | |
Be sure to bracket this source with open-and-close script tags. | |
Disclaimer: this script will be brittle. It examines the rendered HTML and | |
changes it if the expiry is displayed as "never". If for whatever reason the | |
portal starts rendering the HTML differently, this custom script will break. | |
How it works | |
This custom script looks for pages that match /my-apps/APP_ID | |
and in that case, checks for the App credentials table, and any entries within | |
it that display 'never' for the API Key (or credential) expiry. Finding any such | |
rows in the table, this script will fetch the App metadata from the portal | |
server, then update the rows in the table with the appropriate expiry. | |
*/ | |
const wellKnownCsrfHeaderName = 'X-Apigee-CSRF'; | |
const CHECK_LIMIT = 10; | |
window.portal = {}; | |
window.portal.pageEventListeners = { | |
onLoad: (path) => { | |
/* do not match on /my-apps/new */ | |
let appRegex = new RegExp('/my-apps/(((.+)-){4}(.+))$'), | |
match = path.match(appRegex); | |
if (match && match[1]) { | |
setTimeout(() => checkForExpiryDisplay(match[1]), 200); | |
return true; | |
} | |
return undefined; | |
}, | |
onUnload: (path, contextReturnedFromOnLoad) => { | |
} | |
}; | |
let checkCount = 0; | |
function checkForExpiryDisplay(appId) { | |
let div = document.querySelector('div.app-section-api-keys'); | |
checkCount++; | |
if (checkCount < CHECK_LIMIT) { | |
if (div) { | |
let table = div.querySelector('table.app-table'); | |
if (table) { | |
let rows = table.querySelectorAll('tr.app-api-key-active'); | |
if (rows && rows.length) { | |
let anyExpired = Array.prototype.filter.call( rows, row => { | |
let td = row.querySelector('td.app-details-api-key-expires'); | |
return (td && td.textContent.trim() == 'never'); | |
}); | |
if (anyExpired && anyExpired.length) { | |
fetchOneApp(table, appId); | |
} | |
} | |
} | |
} | |
} | |
setTimeout(() => checkForExpiryDisplay(appId), 1200); | |
} | |
function toLocalTimeString(d) { | |
let s = d.toString(); | |
let parts = s.split(' '); | |
/* | |
* [ | |
* 'Tue', 'Feb', | |
* '02', '2021', | |
* '14:54:19', 'GMT-0800', | |
* '(Pacific', 'Standard', | |
* 'Time)' | |
* ] | |
*/ | |
let leftFillZero = n => ('0'+n).slice(0,2); | |
let monthIndex = s => { | |
let ix = ['Jan', 'Feb','Mar', 'Apr', 'May','Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'].indexOf(s); | |
return leftFillZero(ix + 1); | |
}; | |
return parts[3] + '-' + | |
monthIndex(parts[1]) + '-' + | |
parts[2] + ' ' + | |
parts[4]; | |
} | |
function updateOneRow(table) { | |
return function(cred) { | |
let rows = table.querySelectorAll('tr.app-api-key-active'); | |
if (rows && rows.length) { | |
let thisRow = Array.prototype.find.call( rows, row => { | |
let td = row.querySelector('td.app-api-key-value'); | |
if ( ! td || td.firstChild.wholeText.trim() != cred.consumerKey) { | |
return false; | |
} | |
td = row.querySelector('td.app-details-api-key-expires'); | |
if ( ! td || td.textContent.trim() != 'never') { | |
return false; | |
} | |
return true; | |
}); | |
if (thisRow) { | |
let td = thisRow.querySelector('td.app-details-api-key-expires'); | |
if (cred.expiresAt == -1) { | |
td.textContent = 'NEVER'; | |
} | |
else { | |
td.textContent = toLocalTimeString(new Date(cred.expiresAt)); | |
if (cred.expiresAt < Date.now()) { | |
td.style.color = 'Red'; | |
td.setAttribute('title', 'EXPIRED'); | |
} | |
} | |
td = thisRow.querySelector('td.app-details-api-key-created'); | |
td.textContent = toLocalTimeString(new Date(cred.issuedAt)); | |
} | |
} | |
}; | |
} | |
function getCsrfHeader() { | |
let x = document.cookie | |
.split(';') | |
.map(e => e.trim()) | |
.find(item => item.startsWith(wellKnownCsrfHeaderName)); | |
if (x) { | |
let parts = x.split('='); | |
if (parts && parts.length > 1) { | |
return parts.slice(1).join('='); | |
} | |
} | |
return 'unknown'; | |
} | |
function fetchOneApp(table, appId) { | |
let method = 'GET', | |
credentials = 'same-origin', | |
url = `/consumers/api/apps/${appId}`, | |
headers = { Accept: 'application/json' }; | |
headers[wellKnownCsrfHeaderName] = getCsrfHeader(); | |
return fetch(url, { method, credentials, headers }) | |
.then(response => response.json()) | |
.then(json => { | |
if (json.status == 'success') { | |
json.data.credentials.forEach(updateOneRow(table)); | |
} | |
}) | |
.catch(error => { | |
console.log(error); | |
}); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment