Generate SSD remote URL validation from typed Jerboa

ober

80aa1bb679ee3c42bf60d480e6d9ff705c8393b6

diff --git a/templates/ssd-review.ss b/templates/ssd-review.ss
index 953c054..130b813 100644
--- a/templates/ssd-review.ss
+++ b/templates/ssd-review.ss
@@ -15546,7 +15546,8 @@
                 truthStoreStorageSummaryLocal
                 truthStoreStorageStatsLocal
                 truthStoreEnsureStorageCapacityLocal
-                truthStoreLoadRemoteConfigLocal)
+                truthStoreLoadRemoteConfigLocal
+                truthStoreRemoteUrlLocal)
         (type Context)
         (type Exception)
         (type File)
@@ -15648,6 +15649,8 @@
         (extern (truthStoreUrlRef
                   (url : URL)) : (Nullable String)
           (kotlin-member-get ref))
+        (extern (truthStoreUrlText (url : URL)) : String
+          (kotlin-member-call toString))
         (extern (truthStoreMessageDigestGetInstance
                   (algorithm : String)) : MessageDigest
           (kotlin-call MessageDigest getInstance))
@@ -15948,7 +15951,48 @@
                           pin)
                         "SPKI pin requires HTTPS")
                       (nullable-some
-                        (make-RemoteConfig url pin token)))))))))))
+                        (make-RemoteConfig url pin token)))))))))
+        (def (truthStoreRemoteConfigOrThrow
+               (config : (Nullable RemoteConfig))) : RemoteConfig
+          (if (remoteConfigPresent config)
+            (nullable-get config)
+            (throw
+              (truthStoreIllegalStateException
+                "Remote SSD service is not locally configured")
+              RemoteConfig)))
+        (def (truthStoreRemoteUrlLocal
+               (configValue : (Nullable RemoteConfig))
+               (relative : String)) : URL
+          (begin
+            (truthStoreRequired
+              (remoteRelativePathSafe relative)
+              "Unsafe remote relative path")
+            (let ((config (truthStoreRemoteConfigOrThrow configValue)))
+              (let ((candidate
+                      (truthStoreUrl
+                        (string-append
+                          (string-append
+                            (truthStoreStripTrailingSlashes
+                              (truthStoreUrlText
+                                (RemoteConfig-apiUrl config)))
+                            "/")
+                          relative))))
+                (let ((basePort
+                        (urlEffectivePort (RemoteConfig-apiUrl config)))
+                      (candidatePort (urlEffectivePort candidate)))
+                  (begin
+                    (truthStoreRequired
+                      (remoteOriginMatches
+                        (truthStoreUrlProtocol candidate)
+                        (truthStoreUrlHost candidate)
+                        candidatePort
+                        (truthStoreUrlProtocol
+                          (RemoteConfig-apiUrl config))
+                        (truthStoreUrlHost
+                          (RemoteConfig-apiUrl config))
+                        basePort)
+                      "Remote URL escaped configured HTTPS origin")
+                    candidate))))))))
 
     (kotlin-file-lines "com/sfb/ssdreview/TruthStore.kt"
       (
@@ -16126,18 +16170,8 @@
        "    private fun loadRemoteConfig(): RemoteConfig? ="
        "        truthStoreLoadRemoteConfigLocal(context)"
        ""
-       "    private fun remoteUrl(relative: String): URL {"
-       "        require(remoteRelativePathSafe(relative))"
-       "        if (!remoteConfigPresent(remoteConfig)) throw IllegalStateException(\"Remote SSD service is not locally configured\")"
-       "        val config = checkNotNull(remoteConfig)"
-       "        val candidate = URL(config.apiUrl.toString().trimEnd('/') + \"/\" + relative)"
-       "        val basePort = urlEffectivePort(config.apiUrl)"
-       "        val candidatePort = urlEffectivePort(candidate)"
-       "        require(remoteOriginMatches(candidate.protocol, candidate.host, candidatePort, config.apiUrl.protocol, config.apiUrl.host, basePort)) {"
-       "            \"Remote URL escaped configured HTTPS origin\""
-       "        }"
-       "        return candidate"
-       "    }"
+       "    private fun remoteUrl(relative: String): URL ="
+       "        truthStoreRemoteUrlLocal(remoteConfig, relative)"
        ""
        "    private fun openPinnedConnection("
        "        relative: String,"