From f2196c5ff624b2ac37b73a91bf9e9bbbcb994c52 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:28:30 +0200 Subject: [PATCH 1/6] Better error message when connecting to insecure contexts. --- .../src/library/powersync/TokenConnector.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tools/diagnostics-app/src/library/powersync/TokenConnector.ts b/tools/diagnostics-app/src/library/powersync/TokenConnector.ts index 59e82c18..0799657d 100644 --- a/tools/diagnostics-app/src/library/powersync/TokenConnector.ts +++ b/tools/diagnostics-app/src/library/powersync/TokenConnector.ts @@ -22,6 +22,7 @@ export class TokenConnector implements PowerSyncBackendConnector { } async signIn(credentials: Credentials) { + validateSecureContext(credentials.endpoint); try { localStorage.setItem('powersync_credentials', JSON.stringify(credentials)); await connect(); @@ -39,3 +40,19 @@ export class TokenConnector implements PowerSyncBackendConnector { localStorage.removeItem('powersync_credentials'); } } + +function validateSecureContext(url: string) { + if (!location.href.startsWith('https:')) { + return; + } + const parsedUrl = new URL(url); + const secure = + parsedUrl.protocol === 'https:' || + parsedUrl.hostname === 'localhost' || + parsedUrl.hostname === '127.0.0.1' || + parsedUrl.hostname === '::1'; + if (!secure) { + throw new Error(`Cannot connect to http endpoints from the hosted diagnostics app. +Run either the PowerSync endpoint on http://localhost, or the diagnostics app on http://localhost.`); + } +} From 2411b15d7c957f612916fd06795a17e1ceeb1eb0 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:31:30 +0200 Subject: [PATCH 2/6] Basic token validation. --- .../src/library/powersync/TokenConnector.ts | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tools/diagnostics-app/src/library/powersync/TokenConnector.ts b/tools/diagnostics-app/src/library/powersync/TokenConnector.ts index 0799657d..49055d0f 100644 --- a/tools/diagnostics-app/src/library/powersync/TokenConnector.ts +++ b/tools/diagnostics-app/src/library/powersync/TokenConnector.ts @@ -23,6 +23,7 @@ export class TokenConnector implements PowerSyncBackendConnector { async signIn(credentials: Credentials) { validateSecureContext(credentials.endpoint); + checkJWT(credentials.token); try { localStorage.setItem('powersync_credentials', JSON.stringify(credentials)); await connect(); @@ -56,3 +57,21 @@ function validateSecureContext(url: string) { Run either the PowerSync endpoint on http://localhost, or the diagnostics app on http://localhost.`); } } + +function checkJWT(token: string) { + // Split the token into parts by "." + const parts = token.split('.'); + + // Check that it has exactly three parts (header, payload, signature) + if (parts.length !== 3) { + throw new Error(`Token must be a JWT: Expected 3 parts, got ${parts.length}`); + } + + // Check that each part is base64 or base64url encoded + const base64UrlRegex = /^[A-Za-z0-9-_]+$/; + + const isBase64 = parts.every((part) => base64UrlRegex.test(part)); + if (!isBase64) { + throw new Error(`Token must be a JWT: Not all parts are base64 encoded`); + } +} From 5b529cfd91bd15256bd182ee1575efefa4741ce5 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:34:16 +0200 Subject: [PATCH 3/6] Fix typo. --- .../src/library/powersync/ConnectionManager.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts b/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts index c9b7df01..825afdd2 100644 --- a/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts +++ b/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts @@ -21,7 +21,7 @@ export const getParams = () => { const stringifiedParams = localStorage.getItem(PARAMS_STORE); const params = safeParse(stringifiedParams); return params; -} +}; export const schemaManager = new DynamicSchemaManager(); @@ -88,7 +88,7 @@ export async function connect() { if (!sync.syncStatus.connected) { // Disconnect but don't wait for it sync.disconnect(); - throw syncErrorTracker.lastSyncError ?? new Error('Failed to conncet'); + throw syncErrorTracker.lastSyncError ?? new Error('Failed to connect'); } else { syncErrorTracker.lastSyncError = null; } From 8221aa0db507d49a17151cfc39fafaa6de8b432a Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:38:50 +0200 Subject: [PATCH 4/6] Add notes on running with Docker. --- tools/diagnostics-app/README.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/diagnostics-app/README.md b/tools/diagnostics-app/README.md index 2a7d9216..3c008822 100644 --- a/tools/diagnostics-app/README.md +++ b/tools/diagnostics-app/README.md @@ -11,6 +11,14 @@ The app is currently available at [https://diagnostics-app.powersync.com/](https It can also be run as a local standalone web app, and is largely based on the [web SDK](/packages/web/). +## Running the app with Docker + +```sh +docker run --pull always -p 8082:80 journeyapps/powersync-diagnostics-app +``` + +The app will be available on http://localhost:8082. + ## Running the app locally In the root of the repository, run: From 677d7824123e8264a905df6ac4adb07b8293fb18 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:39:45 +0200 Subject: [PATCH 5/6] Add changeset. --- .changeset/mean-mayflies-learn.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/mean-mayflies-learn.md diff --git a/.changeset/mean-mayflies-learn.md b/.changeset/mean-mayflies-learn.md new file mode 100644 index 00000000..09473a94 --- /dev/null +++ b/.changeset/mean-mayflies-learn.md @@ -0,0 +1,5 @@ +--- +'@powersync/diagnostics-app': minor +--- + +Improved error messages for some token or endpoint issues From bc2ed4b9f6729c7ed5a059a5b5d9f8489b934673 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:41:14 +0200 Subject: [PATCH 6/6] Clear dynamic schema when signing out. --- tools/diagnostics-app/src/library/powersync/ConnectionManager.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts b/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts index 825afdd2..52595214 100644 --- a/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts +++ b/tools/diagnostics-app/src/library/powersync/ConnectionManager.ts @@ -112,6 +112,7 @@ export async function disconnect() { export async function signOut() { connector.clearCredentials(); await db.disconnectAndClear(); + await schemaManager.clear(); } export const setParams = (p: object) => {