78 404 when the application put under nginx subdirectory with proxy pass (#79)

* use http.FileServer insetead of custom middleware

* fixed behavior under reverse proxy

* enabled reverse proxy subfolder as "domain value"

* domain validation

* code refactoring

* code refactoring

* updated translation
This commit is contained in:
Marco
2023-08-21 12:24:50 +02:00
committed by GitHub
parent a005f159c6
commit c50c1f627e
8 changed files with 55 additions and 29 deletions

View File

@@ -34,6 +34,7 @@ languages:
clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may close this window)
restartAppMessage: Needs a page reload to take effect
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
italian:
urlInput: URL di YouTube o di qualsiasi altro servizio supportato
statusTitle: Stato
@@ -67,6 +68,7 @@ languages:
clipboardAction: URL copiato negli appunti
playlistCheckbox: Download playlist (richiederà tempo, puoi chiudere la finestra dopo l'inoltro)
restartAppMessage: La finestra deve essere ricaricata perché abbia effetto
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
chinese:
urlInput: YouTube 或其他受支持服务的视频网址
statusTitle: 状态
@@ -100,6 +102,7 @@ languages:
archiveTitle: 归档
clipboardAction: 复制 URL 到剪贴板
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
spanish:
urlInput: URL de YouTube u otro servicio compatible
statusTitle: Estado
@@ -132,6 +135,7 @@ languages:
archiveTitle: Archive
clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
russian:
urlInput: URL-адрес YouTube или любого другого поддерживаемого сервиса
statusTitle: Статус
@@ -164,6 +168,7 @@ languages:
archiveTitle: Архив
clipboardAction: URL скопирован в буфер обмена
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
korean:
urlInput: YouTube나 다른 지원되는 사이트의 URL
statusTitle: 상태
@@ -196,6 +201,7 @@ languages:
archiveTitle: Archive
clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
japanese:
urlInput: YouTubeまたはサポート済み動画のURL
statusTitle: 状態
@@ -229,6 +235,7 @@ languages:
archiveTitle: Archive
clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
catalan:
urlInput: URL de YouTube o d'un altre servei compatible
statusTitle: Estat
@@ -261,6 +268,7 @@ languages:
archiveTitle: Archive
clipboardAction: Copied URL to clipboard
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
ukrainian:
urlInput: URL-адреса YouTube або будь-якого іншого підтримуваного сервісу
statusTitle: Статус
@@ -293,6 +301,7 @@ languages:
archiveTitle: Архів
clipboardAction: URL скопійовано в буфер обміну
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder
polish:
urlInput: Adres URL YouTube lub innej obsługiwanej usługi
statusTitle: Status
@@ -325,3 +334,4 @@ languages:
archiveTitle: Archiwum
clipboardAction: Adres URL zostanie skopiowany do schowka
playlistCheckbox: Download playlist (it will take time, after submitting you may even close this window)
servedFromReverseProxyCheckbox: Is behind a reverse proxy subfolder

View File

@@ -1,18 +1,6 @@
import { atom, selector } from 'recoil'
import { prefersDarkMode } from '../utils'
export type Language =
| 'english'
| 'chinese'
| 'russian'
| 'italian'
| 'spanish'
| 'korean'
| 'japanese'
| 'catalan'
| 'ukrainian'
| 'polish'
export const languages = [
'english',
'chinese',
@@ -26,6 +14,8 @@ export const languages = [
'polish',
] as const
export type Language = (typeof languages)[number]
export type Theme = 'light' | 'dark' | 'system'
export type ThemeNarrowed = 'light' | 'dark'
@@ -40,6 +30,7 @@ export interface SettingsState {
pathOverriding: boolean
enableCustomArgs: boolean
listView: boolean
servedFromReverseProxy: boolean
}
export const languageState = atom<Language>({
@@ -133,9 +124,20 @@ export const listViewState = atom({
]
})
export const servedFromReverseProxyState = atom({
key: 'servedFromReverseProxyState',
default: localStorage.getItem('reverseProxy') === "true",
effects: [
({ onSet }) =>
onSet(a => localStorage.setItem('reverseProxy', a.toString()))
]
})
export const serverAddressAndPortState = selector({
key: 'serverAddressAndPortState',
get: ({ get }) => `${get(serverAddressState)}:${get(serverPortState)}`
get: ({ get }) => get(servedFromReverseProxyState)
? `${get(serverAddressState)}`
: `${get(serverAddressState)}:${get(serverPortState)}`
})
export const serverURL = selector({
@@ -184,5 +186,6 @@ export const settingsState = selector<SettingsState>({
pathOverriding: get(pathOverridingState),
enableCustomArgs: get(enableCustomArgsState),
listView: get(listViewState),
servedFromReverseProxy: get(servedFromReverseProxyState),
})
})

View File

@@ -1,6 +1,6 @@
import { CircularProgress } from '@mui/material'
import { Suspense, lazy } from 'react'
import { createBrowserRouter } from 'react-router-dom'
import { createHashRouter } from 'react-router-dom'
import Layout from './Layout'
const Home = lazy(() => import('./views/Home'))
@@ -10,7 +10,7 @@ const Settings = lazy(() => import('./views/Settings'))
const ErrorBoundary = lazy(() => import('./components/ErrorBoundary'))
export const router = createBrowserRouter([
export const router = createHashRouter([
{
path: '/',
Component: () => <Layout />,

View File

@@ -19,9 +19,13 @@ export function validateIP(ipAddr: string): boolean {
* @param domainName
* @returns domain validity test
*/
export function validateDomain(domainName: string): boolean {
let domainRegex = /[^@ \t\r\n]+.[^@ \t\r\n]+\.[^@ \t\r\n]+/
return domainRegex.test(domainName) || domainName === 'localhost'
export function validateDomain(url: string): boolean {
const urlRegex = /(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()!@:%_\+.~#?&\/\/=]*)/
const slugRegex = /^[a-z0-9]+(?:-[a-z0-9]+)*$/
const [name, slug] = url.split('/')
return urlRegex.test(url) || name === 'localhost' && slugRegex.test(slug)
}
/**

View File

@@ -1,5 +1,6 @@
import {
Button,
Checkbox,
Container,
FormControl,
FormControlLabel,
@@ -36,6 +37,7 @@ import {
languages,
latestCliArgumentsState,
pathOverridingState,
servedFromReverseProxyState,
serverAddressState,
serverPortState,
themeState
@@ -48,6 +50,7 @@ import { validateDomain, validateIP } from '../utils'
// NEED ABSOLUTELY TO BE SPLIT IN MULTIPLE COMPONENTS
export default function Settings() {
const [reverseProxy, setReverseProxy] = useRecoilState(servedFromReverseProxyState)
const [formatSelection, setFormatSelection] = useRecoilState(formatSelectionState)
const [pathOverriding, setPathOverriding] = useRecoilState(pathOverridingState)
const [fileRenaming, setFileRenaming] = useRecoilState(fileRenamingState)
@@ -154,16 +157,27 @@ export default function Settings() {
InputProps={{
startAdornment: <InputAdornment position="start">ws://</InputAdornment>,
}}
sx={{ mb: 2 }}
/>
</Grid>
<Grid item xs={12} md={1}>
<TextField
disabled={reverseProxy}
fullWidth
label={i18n.t('serverPortTitle')}
defaultValue={serverPort}
onChange={(e) => serverPort$.next(e.currentTarget.value)}
error={isNaN(Number(serverPort)) || Number(serverPort) > 65535}
/>
</Grid>
<Grid item xs={12}>
<FormControlLabel
control={
<Checkbox
defaultChecked={reverseProxy}
onChange={() => setReverseProxy(state => !state)}
/>
}
label={i18n.t('servedFromReverseProxyCheckbox')}
sx={{ mb: 2 }}
/>
</Grid>

View File

@@ -1,7 +1,6 @@
import react from '@vitejs/plugin-react-swc'
import ViteYaml from '@modyfi/vite-plugin-yaml'
import { defineConfig } from 'vite'
import { resolve } from 'path'
export default defineConfig(() => {
return {
@@ -9,10 +8,9 @@ export default defineConfig(() => {
react(),
ViteYaml(),
],
root: resolve(__dirname, '.'),
base: '',
build: {
emptyOutDir: true,
outDir: resolve(__dirname, 'dist'),
}
}
})

View File

@@ -22,7 +22,8 @@ var (
requireAuth bool
rpcSecret string
//go:embed frontend/dist
//go:embed frontend/dist/index.html
//go:embed frontend/dist/assets/*
frontend embed.FS
)

View File

@@ -43,7 +43,6 @@ func RunBlocking(port int, frontend fs.FS) {
mq: mq,
})
// http-post
go gracefulShutdown(srv, &db)
go autoPersist(time.Minute*5, &db)
@@ -59,12 +58,9 @@ func newServer(c serverConfig) *http.Server {
r.Use(cors.AllowAll().Handler)
r.Use(middleware.Logger)
sh := middlewares.NewSpaHandler("index.html", c.frontend)
sh.AddClientRoute("/settings")
sh.AddClientRoute("/archive")
sh.AddClientRoute("/login")
app := http.FileServer(http.FS(c.frontend))
r.Get("/*", sh.Handler())
r.Mount("/", app)
// Archive routes
r.Route("/archive", func(r chi.Router) {