Compare commits
5 Commits
v4.10.2
...
improve-sw
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b9dda2c553 | ||
|
|
073a9f5786 | ||
|
|
655c1c9aff | ||
|
|
17d4bceb42 | ||
|
|
0f61f2f328 |
4
.github/workflows/prod-deploy.yml
vendored
4
.github/workflows/prod-deploy.yml
vendored
@@ -72,12 +72,12 @@ jobs:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3.11.1
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.6.0
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_PASSWORD }}
|
||||
- name: Login to the Container registry
|
||||
uses: docker/login-action@v3.5.0
|
||||
uses: docker/login-action@v3.6.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
|
||||
@@ -11,7 +11,7 @@ RUN npm run build
|
||||
|
||||
|
||||
## App
|
||||
FROM nginx:1.29.1-alpine
|
||||
FROM nginx:1.29.3-alpine
|
||||
|
||||
COPY --from=builder /src/dist /app
|
||||
COPY --from=builder /src/docker-nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
@@ -212,9 +212,10 @@ export const getMentions = (mx: MatrixClient, roomId: string, editor: Editor): M
|
||||
if (node.type === BlockType.CodeBlock) return;
|
||||
|
||||
if (node.type === BlockType.Mention) {
|
||||
if (node.id === getCanonicalAliasOrRoomId(mx, roomId)) {
|
||||
if (node.name === '@room') {
|
||||
mentionData.room = true;
|
||||
}
|
||||
|
||||
if (isUserId(node.id) && node.id !== mx.getUserId()) {
|
||||
mentionData.users.add(node.id);
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ export function CreateRoomForm({ defaultKind, space, onCreate }: CreateRoomFormP
|
||||
onClick={() => setAdvance(!advance)}
|
||||
type="button"
|
||||
>
|
||||
<Text size="T200">Advance Options</Text>
|
||||
<Text size="T200">Advanced Options</Text>
|
||||
</Chip>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -184,7 +184,7 @@ export function CreateSpaceForm({ defaultKind, space, onCreate }: CreateSpaceFor
|
||||
onClick={() => setAdvance(!advance)}
|
||||
type="button"
|
||||
>
|
||||
<Text size="T200">Advance Options</Text>
|
||||
<Text size="T200">Advanced Options</Text>
|
||||
</Chip>
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -59,7 +59,7 @@ export function General({ requestClose }: GeneralProps) {
|
||||
<RoomLocalAddresses permissions={permissions} />
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">Advance Options</Text>
|
||||
<Text size="L400">Advanced Options</Text>
|
||||
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -55,7 +55,7 @@ export function General({ requestClose }: GeneralProps) {
|
||||
<RoomLocalAddresses permissions={permissions} />
|
||||
</Box>
|
||||
<Box direction="Column" gap="100">
|
||||
<Text size="L400">Advance Options</Text>
|
||||
<Text size="L400">Advanced Options</Text>
|
||||
<RoomUpgrade permissions={permissions} requestClose={requestClose} />
|
||||
</Box>
|
||||
</Box>
|
||||
|
||||
@@ -68,6 +68,7 @@ import { Create } from './client/create';
|
||||
import { CreateSpaceModalRenderer } from '../features/create-space';
|
||||
import { SearchModalRenderer } from '../features/search';
|
||||
import { getFallbackSession } from '../state/sessions';
|
||||
import { pushSessionToSW } from '../../sw-session';
|
||||
|
||||
export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize) => {
|
||||
const { hashRouter } = clientConfig;
|
||||
@@ -106,7 +107,8 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize)
|
||||
|
||||
<Route
|
||||
loader={() => {
|
||||
if (!getFallbackSession()) {
|
||||
const session = getFallbackSession();
|
||||
if (!session) {
|
||||
const afterLoginPath = getAppPathFromHref(
|
||||
getOriginBaseUrl(hashRouter),
|
||||
window.location.href
|
||||
@@ -114,6 +116,7 @@ export const createRouter = (clientConfig: ClientConfig, screenSize: ScreenSize)
|
||||
if (afterLoginPath) setAfterLoginRedirectPath(afterLoginPath);
|
||||
return redirect(getLoginPath());
|
||||
}
|
||||
pushSessionToSW(session.baseUrl, session.accessToken);
|
||||
return null;
|
||||
}}
|
||||
element={
|
||||
|
||||
@@ -2,6 +2,7 @@ import { createClient, MatrixClient, IndexedDBStore, IndexedDBCryptoStore } from
|
||||
|
||||
import { cryptoCallbacks } from './secretStorageKeys';
|
||||
import { clearNavToActivePathStore } from '../app/state/navToActivePath';
|
||||
import { pushSessionToSW } from '../sw-session';
|
||||
|
||||
type Session = {
|
||||
baseUrl: string;
|
||||
@@ -53,6 +54,7 @@ export const clearCacheAndReload = async (mx: MatrixClient) => {
|
||||
};
|
||||
|
||||
export const logoutClient = async (mx: MatrixClient) => {
|
||||
pushSessionToSW();
|
||||
mx.stopClient();
|
||||
try {
|
||||
await mx.logout();
|
||||
|
||||
@@ -15,6 +15,8 @@ import App from './app/pages/App';
|
||||
|
||||
// import i18n (needs to be bundled ;))
|
||||
import './app/i18n';
|
||||
import { pushSessionToSW } from './sw-session';
|
||||
import { getFallbackSession } from './app/state/sessions';
|
||||
|
||||
document.body.classList.add(configClass, varsClass);
|
||||
|
||||
@@ -25,16 +27,9 @@ if ('serviceWorker' in navigator) {
|
||||
? `${trimTrailingSlash(import.meta.env.BASE_URL)}/sw.js`
|
||||
: `/dev-sw.js?dev-sw`;
|
||||
|
||||
navigator.serviceWorker.register(swUrl);
|
||||
navigator.serviceWorker.addEventListener('message', (event) => {
|
||||
if (event.data?.type === 'token' && event.data?.responseKey) {
|
||||
// Get the token for SW.
|
||||
const token = localStorage.getItem('cinny_access_token') ?? undefined;
|
||||
event.source!.postMessage({
|
||||
responseKey: event.data.responseKey,
|
||||
token,
|
||||
});
|
||||
}
|
||||
navigator.serviceWorker.register(swUrl).then(() => {
|
||||
const session = getFallbackSession();
|
||||
pushSessionToSW(session?.baseUrl, session?.accessToken);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
10
src/sw-session.ts
Normal file
10
src/sw-session.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export function pushSessionToSW(baseUrl?: string, accessToken?: string) {
|
||||
if (!('serviceWorker' in navigator)) return;
|
||||
if (!navigator.serviceWorker.controller) return;
|
||||
|
||||
navigator.serviceWorker.controller.postMessage({
|
||||
type: 'setSession',
|
||||
accessToken,
|
||||
baseUrl,
|
||||
});
|
||||
}
|
||||
94
src/sw.ts
94
src/sw.ts
@@ -3,22 +3,64 @@
|
||||
export type {};
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
async function askForAccessToken(client: Client): Promise<string | undefined> {
|
||||
return new Promise((resolve) => {
|
||||
const responseKey = Math.random().toString(36);
|
||||
const listener = (event: ExtendableMessageEvent) => {
|
||||
if (event.data.responseKey !== responseKey) return;
|
||||
resolve(event.data.token);
|
||||
self.removeEventListener('message', listener);
|
||||
};
|
||||
self.addEventListener('message', listener);
|
||||
client.postMessage({ responseKey, type: 'token' });
|
||||
self.addEventListener('install', () => {
|
||||
self.skipWaiting();
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event: ExtendableEvent) => {
|
||||
event.waitUntil(self.clients.claim());
|
||||
});
|
||||
|
||||
type SessionInfo = {
|
||||
accessToken: string;
|
||||
baseUrl: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Store session per client (tab)
|
||||
*/
|
||||
const sessions = new Map<string, SessionInfo>();
|
||||
|
||||
async function cleanupDeadClients() {
|
||||
const activeClients = await self.clients.matchAll();
|
||||
const activeIds = new Set(activeClients.map((c) => c.id));
|
||||
|
||||
Array.from(sessions.keys()).forEach((id) => {
|
||||
if (!activeIds.has(id)) {
|
||||
sessions.delete(id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function fetchConfig(token?: string): RequestInit | undefined {
|
||||
if (!token) return undefined;
|
||||
/**
|
||||
* Receive session updates from clients
|
||||
*/
|
||||
self.addEventListener('message', (event: ExtendableMessageEvent) => {
|
||||
const client = event.source as Client | null;
|
||||
if (!client) return;
|
||||
|
||||
const { type, accessToken, baseUrl } = event.data || {};
|
||||
|
||||
if (type !== 'setSession') return;
|
||||
|
||||
cleanupDeadClients();
|
||||
|
||||
if (typeof accessToken === 'string' && typeof baseUrl === 'string') {
|
||||
sessions.set(client.id, { accessToken, baseUrl });
|
||||
} else {
|
||||
// Logout or invalid session
|
||||
sessions.delete(client.id);
|
||||
}
|
||||
});
|
||||
|
||||
function validMediaRequest(url: string, baseUrl: string): boolean {
|
||||
const downloadUrl = new URL('/_matrix/client/v1/media/download', baseUrl);
|
||||
const thumbnailUrl = new URL('/_matrix/client/v1/media/thumbnail', baseUrl);
|
||||
|
||||
return url.startsWith(downloadUrl.href) || url.startsWith(thumbnailUrl.href);
|
||||
}
|
||||
|
||||
function fetchConfig(token: string): RequestInit {
|
||||
return {
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`,
|
||||
@@ -27,26 +69,16 @@ function fetchConfig(token?: string): RequestInit | undefined {
|
||||
};
|
||||
}
|
||||
|
||||
self.addEventListener('activate', (event: ExtendableEvent) => {
|
||||
event.waitUntil(clients.claim());
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event: FetchEvent) => {
|
||||
const { url, method } = event.request;
|
||||
if (method !== 'GET') return;
|
||||
if (
|
||||
!url.includes('/_matrix/client/v1/media/download') &&
|
||||
!url.includes('/_matrix/client/v1/media/thumbnail')
|
||||
) {
|
||||
return;
|
||||
}
|
||||
event.respondWith(
|
||||
(async (): Promise<Response> => {
|
||||
const client = await self.clients.get(event.clientId);
|
||||
let token: string | undefined;
|
||||
if (client) token = await askForAccessToken(client);
|
||||
|
||||
return fetch(url, fetchConfig(token));
|
||||
})()
|
||||
);
|
||||
if (method !== 'GET') return;
|
||||
if (!event.clientId) return;
|
||||
|
||||
const session = sessions.get(event.clientId);
|
||||
if (!session) return;
|
||||
|
||||
if (!validMediaRequest(url, session.baseUrl)) return;
|
||||
|
||||
event.respondWith(fetch(url, fetchConfig(session.accessToken)));
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user