diff --git a/apps/common/Web/Embedded.hs b/apps/common/Web/Embedded.hs new file mode 100644 index 000000000..9dae7b53f --- /dev/null +++ b/apps/common/Web/Embedded.hs @@ -0,0 +1,15 @@ +{-# LANGUAGE TemplateHaskell #-} + +module Web.Embedded where + +import Data.FileEmbed (embedDir, embedFile) +import Simplex.Messaging.Server.Web (EmbeddedContent (..)) + +embeddedContent :: EmbeddedContent +embeddedContent = + EmbeddedContent + { indexHtml = $(embedFile "apps/common/Web/static/index.html"), + linkHtml = $(embedFile "apps/common/Web/static/link.html"), + mediaContent = $(embedDir "apps/common/Web/static/media/"), + wellKnown = $(embedDir "apps/common/Web/static/.well-known/") + } diff --git a/src/Simplex/Messaging/Server/Web/.well-known/apple-app-site-association b/apps/common/Web/static/.well-known/apple-app-site-association similarity index 100% rename from src/Simplex/Messaging/Server/Web/.well-known/apple-app-site-association rename to apps/common/Web/static/.well-known/apple-app-site-association diff --git a/src/Simplex/Messaging/Server/Web/.well-known/assetlinks.json b/apps/common/Web/static/.well-known/assetlinks.json similarity index 100% rename from src/Simplex/Messaging/Server/Web/.well-known/assetlinks.json rename to apps/common/Web/static/.well-known/assetlinks.json diff --git a/src/Simplex/Messaging/Server/Web/index.html b/apps/common/Web/static/index.html similarity index 100% rename from src/Simplex/Messaging/Server/Web/index.html rename to apps/common/Web/static/index.html diff --git a/src/Simplex/Messaging/Server/Web/link.html b/apps/common/Web/static/link.html similarity index 100% rename from src/Simplex/Messaging/Server/Web/link.html rename to apps/common/Web/static/link.html diff --git a/src/Simplex/Messaging/Server/Web/media/GilroyBold.woff2 b/apps/common/Web/static/media/GilroyBold.woff2 similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/GilroyBold.woff2 rename to apps/common/Web/static/media/GilroyBold.woff2 diff --git a/src/Simplex/Messaging/Server/Web/media/GilroyLight.woff2 b/apps/common/Web/static/media/GilroyLight.woff2 similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/GilroyLight.woff2 rename to apps/common/Web/static/media/GilroyLight.woff2 diff --git a/src/Simplex/Messaging/Server/Web/media/GilroyMedium.woff2 b/apps/common/Web/static/media/GilroyMedium.woff2 similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/GilroyMedium.woff2 rename to apps/common/Web/static/media/GilroyMedium.woff2 diff --git a/src/Simplex/Messaging/Server/Web/media/GilroyRegular.woff2 b/apps/common/Web/static/media/GilroyRegular.woff2 similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/GilroyRegular.woff2 rename to apps/common/Web/static/media/GilroyRegular.woff2 diff --git a/src/Simplex/Messaging/Server/Web/media/GilroyRegularItalic.woff2 b/apps/common/Web/static/media/GilroyRegularItalic.woff2 similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/GilroyRegularItalic.woff2 rename to apps/common/Web/static/media/GilroyRegularItalic.woff2 diff --git a/src/Simplex/Messaging/Server/Web/media/apk_icon.png b/apps/common/Web/static/media/apk_icon.png similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/apk_icon.png rename to apps/common/Web/static/media/apk_icon.png diff --git a/src/Simplex/Messaging/Server/Web/media/apple_store.svg b/apps/common/Web/static/media/apple_store.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/apple_store.svg rename to apps/common/Web/static/media/apple_store.svg diff --git a/src/Simplex/Messaging/Server/Web/media/contact.js b/apps/common/Web/static/media/contact.js similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/contact.js rename to apps/common/Web/static/media/contact.js diff --git a/src/Simplex/Messaging/Server/Web/media/contact_page_mobile.png b/apps/common/Web/static/media/contact_page_mobile.png similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/contact_page_mobile.png rename to apps/common/Web/static/media/contact_page_mobile.png diff --git a/src/Simplex/Messaging/Server/Web/media/f_droid.svg b/apps/common/Web/static/media/f_droid.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/f_droid.svg rename to apps/common/Web/static/media/f_droid.svg diff --git a/src/Simplex/Messaging/Server/Web/media/favicon.ico b/apps/common/Web/static/media/favicon.ico similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/favicon.ico rename to apps/common/Web/static/media/favicon.ico diff --git a/src/Simplex/Messaging/Server/Web/media/google_play.svg b/apps/common/Web/static/media/google_play.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/google_play.svg rename to apps/common/Web/static/media/google_play.svg diff --git a/src/Simplex/Messaging/Server/Web/media/logo-dark.png b/apps/common/Web/static/media/logo-dark.png similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/logo-dark.png rename to apps/common/Web/static/media/logo-dark.png diff --git a/src/Simplex/Messaging/Server/Web/media/logo-light.png b/apps/common/Web/static/media/logo-light.png similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/logo-light.png rename to apps/common/Web/static/media/logo-light.png diff --git a/src/Simplex/Messaging/Server/Web/media/logo-symbol-dark.svg b/apps/common/Web/static/media/logo-symbol-dark.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/logo-symbol-dark.svg rename to apps/common/Web/static/media/logo-symbol-dark.svg diff --git a/src/Simplex/Messaging/Server/Web/media/logo-symbol-light.svg b/apps/common/Web/static/media/logo-symbol-light.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/logo-symbol-light.svg rename to apps/common/Web/static/media/logo-symbol-light.svg diff --git a/src/Simplex/Messaging/Server/Web/media/moon.svg b/apps/common/Web/static/media/moon.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/moon.svg rename to apps/common/Web/static/media/moon.svg diff --git a/src/Simplex/Messaging/Server/Web/media/qrcode.js b/apps/common/Web/static/media/qrcode.js similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/qrcode.js rename to apps/common/Web/static/media/qrcode.js diff --git a/src/Simplex/Messaging/Server/Web/media/script.js b/apps/common/Web/static/media/script.js similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/script.js rename to apps/common/Web/static/media/script.js diff --git a/src/Simplex/Messaging/Server/Web/media/style.css b/apps/common/Web/static/media/style.css similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/style.css rename to apps/common/Web/static/media/style.css diff --git a/src/Simplex/Messaging/Server/Web/media/sun.svg b/apps/common/Web/static/media/sun.svg similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/sun.svg rename to apps/common/Web/static/media/sun.svg diff --git a/src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.css b/apps/common/Web/static/media/swiper-bundle.min.css similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.css rename to apps/common/Web/static/media/swiper-bundle.min.css diff --git a/src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.js b/apps/common/Web/static/media/swiper-bundle.min.js similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.js rename to apps/common/Web/static/media/swiper-bundle.min.js diff --git a/src/Simplex/Messaging/Server/Web/media/tailwind.css b/apps/common/Web/static/media/tailwind.css similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/tailwind.css rename to apps/common/Web/static/media/tailwind.css diff --git a/src/Simplex/Messaging/Server/Web/media/testflight.png b/apps/common/Web/static/media/testflight.png similarity index 100% rename from src/Simplex/Messaging/Server/Web/media/testflight.png rename to apps/common/Web/static/media/testflight.png diff --git a/apps/smp-server/SMPWeb.hs b/apps/smp-server/SMPWeb.hs index efa7edee3..9a449e80b 100644 --- a/apps/smp-server/SMPWeb.hs +++ b/apps/smp-server/SMPWeb.hs @@ -8,23 +8,23 @@ module SMPWeb import Data.ByteString (ByteString) import Data.String (fromString) +import Web.Embedded (embeddedContent) import Simplex.Messaging.Encoding.String (strEncode) import Simplex.Messaging.Server.Information import Simplex.Messaging.Server.Main (simplexmqSource) import qualified Simplex.Messaging.Server.Web as Web import Simplex.Messaging.Server.Web (render, serverInfoSubsts, timedTTLText) -import Simplex.Messaging.Server.Web.Embedded as E import Simplex.Messaging.Transport.Client (TransportHost (..)) smpGenerateSite :: ServerInformation -> Maybe TransportHost -> FilePath -> IO () smpGenerateSite si onionHost path = - Web.generateSite (serverInformation si onionHost) smpLinkPages path + Web.generateSite embeddedContent (serverInformation si onionHost) smpLinkPages path smpLinkPages :: [String] smpLinkPages = ["contact", "invitation", "a", "c", "g", "r", "i"] serverInformation :: ServerInformation -> Maybe TransportHost -> ByteString -serverInformation ServerInformation {config, information} onionHost = render E.indexHtml substs +serverInformation ServerInformation {config, information} onionHost = render (Web.indexHtml embeddedContent) substs where substs = [("smpConfig", Just "y"), ("xftpConfig", Nothing)] <> substConfig <> serverInfoSubsts simplexmqSource information <> [("onionHost", strEncode <$> onionHost), ("iniFileName", Just "smp-server.ini")] substConfig = diff --git a/apps/xftp-server/XFTPWeb.hs b/apps/xftp-server/XFTPWeb.hs index e8ee7040a..dd57d43c0 100644 --- a/apps/xftp-server/XFTPWeb.hs +++ b/apps/xftp-server/XFTPWeb.hs @@ -9,6 +9,7 @@ module XFTPWeb import Data.ByteString (ByteString) import Data.Maybe (isJust) import Data.String (fromString) +import Web.Embedded (embeddedContent) import Simplex.FileTransfer.Server.Env (XFTPServerConfig (..)) import Simplex.Messaging.Encoding.String (strEncode) import Simplex.Messaging.Server.Expiration (ExpirationConfig (..)) @@ -16,15 +17,14 @@ import Simplex.Messaging.Server.Information (ServerPublicInfo) import Simplex.Messaging.Server.Main (simplexmqSource) import qualified Simplex.Messaging.Server.Web as Web import Simplex.Messaging.Server.Web (render, serverInfoSubsts, timedTTLText) -import Simplex.Messaging.Server.Web.Embedded as E import Simplex.Messaging.Transport.Client (TransportHost (..)) xftpGenerateSite :: XFTPServerConfig -> Maybe ServerPublicInfo -> Maybe TransportHost -> FilePath -> IO () xftpGenerateSite cfg info onionHost path = - Web.generateSite (xftpServerInformation cfg info onionHost) [] path + Web.generateSite embeddedContent (xftpServerInformation cfg info onionHost) [] path xftpServerInformation :: XFTPServerConfig -> Maybe ServerPublicInfo -> Maybe TransportHost -> ByteString -xftpServerInformation XFTPServerConfig {fileExpiration, logStatsInterval, allowNewFiles, newFileBasicAuth} information onionHost = render E.indexHtml substs +xftpServerInformation XFTPServerConfig {fileExpiration, logStatsInterval, allowNewFiles, newFileBasicAuth} information onionHost = render (Web.indexHtml embeddedContent) substs where substs = [("smpConfig", Nothing), ("xftpConfig", Just "y")] <> substConfig <> serverInfoSubsts simplexmqSource information <> [("onionHost", strEncode <$> onionHost), ("iniFileName", Just "file-server.ini")] substConfig = diff --git a/simplexmq.cabal b/simplexmq.cabal index 2ae127352..d1c1e03bc 100644 --- a/simplexmq.cabal +++ b/simplexmq.cabal @@ -24,33 +24,33 @@ extra-source-files: CHANGELOG.md cbits/sha512.h cbits/sntrup761.h - src/Simplex/Messaging/Server/Web/index.html - src/Simplex/Messaging/Server/Web/link.html - src/Simplex/Messaging/Server/Web/media/apk_icon.png - src/Simplex/Messaging/Server/Web/media/apple_store.svg - src/Simplex/Messaging/Server/Web/media/contact.js - src/Simplex/Messaging/Server/Web/media/contact_page_mobile.png - src/Simplex/Messaging/Server/Web/media/f_droid.svg - src/Simplex/Messaging/Server/Web/media/favicon.ico - src/Simplex/Messaging/Server/Web/media/GilroyBold.woff2 - src/Simplex/Messaging/Server/Web/media/GilroyLight.woff2 - src/Simplex/Messaging/Server/Web/media/GilroyMedium.woff2 - src/Simplex/Messaging/Server/Web/media/GilroyRegular.woff2 - src/Simplex/Messaging/Server/Web/media/GilroyRegularItalic.woff2 - src/Simplex/Messaging/Server/Web/media/google_play.svg - src/Simplex/Messaging/Server/Web/media/logo-dark.png - src/Simplex/Messaging/Server/Web/media/logo-light.png - src/Simplex/Messaging/Server/Web/media/logo-symbol-dark.svg - src/Simplex/Messaging/Server/Web/media/logo-symbol-light.svg - src/Simplex/Messaging/Server/Web/media/moon.svg - src/Simplex/Messaging/Server/Web/media/qrcode.js - src/Simplex/Messaging/Server/Web/media/script.js - src/Simplex/Messaging/Server/Web/media/style.css - src/Simplex/Messaging/Server/Web/media/sun.svg - src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.css - src/Simplex/Messaging/Server/Web/media/swiper-bundle.min.js - src/Simplex/Messaging/Server/Web/media/tailwind.css - src/Simplex/Messaging/Server/Web/media/testflight.png + apps/common/Web/static/index.html + apps/common/Web/static/link.html + apps/common/Web/static/media/apk_icon.png + apps/common/Web/static/media/apple_store.svg + apps/common/Web/static/media/contact.js + apps/common/Web/static/media/contact_page_mobile.png + apps/common/Web/static/media/f_droid.svg + apps/common/Web/static/media/favicon.ico + apps/common/Web/static/media/GilroyBold.woff2 + apps/common/Web/static/media/GilroyLight.woff2 + apps/common/Web/static/media/GilroyMedium.woff2 + apps/common/Web/static/media/GilroyRegular.woff2 + apps/common/Web/static/media/GilroyRegularItalic.woff2 + apps/common/Web/static/media/google_play.svg + apps/common/Web/static/media/logo-dark.png + apps/common/Web/static/media/logo-light.png + apps/common/Web/static/media/logo-symbol-dark.svg + apps/common/Web/static/media/logo-symbol-light.svg + apps/common/Web/static/media/moon.svg + apps/common/Web/static/media/qrcode.js + apps/common/Web/static/media/script.js + apps/common/Web/static/media/style.css + apps/common/Web/static/media/sun.svg + apps/common/Web/static/media/swiper-bundle.min.css + apps/common/Web/static/media/swiper-bundle.min.js + apps/common/Web/static/media/tailwind.css + apps/common/Web/static/media/testflight.png flag swift description: Enable swift JSON format @@ -249,7 +249,6 @@ library Simplex.Messaging.Server.Main.GitCommit Simplex.Messaging.Server.Main.Init Simplex.Messaging.Server.Web - Simplex.Messaging.Server.Web.Embedded Simplex.Messaging.Server.MsgStore Simplex.Messaging.Server.MsgStore.Journal Simplex.Messaging.Server.MsgStore.Journal.SharedLock @@ -345,7 +344,6 @@ library if !flag(client_library) build-depends: case-insensitive ==1.2.* - , file-embed >=0.0.10 && <0.1 , hashable ==1.4.* , ini ==0.4.1 , optparse-applicative >=0.15 && <0.17 @@ -412,15 +410,18 @@ executable smp-server main-is: Main.hs other-modules: SMPWeb + Web.Embedded Paths_simplexmq hs-source-dirs: apps/smp-server + apps/common default-extensions: StrictData ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=incomplete-uni-patterns -Werror=missing-methods -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -O2 -threaded -rtsopts build-depends: base , bytestring + , file-embed >=0.0.10 && <0.1 , simple-logger , simplexmq , text @@ -448,15 +449,18 @@ executable xftp-server main-is: Main.hs other-modules: XFTPWeb + Web.Embedded Paths_simplexmq hs-source-dirs: apps/xftp-server + apps/common default-extensions: StrictData ghc-options: -Weverything -Wno-missing-exported-signatures -Wno-missing-import-lists -Wno-missed-specialisations -Wno-all-missed-specialisations -Wno-unsafe -Wno-safe -Wno-missing-local-signatures -Wno-missing-kind-signatures -Wno-missing-deriving-strategies -Wno-monomorphism-restriction -Wno-prepositive-qualified-module -Wno-implicit-prelude -Wno-missing-safe-haskell-mode -Wno-missing-export-lists -Wno-partial-fields -Wcompat -Werror=incomplete-record-updates -Werror=incomplete-patterns -Werror=incomplete-uni-patterns -Werror=missing-methods -Werror=tabs -Wredundant-constraints -Wincomplete-record-updates -Wunused-type-patterns -O2 -threaded -rtsopts build-depends: base , bytestring + , file-embed >=0.0.10 && <0.1 , simple-logger , simplexmq default-language: Haskell2010 @@ -502,6 +506,7 @@ test-suite simplexmq-test XFTPWebTests SMPWeb XFTPWeb + Web.Embedded Paths_simplexmq if flag(client_postgres) other-modules: @@ -522,6 +527,7 @@ test-suite simplexmq-test tests apps/smp-server apps/xftp-server + apps/common default-extensions: StrictData -- add -fhpc to ghc-options to run tests with coverage @@ -539,6 +545,7 @@ test-suite simplexmq-test , crypton-x509-store , crypton-x509-validation , directory + , file-embed >=0.0.10 && <0.1 , filepath , generic-random ==1.5.* , hashable diff --git a/src/Simplex/Messaging/Parsers.hs b/src/Simplex/Messaging/Parsers.hs index 7acbec743..c138cb8aa 100644 --- a/src/Simplex/Messaging/Parsers.hs +++ b/src/Simplex/Messaging/Parsers.hs @@ -18,6 +18,7 @@ module Simplex.Messaging.Parsers sumTypeJSON, taggedObjectJSON, singleFieldJSON, + singleFieldJSON_, defaultJSON, textP, pattern SingleFieldJSONTag, diff --git a/src/Simplex/Messaging/Server/Web.hs b/src/Simplex/Messaging/Server/Web.hs index 23a534429..1f4430af7 100644 --- a/src/Simplex/Messaging/Server/Web.hs +++ b/src/Simplex/Messaging/Server/Web.hs @@ -6,6 +6,7 @@ module Simplex.Messaging.Server.Web ( EmbeddedWebParams (..), WebHttpsParams (..), + EmbeddedContent (..), serveStaticFiles, attachStaticFiles, serveStaticPageH2, @@ -41,7 +42,6 @@ import Simplex.Messaging.Encoding.String (strEncode) import Simplex.Messaging.Server (AttachHTTP) import Simplex.Messaging.Server.CLI (simplexmqCommit) import Simplex.Messaging.Server.Information -import Simplex.Messaging.Server.Web.Embedded as E import Simplex.Messaging.Transport (simplexMQVersion) import Simplex.Messaging.Util (ifM, tshow) import System.Directory (canonicalizePath, createDirectoryIfMissing, doesFileExist) @@ -62,6 +62,13 @@ data WebHttpsParams = WebHttpsParams key :: FilePath } +data EmbeddedContent = EmbeddedContent + { indexHtml :: ByteString, + linkHtml :: ByteString, + mediaContent :: [(FilePath, ByteString)], + wellKnown :: [(FilePath, ByteString)] + } + serveStaticFiles :: EmbeddedWebParams -> IO () serveStaticFiles EmbeddedWebParams {webStaticPath, webHttpPort, webHttpsParams} = do forM_ webHttpPort $ \port -> flip forkFinally (\e -> logError $ "HTTP server crashed: " <> tshow e) $ do @@ -118,14 +125,14 @@ staticFiles root = S.staticApp settings . changeWellKnownPath _ -> req pfxLen = B.length "/.well-known/" -generateSite :: ByteString -> [String] -> FilePath -> IO () -generateSite indexContent linkPages sitePath = do +generateSite :: EmbeddedContent -> ByteString -> [String] -> FilePath -> IO () +generateSite embedded indexContent linkPages sitePath = do createDirectoryIfMissing True sitePath B.writeFile (sitePath "index.html") indexContent - copyDir "media" E.mediaContent + copyDir "media" $ mediaContent embedded -- `.well-known` path is re-written in changeWellKnownPath, -- staticApp does not allow hidden folders. - copyDir "well-known" E.wellKnown + copyDir "well-known" $ wellKnown embedded forM_ linkPages createLinkPage logInfo $ "Generated static site contents at " <> tshow sitePath where @@ -134,7 +141,7 @@ generateSite indexContent linkPages sitePath = do forM_ content $ \(path, s) -> B.writeFile (sitePath dir path) s createLinkPage path = do createDirectoryIfMissing True $ sitePath path - B.writeFile (sitePath path "index.html") E.linkHtml + B.writeFile (sitePath path "index.html") $ linkHtml embedded -- | Serve static files via HTTP/2 directly (without WAI). -- Path traversal protection: resolved path must stay under canonicalRoot. diff --git a/src/Simplex/Messaging/Server/Web/Embedded.hs b/src/Simplex/Messaging/Server/Web/Embedded.hs deleted file mode 100644 index 7345829cc..000000000 --- a/src/Simplex/Messaging/Server/Web/Embedded.hs +++ /dev/null @@ -1,18 +0,0 @@ -{-# LANGUAGE TemplateHaskell #-} - -module Simplex.Messaging.Server.Web.Embedded where - -import Data.ByteString (ByteString) -import Data.FileEmbed (embedDir, embedFile) - -indexHtml :: ByteString -indexHtml = $(embedFile "src/Simplex/Messaging/Server/Web/index.html") - -linkHtml :: ByteString -linkHtml = $(embedFile "src/Simplex/Messaging/Server/Web/link.html") - -mediaContent :: [(FilePath, ByteString)] -mediaContent = $(embedDir "src/Simplex/Messaging/Server/Web/media/") - -wellKnown :: [(FilePath, ByteString)] -wellKnown = $(embedDir "src/Simplex/Messaging/Server/Web/.well-known/") diff --git a/xftp-web/package.json b/xftp-web/package.json index 7b57e2ad5..f294c9079 100644 --- a/xftp-web/package.json +++ b/xftp-web/package.json @@ -1,6 +1,6 @@ { "name": "@simplex-chat/xftp-web", - "version": "0.1.0", + "version": "0.2.0", "description": "XFTP file transfer protocol client for web/browser environments", "license": "AGPL-3.0-only", "repository": { diff --git a/xftp-web/src/protocol/address.ts b/xftp-web/src/protocol/address.ts index a4d4c05f6..e3eb27fd8 100644 --- a/xftp-web/src/protocol/address.ts +++ b/xftp-web/src/protocol/address.ts @@ -52,3 +52,23 @@ export function parseXFTPServer(address: string): XFTPServer { export function formatXFTPServer(srv: XFTPServer): string { return "xftp://" + base64urlEncode(srv.keyHash) + "@" + srv.host + ":" + srv.port } + +// Extract unique XFTP servers referenced in a file description's chunk replicas. +export function getDescriptionServers(fd: {chunks: {replicas: {server: string}[]}[]}): XFTPServer[] { + const seen = new Set() + const servers: XFTPServer[] = [] + for (const chunk of fd.chunks) { + for (const replica of chunk.replicas) { + if (!seen.has(replica.server)) { + seen.add(replica.server) + servers.push(parseXFTPServer(replica.server)) + } + } + } + return servers +} + +// Build an HTTPS origin from an XFTP server address. +export function serverOrigin(server: XFTPServer): string { + return server.port === "443" ? `https://${server.host}` : `https://${server.host}:${server.port}` +} diff --git a/xftp-web/vite.config.ts b/xftp-web/vite.config.ts index 694f1a949..4781a1957 100644 --- a/xftp-web/vite.config.ts +++ b/xftp-web/vite.config.ts @@ -75,7 +75,7 @@ export default defineConfig(({mode}) => { servers = ['xftp://fp@localhost:443'] } else { // In production mode, use the preset servers - servers = [...presets.simplex, ...presets.flux] + servers = [...presets.simplex] define['__XFTP_SERVERS__'] = JSON.stringify(servers) define['__XFTP_PROXY_PORT__'] = JSON.stringify(null) } @@ -94,6 +94,7 @@ export default defineConfig(({mode}) => { outDir: resolve(__dirname, 'dist-web'), emptyOutDir: true, target: 'esnext', + minify: false, chunkSizeWarningLimit: 1200, rollupOptions: { external: ['node:http2', 'url'], diff --git a/xftp-web/web/download.ts b/xftp-web/web/download.ts index 949983659..35e09d701 100644 --- a/xftp-web/web/download.ts +++ b/xftp-web/web/download.ts @@ -5,6 +5,7 @@ import { newXFTPAgent, closeXFTPAgent, decodeDescriptionURI, downloadFileRaw } from '../src/agent.js' +import {getDescriptionServers} from '../src/protocol/address.js' import {XFTPPermanentError} from '../src/client.js' const DECRYPT_WEIGHT = 0.15 @@ -20,6 +21,8 @@ export function initDownload(app: HTMLElement, hash: string) { return } + const wrongServer = !getDescriptionServers(fd).map(s => s.host).includes(window.location.hostname) + const size = fd.redirect ? fd.redirect.size : fd.size app.innerHTML = `
@@ -62,6 +65,11 @@ export function initDownload(app: HTMLElement, hash: string) { showStage(errorStage) } + if (wrongServer) { + readyStage.innerHTML = `

${t('wrongServer', 'This file is not hosted on this server.')}

` + return + } + dlBtn.addEventListener('click', startDownload) retryBtn.addEventListener('click', () => showStage(readyStage)) diff --git a/xftp-web/web/upload.ts b/xftp-web/web/upload.ts index a3a60cdca..78906bb35 100644 --- a/xftp-web/web/upload.ts +++ b/xftp-web/web/upload.ts @@ -6,6 +6,7 @@ import { newXFTPAgent, closeXFTPAgent, uploadFile, encodeDescriptionURI, type EncryptedFileMetadata } from '../src/agent.js' +import {getDescriptionServers, serverOrigin} from '../src/protocol/address.js' import {XFTPPermanentError} from '../src/client.js' const MAX_SIZE = 100 * 1024 * 1024 @@ -170,7 +171,11 @@ export function initUpload(app: HTMLElement) { }) if (aborted) return - const url = window.location.origin + window.location.pathname + '#' + result.uri + const descServers = getDescriptionServers(result.rcvDescription) + const origin = descServers.length > 0 + ? serverOrigin(descServers[0]) + : window.location.origin + const url = origin + window.location.pathname + '#' + result.uri shareLink.value = url showStage(completeStage) app.dispatchEvent(new CustomEvent('xftp:upload-complete', {detail: {url}, bubbles: true}))