From 37ce109009d0c5928eb8e03394f4c5e2e3141dfa Mon Sep 17 00:00:00 2001 From: Evgeny Date: Fri, 11 Apr 2025 18:30:43 +0100 Subject: [PATCH] smp server: .well-known folder for server pages for SimpleX apps to handle preset server links (#1510) * smp server: .well-known folder for server pages for SimpleX apps to handle preset server links * add short link group path * test --- .../apple-app-site-association/index.json | 49 +++++++++++++++++++ .../static/.well-known/assetlinks.json | 16 ++++++ apps/smp-server/web/Static.hs | 9 +++- apps/smp-server/web/Static/Embedded.hs | 3 ++ tests/AgentTests/ConnectionRequestTests.hs | 10 ++++ 5 files changed, 85 insertions(+), 2 deletions(-) create mode 100644 apps/smp-server/static/.well-known/apple-app-site-association/index.json create mode 100644 apps/smp-server/static/.well-known/assetlinks.json diff --git a/apps/smp-server/static/.well-known/apple-app-site-association/index.json b/apps/smp-server/static/.well-known/apple-app-site-association/index.json new file mode 100644 index 000000000..3b513fe61 --- /dev/null +++ b/apps/smp-server/static/.well-known/apple-app-site-association/index.json @@ -0,0 +1,49 @@ +{ + "applinks": { + "details": [ + { + "appIDs": [ + "5NN7GUYB6T.chat.simplex.app" + ], + "components": [ + { + "/": "/contact/*" + }, + { + "/": "/contact" + }, + { + "/": "/invitation/*" + }, + { + "/": "/invitation" + }, + { + "/": "/a/*" + }, + { + "/": "/a" + }, + { + "/": "/c/*" + }, + { + "/": "/c" + }, + { + "/": "/g/*" + }, + { + "/": "/g" + }, + { + "/": "/i/*" + }, + { + "/": "/i" + } + ] + } + ] + } +} \ No newline at end of file diff --git a/apps/smp-server/static/.well-known/assetlinks.json b/apps/smp-server/static/.well-known/assetlinks.json new file mode 100644 index 000000000..e19f8a4c1 --- /dev/null +++ b/apps/smp-server/static/.well-known/assetlinks.json @@ -0,0 +1,16 @@ +[ + { + "relation": [ + "delegate_permission/common.handle_all_urls" + ], + "target": { + "namespace": "android_app", + "package_name": "chat.simplex.app", + "sha256_cert_fingerprints": [ + "5E:3E:DC:C2:00:FB:A8:D5:F4:88:F3:CA:4C:32:5B:05:78:C5:6A:9C:03:A1:CC:B5:92:9C:D7:5C:7E:57:E2:4D", + "3C:52:C4:FD:3C:AD:1C:07:C9:B0:0A:70:80:E3:58:FA:B9:FE:FC:B8:AF:5A:EC:14:77:65:F1:6D:0F:21:AD:85", + "AE:C1:95:DC:FD:46:14:BD:3A:91:EC:26:D1:D5:14:C8:75:71:C5:CC:8D:CF:48:08:3F:92:83:14:3C:A2:B9:A6" + ] + } + } +] diff --git a/apps/smp-server/web/Static.hs b/apps/smp-server/web/Static.hs index 8d85c4b7f..8a5a31adf 100644 --- a/apps/smp-server/web/Static.hs +++ b/apps/smp-server/web/Static.hs @@ -82,8 +82,8 @@ generateSite :: ServerInformation -> Maybe TransportHost -> FilePath -> IO () generateSite si onionHost sitePath = do createDirectoryIfMissing True sitePath B.writeFile (sitePath "index.html") $ serverInformation si onionHost - createDirectoryIfMissing True $ sitePath "media" - forM_ E.mediaContent $ \(path, bs) -> B.writeFile (sitePath "media" path) bs + copyDir "media" E.mediaContent + copyDir ".well-known" E.wellKnown createLinkPage "contact" createLinkPage "invitation" createLinkPage "a" @@ -91,6 +91,11 @@ generateSite si onionHost sitePath = do createLinkPage "i" logInfo $ "Generated static site contents at " <> tshow sitePath where + copyDir dir content = do + createDirectoryIfMissing True $ sitePath dir + forM_ content $ \(path, s) -> do + createDirectoryIfMissing True $ sitePath dir takeDirectory path + B.writeFile (sitePath dir path) s createLinkPage path = do createDirectoryIfMissing True $ sitePath path B.writeFile (sitePath path "index.html") E.linkHtml diff --git a/apps/smp-server/web/Static/Embedded.hs b/apps/smp-server/web/Static/Embedded.hs index 23698dd6f..c1c4fde2f 100644 --- a/apps/smp-server/web/Static/Embedded.hs +++ b/apps/smp-server/web/Static/Embedded.hs @@ -13,3 +13,6 @@ linkHtml = $(embedFile "apps/smp-server/static/link.html") mediaContent :: [(FilePath, ByteString)] mediaContent = $(embedDir "apps/smp-server/static/media/") + +wellKnown :: [(FilePath, ByteString)] +wellKnown = $(embedDir "apps/smp-server/static/.well-known/") diff --git a/tests/AgentTests/ConnectionRequestTests.hs b/tests/AgentTests/ConnectionRequestTests.hs index d74979434..1782d3ccd 100644 --- a/tests/AgentTests/ConnectionRequestTests.hs +++ b/tests/AgentTests/ConnectionRequestTests.hs @@ -4,6 +4,7 @@ {-# LANGUAGE OverloadedLists #-} {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE PatternSynonyms #-} +{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeApplications #-} {-# OPTIONS_GHC -Wno-orphans #-} {-# OPTIONS_GHC -fno-warn-ambiguous-fields #-} @@ -332,6 +333,15 @@ connectionRequestTests = `shouldBe` contact shortSrv (LinkKey "0123456789abcdef0123456789abcdef") restoreShortLink [srv] (contact srv2 (LinkKey "0123456789abcdef0123456789abcdef")) `shouldBe` contact srv2 (LinkKey "0123456789abcdef0123456789abcdef") + Right (lnk :: ConnShortLink 'CMContact) <- pure $ strDecode "https://localhost/a#4AkRDmhf64tdRlN406g8lJRg5OCmhD6ynIhi6glOcCM?p=7001&c=LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI" + Right (lnk' :: ConnShortLink 'CMContact) <- pure $ strDecode "https://localhost/a#4AkRDmhf64tdRlN406g8lJRg5OCmhD6ynIhi6glOcCM" + let presetSrv :: SMPServer = "smp://LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI=@localhost:7001" + shortenShortLink [presetSrv] lnk `shouldBe` lnk' + restoreShortLink [presetSrv] lnk' `shouldBe` lnk + Right (inv :: ConnShortLink 'CMInvitation) <- pure $ strDecode "https://localhost/i#tnUaHYp8saREmyEHR93SBpl8ySHBchOt/LJ1ZQUzxH9Udb0jw5wmJACv5o6oe8e7BsX_hUCUMTSY?p=7001&c=LcJUMfVhwD8yxjAiSaDzzGF3-kLG4Uh0Fl_ZIjrRwjI" + Right (inv' :: ConnShortLink 'CMInvitation) <- pure $ strDecode "https://localhost/i#tnUaHYp8saREmyEHR93SBpl8ySHBchOt/LJ1ZQUzxH9Udb0jw5wmJACv5o6oe8e7BsX_hUCUMTSY" + shortenShortLink [presetSrv] inv `shouldBe` inv' + restoreShortLink [presetSrv] inv' `shouldBe` inv where smpEncodingTest :: (Encoding a, Eq a, Show a, HasCallStack) => a -> Expectation smpEncodingTest a = smpDecode (smpEncode a) `shouldBe` Right a