Overview

Private Alpha

Extensions are in private Alpha. Get in touch if you'd like early access.

Architecture

  • Statically hosted on AWS S3
  • HTML Iframe + CORS
  • JWT Auth for data access (expires after one hour)

Permissions

Permissions are requested by adding the text values to the manifest.json file under the permissions property. End users will accept all permissions before they will be able to open the Community Web Report.

Permission KeyPermission Description
org.contextProvides team members and a list of all projects (names and IDs).
project.basicBasic read access to recent sessions, and single row data access to Person, Session, Event table data when primary IDs are known (identityId + sessionId).
project.configRead Project tracking configs.
project.sql.selectEnable custom SELECT SQL queries scoped to the active projectId.
project.sql.communityEnable querying community SQL report- note that reports are limited to project data by "row level security" policies.
project.sql.cubejsEnables Cube.js query access.
project.s3.readEnable reading of S3 session recordings.
project.api.getGET API general methods.
project.api.allGET/POST/PUT/DELETE API general methods.

browser.storage
Enable storage manager that safely sets browser storage (local/session/cookie storage).
browser.networkEnables accessing external network requests across the internet. Fetch, XMLHttpRequest, and Websockets are by default disabled by CSPs.

Library

Initializing Web Report Manager SDK
import WisdomAppManager from 'XXXXXXXXX/../library/dist/index.js' // S3 Bucket Reference
const manager = new WisdomAppManager(/* For Development, pass JWT here */);

Publishing & Approval Guidelines

  • Manual upload of ZIP folder containing static web assets, with index.html as the entry point. Please do not link to external dependencies- download them locally.
  • Sensible Query Limits
  • Disallowed Features:
    • Direct browser storage (Local/Session/Cookie)
    • Message Passing (to parent Wisdom frames)

Proposed Access

  • Puppeteer/Playwright Access

Security + Defense in Depth

  • SQL queries are run with a ReadOnly PostgreSQL user.
  • Community Web Reports are undergo manual code reviews.
  • Data Exfiltration is prevented at a few different levels using CSPs and other techniques. While a few possible data exfiltration methods could exist, we think they have been balanced (or mitigated) with manual code reviews for community apps (and community SQL reports).

Wisdom Manager SDK

Library Note

Note the following patterns:

1. Naming methods "Get" is local, "Fetch" is across network
2. All methods use promises
3. Helper methods are prefixed with an underscore\n

Initializing the Library:

const appManager = AppManager(jwt, orgId, options);
await appManager.init();


Web Report Library
class WisdomAppManager {
async init () {}
getOrg(orgId){}
getProject(projectId){}
getAppManifest(){}
getAppReadme(){}
getUserSelf(){}
getTeam(){}
// -------- Misc Management --------
devLog(level: DevLogLevel, ...args: any) {}
notify(level: string, title: string, detail: string) {}
// -------- Helpers --------
_getSearchParam(paramName) {}
sanitizeTemplate = (strObj, ...substitutions) => {
// Use: this.stripHtml`hello <b>my</b> name is ${'<b>XSS</b>.'}`
}
// -------- Configs --------
// Transparently applies AppId, OrgId, UserId to each.
@requirePermissions(['storage'])
async getLocalStorage(name: string) {}
@requirePermissions(['storage'])
async getSessionStorage(name: string) {}
@todo
@requirePermissions(['storage'])
async fetchRemoteStorage(confName: string) {}
@requirePermissions(['storage'])
async setLocalStorage(name: string, json): Promise<any> {}
@requirePermissions(['storage'])
async setSessionStorage(name: string, json): Promise<any> {}
@requirePermissions(['storage'])
async setRemoteStorage(confName: string, confVal: object): Promise<any> {}
// -------- Direct Queries --------
knexSqlBuilder() {}
@requirePermissions(['sqlProjectRead'])
async querySql(query) {}
@requirePermissions(['sqlProjectRead'])
async queryCubeJs(query) {}
// ------- Fetching General Records + Reports
@requirePermissions(['s3ProjectRead'])
async fetchSessionBlob(sessionId) {}
@requirePermissions(['basic'])
async fetchSessionRow(sessionId) {}
@requirePermissions(['basic'])
async fetchEventRow(sessionId, eventId) {}
@requirePermissions(['basic'])
async fetchPersonRow(identityId) {}
@requirePermissions(['basic'])
async fetchRecentSessionRows(limit=1000) {}
// ------- MISC -------
@requirePermissions(['basic'])
async fetchCompressedUrlHierarchy() {}
@requirePermissions(['basic'])
async fetchDeminifiedStackFrames(frames: object[]) {}
@requirePermissions(['basic'])
async fetchDeminfiedErrorFrame(frame: object) {}
}
Last updated on by John Gracey