Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 92be2a30d1 | |||
| f4f6e8560b | |||
| 1900dd9cb1 | |||
| 1226bd28aa | |||
| 7cdee73542 | |||
| e8ba8ffdba | |||
| 52298d1d46 | |||
| 7fc5d66b8c |
@@ -10,14 +10,21 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 20 }
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'web/package-lock.json'
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('web/package-lock.json') }}
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Cache Rust target and registry
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
workspaces: 'web/src-tauri'
|
||||
path: |
|
||||
~/.cargo/registry
|
||||
~/.cargo/git
|
||||
web/src-tauri/target
|
||||
key: ${{ runner.os }}-cargo-${{ hashFiles('web/src-tauri/Cargo.lock') }}
|
||||
- name: Install system deps
|
||||
run: sudo apt-get update && sudo apt-get install -y libwebkit2gtk-4.1-dev libgtk-3-dev libappindicator3-dev librsvg2-dev patchelf rpm
|
||||
- name: Build frontend
|
||||
@@ -40,10 +47,12 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/setup-node@v4
|
||||
with: { node-version: 20 }
|
||||
- name: Cache npm
|
||||
uses: actions/cache@v3
|
||||
with:
|
||||
node-version: 20
|
||||
cache: 'npm'
|
||||
cache-dependency-path: 'web/package-lock.json'
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-npm-${{ hashFiles('web/package-lock.json') }}
|
||||
- name: Install Rust
|
||||
run: |
|
||||
curl.exe -sLo rustup-init.exe https://win.rustup.rs/x86_64
|
||||
@@ -51,9 +60,11 @@ jobs:
|
||||
set PATH=%USERPROFILE%\.cargo\bin;%PATH%
|
||||
rustc --version
|
||||
shell: cmd
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- name: Cache Rust target and registry
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: 'web/src-tauri'
|
||||
workspaces: |
|
||||
web/src-tauri
|
||||
- name: Build frontend
|
||||
run: cd web && npm ci && npm run build
|
||||
shell: cmd
|
||||
@@ -82,5 +93,8 @@ jobs:
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
files: |
|
||||
linux-bundles/*
|
||||
windows-bundles/*
|
||||
linux-bundles/**/*.AppImage
|
||||
linux-bundles/**/*.deb
|
||||
linux-bundles/**/*.rpm
|
||||
windows-bundles/**/*.msi
|
||||
windows-bundles/**/*.exe
|
||||
|
||||
+12
-1
@@ -37,6 +37,7 @@ import (
|
||||
"git.dustin.coffee/hobokenchicken/dumpsterChat/internal/webhook"
|
||||
"github.com/go-chi/chi/v5"
|
||||
chimw "github.com/go-chi/chi/v5/middleware"
|
||||
"github.com/go-chi/cors"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
)
|
||||
|
||||
@@ -70,7 +71,7 @@ func main() {
|
||||
sessionStore := auth.NewSessionStore(database.DB, cfg)
|
||||
|
||||
// WebSocket origin allowlist
|
||||
wsOrigins := []string{"https://" + cfg.Host}
|
||||
wsOrigins := []string{"https://" + cfg.Host, "http://tauri.localhost", "https://tauri.localhost", "tauri://localhost"}
|
||||
if cfg.Host == "localhost" {
|
||||
wsOrigins = append(wsOrigins, "http://localhost:"+cfg.Port)
|
||||
}
|
||||
@@ -119,6 +120,16 @@ func main() {
|
||||
memberHandler := server.NewMemberHandler(database.DB)
|
||||
|
||||
r := chi.NewRouter()
|
||||
|
||||
r.Use(cors.Handler(cors.Options{
|
||||
AllowedOrigins: []string{"https://" + cfg.Host, "http://localhost:" + cfg.Port, "http://tauri.localhost", "https://tauri.localhost", "tauri://localhost"},
|
||||
AllowedMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS"},
|
||||
AllowedHeaders: []string{"Accept", "Authorization", "Content-Type", "X-CSRF-Token"},
|
||||
ExposedHeaders: []string{"Link"},
|
||||
AllowCredentials: true,
|
||||
MaxAge: 300,
|
||||
}))
|
||||
|
||||
r.Use(chimw.Logger)
|
||||
r.Use(chimw.Recoverer)
|
||||
r.Use(chimw.RequestID)
|
||||
|
||||
@@ -49,6 +49,7 @@ require (
|
||||
github.com/fsnotify/fsnotify v1.10.1 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.9.2 // indirect
|
||||
github.com/gammazero/deque v1.2.1 // indirect
|
||||
github.com/go-chi/cors v1.2.2 // indirect
|
||||
github.com/go-logr/logr v1.4.3 // indirect
|
||||
github.com/go-logr/stdr v1.2.2 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
|
||||
@@ -87,6 +87,8 @@ github.com/gammazero/deque v1.2.1 h1:9fnQVFCCZ9/NOc7ccTNqzoKd1tCWOqeI05/lPqFPMGQ
|
||||
github.com/gammazero/deque v1.2.1/go.mod h1:5nSFkzVm+afG9+gy0VIowlqVAW4N8zNcMne+CMQVD2g=
|
||||
github.com/go-chi/chi/v5 v5.3.0 h1:halUjDxhshgXHMrao5bB8eNBXo/rnzwr8m5m36glehM=
|
||||
github.com/go-chi/chi/v5 v5.3.0/go.mod h1:R+tYY2hNuVUUjxoPtqUdgBqevM9s9njzkTLutVsOCto=
|
||||
github.com/go-chi/cors v1.2.2 h1:Jmey33TE+b+rB7fT8MUy1u0I4L+NARQlK6LhzKPSyQE=
|
||||
github.com/go-chi/cors v1.2.2/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
|
||||
@@ -17,7 +17,7 @@ func SetSessionCookie(w http.ResponseWriter, cookieName, token string, duration
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
Secure: secure,
|
||||
SameSite: http.SameSiteLaxMode,
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
MaxAge: int(duration.Seconds()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -234,7 +234,8 @@ func (h *WebAuthnHandler) LoginBegin(w http.ResponseWriter, r *http.Request) {
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
MaxAge: 300, // 5 minutes
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
Secure: true,
|
||||
})
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
@@ -341,7 +342,8 @@ func (h *WebAuthnHandler) LoginFinish(w http.ResponseWriter, r *http.Request) {
|
||||
Path: "/",
|
||||
HttpOnly: true,
|
||||
MaxAge: -1,
|
||||
SameSite: http.SameSiteStrictMode,
|
||||
SameSite: http.SameSiteNoneMode,
|
||||
Secure: true,
|
||||
})
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"project_info": {
|
||||
"project_number": "629643353973",
|
||||
"project_id": "dumpster-chat",
|
||||
"storage_bucket": "dumpster-chat.firebasestorage.app"
|
||||
},
|
||||
"client": [
|
||||
{
|
||||
"client_info": {
|
||||
"mobilesdk_app_id": "1:629643353973:android:29dcc703959dd306c0fd3c",
|
||||
"android_client_info": {
|
||||
"package_name": "coffee.dustin.dumpster"
|
||||
}
|
||||
},
|
||||
"oauth_client": [],
|
||||
"api_key": [
|
||||
{
|
||||
"current_key": "AIzaSyDt3h4G-imzD7IedRqYOUBIv8CtZQT2YyA"
|
||||
}
|
||||
],
|
||||
"services": {
|
||||
"appinvite_service": {
|
||||
"other_platform_oauth_client": []
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
"configuration_version": "1"
|
||||
}
|
||||
+10
-1
@@ -60,11 +60,20 @@
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.tsx"></script>
|
||||
<script>
|
||||
// Register service worker
|
||||
// Register service worker (only for web, avoid in Tauri to prevent 404 cache bugs)
|
||||
if ('serviceWorker' in navigator) {
|
||||
if (!('__TAURI_INTERNALS__' in window) && !('__TAURI__' in window)) {
|
||||
window.addEventListener('load', () => {
|
||||
navigator.serviceWorker.register('/sw.js').catch(() => {});
|
||||
});
|
||||
} else {
|
||||
// In Tauri, aggressively unregister any old service workers that might be causing 404s
|
||||
navigator.serviceWorker.getRegistrations().then((registrations) => {
|
||||
for (let registration of registrations) {
|
||||
registration.unregister();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
|
||||
@@ -3,6 +3,71 @@ import { createRoot } from 'react-dom/client';
|
||||
import './styles/index.css';
|
||||
import App from './App.tsx';
|
||||
|
||||
const isTauri = 'window' in globalThis && '__TAURI_INTERNALS__' in window;
|
||||
if (isTauri) {
|
||||
const TARGET = 'https://dumpster.dustin.coffee';
|
||||
const WS_TARGET = 'wss://dumpster.dustin.coffee';
|
||||
|
||||
let sessionToken = localStorage.getItem('dumpster_session_token') || '';
|
||||
|
||||
const originalFetch = window.fetch;
|
||||
window.fetch = async (input, init) => {
|
||||
let url = typeof input === 'string' ? input : input.toString();
|
||||
if (url.startsWith('/')) {
|
||||
url = TARGET + url;
|
||||
}
|
||||
|
||||
let newInit = init ? { ...init } : {};
|
||||
if (sessionToken) {
|
||||
newInit.headers = {
|
||||
...newInit.headers,
|
||||
'Authorization': 'Bearer ' + sessionToken
|
||||
};
|
||||
}
|
||||
|
||||
const response = await originalFetch(url, newInit);
|
||||
|
||||
const token = response.headers.get('X-Session-Token');
|
||||
if (token) {
|
||||
sessionToken = token;
|
||||
localStorage.setItem('dumpster_session_token', token);
|
||||
}
|
||||
|
||||
if (url.endsWith('/auth/logout') && response.ok) {
|
||||
sessionToken = '';
|
||||
localStorage.removeItem('dumpster_session_token');
|
||||
}
|
||||
|
||||
return response;
|
||||
};
|
||||
|
||||
const OriginalWebSocket = window.WebSocket;
|
||||
window.WebSocket = function(url: string | URL, protocols?: string | string[]) {
|
||||
let urlStr = typeof url === 'string' ? url : url.toString();
|
||||
if (urlStr.includes('tauri.localhost') || urlStr.includes('tauri://localhost')) {
|
||||
urlStr = urlStr.replace(/^(wss?|https?|tauri):\/\/tauri\.localhost/, WS_TARGET);
|
||||
urlStr = urlStr.replace(/^tauri:\/\/localhost/, WS_TARGET);
|
||||
} else if (urlStr.startsWith('ws://localhost') && isTauri) {
|
||||
urlStr = urlStr.replace('ws://localhost', WS_TARGET);
|
||||
} else if (urlStr.startsWith('/')) {
|
||||
urlStr = WS_TARGET + urlStr;
|
||||
}
|
||||
|
||||
const ws = new OriginalWebSocket(urlStr, protocols);
|
||||
|
||||
if (sessionToken && urlStr.includes('/ws') && !urlStr.includes('/ws/bot')) {
|
||||
const originalOnOpen = ws.onopen;
|
||||
ws.onopen = function(ev) {
|
||||
ws.send(JSON.stringify({ token: sessionToken }));
|
||||
if (originalOnOpen) originalOnOpen.call(ws, ev);
|
||||
};
|
||||
}
|
||||
|
||||
return ws;
|
||||
} as unknown as typeof WebSocket;
|
||||
window.WebSocket.prototype = OriginalWebSocket.prototype;
|
||||
}
|
||||
|
||||
createRoot(document.getElementById('root')!).render(
|
||||
<StrictMode>
|
||||
<App />
|
||||
|
||||
Reference in New Issue
Block a user