Skip to content

Commit

Permalink
Merge pull request #394 from powersync-ja/diagnostics-fixes
Browse files Browse the repository at this point in the history
Minor diagnostics-app improvements
  • Loading branch information
rkistner authored Nov 11, 2024
2 parents 7bd5cd0 + bc2ed4b commit 61c23b1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .changeset/mean-mayflies-learn.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@powersync/diagnostics-app': minor
---

Improved error messages for some token or endpoint issues
8 changes: 8 additions & 0 deletions tools/diagnostics-app/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export const getParams = () => {
const stringifiedParams = localStorage.getItem(PARAMS_STORE);
const params = safeParse(stringifiedParams);
return params;
}
};

export const schemaManager = new DynamicSchemaManager();

Expand Down Expand Up @@ -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;
}
Expand All @@ -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) => {
Expand Down
36 changes: 36 additions & 0 deletions tools/diagnostics-app/src/library/powersync/TokenConnector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ 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();
Expand All @@ -39,3 +41,37 @@ 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.`);
}
}

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`);
}
}

0 comments on commit 61c23b1

Please sign in to comment.