Skip to content

Instantly share code, notes, and snippets.

@DinoChiesa
Last active February 2, 2021 23:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DinoChiesa/85e694358137f5c324a0c49c2c448e28 to your computer and use it in GitHub Desktop.
Save DinoChiesa/85e694358137f5c324a0c49c2c448e28 to your computer and use it in GitHub Desktop.
/* 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