Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,20 @@ data class AndroidDownloadedGraphSnapshot(
class AndroidGraphSnapshotException(message: String, cause: Throwable? = null) :
Exception(message, cause)

internal fun resolveSnapshotStreamUrl(metadataUrl: URL, advertisedUrl: String): URL {
val url = URL(metadataUrl, advertisedUrl)
if (metadataUrl.protocol != "https" || url.protocol != "http") return url

// A self-hosted Node server behind a TLS proxy can advertise its HTTP origin.
// The graph's standard stream is served beside its metadata on the proxy.
val stream = URL(metadataUrl, "stream")
val path = url.path
return if (path.endsWith("/snapshot/stream") &&
(path == stream.path || (path.startsWith("/sync/") && stream.path.endsWith(path)))) {
URL(metadataUrl, "stream" + url.query?.let { "?$it" }.orEmpty())
} else url
}

class AndroidGraphSnapshotDownloader {
suspend fun download(
baseUrl: String,
Expand All @@ -30,7 +44,7 @@ class AndroidGraphSnapshotDownloader {
val metadataBody = readText(metadataUrl, accessToken, "Snapshot metadata")
val resolved = shared(callCore, "resolveSnapshotDownload", JSONObject()
.put("metadataBody", metadataBody))
val snapshotUrl = URL(metadataUrl, resolved.getString("downloadURL"))
val snapshotUrl = resolveSnapshotStreamUrl(metadataUrl, resolved.getString("downloadURL"))

val directory = File(workingDirectory)
if (!directory.isDirectory && !directory.mkdirs()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,28 @@ import org.junit.Test
import org.json.JSONObject
import com.sun.net.httpserver.HttpServer
import java.net.InetSocketAddress
import java.net.URL
import java.nio.file.Files

class AndroidGraphSnapshotDownloaderTest {
@Test
fun `downloads the standard stream through the configured HTTPS proxy`() {
val metadata = URL("https://sync.example.test:8443/logseq/sync/graph/snapshot/download")
val url = resolveSnapshotStreamUrl(metadata, "http://backend:8787/sync/graph/snapshot/stream?cursor=42")
assertEquals("https://sync.example.test:8443/logseq/sync/graph/snapshot/stream?cursor=42", url.toString())
}

@Test
fun `respects other download links and direct HTTP servers`() {
val metadata = URL("https://sync.example.test/sync/graph/snapshot/download")
val otherGraph = "http://backend:8787/sync/other/snapshot/stream"
val signedDownload = "https://storage.example.test/graph.snapshot?signature=abc"
val directStream = "http://localhost:8787/sync/graph/snapshot/stream"
assertEquals(otherGraph, resolveSnapshotStreamUrl(metadata, otherGraph).toString())
assertEquals(signedDownload, resolveSnapshotStreamUrl(metadata, signedDownload).toString())
assertEquals(directStream, resolveSnapshotStreamUrl(URL("http://localhost:8787/sync/graph/snapshot/download"), directStream).toString())
}

@Test
fun `downloads the shared snapshot plan and preserves binary bytes`() = runBlocking {
val server = HttpServer.create(InetSocketAddress("127.0.0.1", 0), 0)
Expand Down
Loading