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 Key | Permission Description |
|---|---|
org.context | Provides team members and a list of all projects (names and IDs). |
project.basic | Basic read access to recent sessions, and single row data access to Person, Session, Event table data when primary IDs are known (identityId + sessionId). |
project.config | Read Project tracking configs. |
project.sql.select | Enable custom SELECT SQL queries scoped to the active projectId. |
project.sql.community | Enable querying community SQL report- note that reports are limited to project data by "row level security" policies. |
project.sql.cubejs | Enables Cube.js query access. |
project.s3.read | Enable reading of S3 session recordings. |
project.api.get | GET API general methods. |
project.api.all | GET/POST/PUT/DELETE API general methods. |
browser.storage | Enable storage manager that safely sets browser storage (local/session/cookie storage). |
browser.network | Enables 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 Referenceconst manager = new WisdomAppManager(/* For Development, pass JWT here */);
Publishing & Approval Guidelines
- Manual upload of ZIP folder containing static web assets, with
index.htmlas 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 network2. All methods use promises3. 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) {}}