Skip to content

Commit 61c23b1

Browse files
authored
Merge pull request #394 from powersync-ja/diagnostics-fixes
Minor diagnostics-app improvements
2 parents 7bd5cd0 + bc2ed4b commit 61c23b1

File tree

4 files changed

+52
-2
lines changed

4 files changed

+52
-2
lines changed

.changeset/mean-mayflies-learn.md

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@powersync/diagnostics-app': minor
3+
---
4+
5+
Improved error messages for some token or endpoint issues

tools/diagnostics-app/README.md

+8
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@ The app is currently available at [https://diagnostics-app.powersync.com/](https
1111

1212
It can also be run as a local standalone web app, and is largely based on the [web SDK](/packages/web/).
1313

14+
## Running the app with Docker
15+
16+
```sh
17+
docker run --pull always -p 8082:80 journeyapps/powersync-diagnostics-app
18+
```
19+
20+
The app will be available on http://localhost:8082.
21+
1422
## Running the app locally
1523

1624
In the root of the repository, run:

tools/diagnostics-app/src/library/powersync/ConnectionManager.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ export const getParams = () => {
2121
const stringifiedParams = localStorage.getItem(PARAMS_STORE);
2222
const params = safeParse(stringifiedParams);
2323
return params;
24-
}
24+
};
2525

2626
export const schemaManager = new DynamicSchemaManager();
2727

@@ -88,7 +88,7 @@ export async function connect() {
8888
if (!sync.syncStatus.connected) {
8989
// Disconnect but don't wait for it
9090
sync.disconnect();
91-
throw syncErrorTracker.lastSyncError ?? new Error('Failed to conncet');
91+
throw syncErrorTracker.lastSyncError ?? new Error('Failed to connect');
9292
} else {
9393
syncErrorTracker.lastSyncError = null;
9494
}
@@ -112,6 +112,7 @@ export async function disconnect() {
112112
export async function signOut() {
113113
connector.clearCredentials();
114114
await db.disconnectAndClear();
115+
await schemaManager.clear();
115116
}
116117

117118
export const setParams = (p: object) => {

tools/diagnostics-app/src/library/powersync/TokenConnector.ts

+36
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ export class TokenConnector implements PowerSyncBackendConnector {
2222
}
2323

2424
async signIn(credentials: Credentials) {
25+
validateSecureContext(credentials.endpoint);
26+
checkJWT(credentials.token);
2527
try {
2628
localStorage.setItem('powersync_credentials', JSON.stringify(credentials));
2729
await connect();
@@ -39,3 +41,37 @@ export class TokenConnector implements PowerSyncBackendConnector {
3941
localStorage.removeItem('powersync_credentials');
4042
}
4143
}
44+
45+
function validateSecureContext(url: string) {
46+
if (!location.href.startsWith('https:')) {
47+
return;
48+
}
49+
const parsedUrl = new URL(url);
50+
const secure =
51+
parsedUrl.protocol === 'https:' ||
52+
parsedUrl.hostname === 'localhost' ||
53+
parsedUrl.hostname === '127.0.0.1' ||
54+
parsedUrl.hostname === '::1';
55+
if (!secure) {
56+
throw new Error(`Cannot connect to http endpoints from the hosted diagnostics app.
57+
Run either the PowerSync endpoint on http://localhost, or the diagnostics app on http://localhost.`);
58+
}
59+
}
60+
61+
function checkJWT(token: string) {
62+
// Split the token into parts by "."
63+
const parts = token.split('.');
64+
65+
// Check that it has exactly three parts (header, payload, signature)
66+
if (parts.length !== 3) {
67+
throw new Error(`Token must be a JWT: Expected 3 parts, got ${parts.length}`);
68+
}
69+
70+
// Check that each part is base64 or base64url encoded
71+
const base64UrlRegex = /^[A-Za-z0-9-_]+$/;
72+
73+
const isBase64 = parts.every((part) => base64UrlRegex.test(part));
74+
if (!isBase64) {
75+
throw new Error(`Token must be a JWT: Not all parts are base64 encoded`);
76+
}
77+
}

0 commit comments

Comments
 (0)