~jan0sch/smederee

Showing details for patch 3737a2326fa5bc71cc625edb59166827df10965b.
2022-09-12 (Mon), 7:21 PM - Jens Grassel - 3737a2326fa5bc71cc625edb59166827df10965b

SSH: Experimental pull and push support.

- start ssh server if enabled
- pull works
- push works but hangs after completion
Summary of changes
5 files modified with 48 lines added and 14 lines removed
  • modules/hub/src/main/scala/de/smederee/hub/HubServer.scala with 19 added and 2 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala with 13 added and 1 removed lines
  • modules/hub/src/main/scala/de/smederee/hub/config/SmedereeHubConfig.scala with 8 added and 3 removed lines
  • modules/hub/src/main/scala/de/smederee/ssh/DarcsSshCommand.scala with 6 added and 6 removed lines
  • modules/hub/src/main/twirl/de/smederee/hub/views/showRepositoryOverview.scala.html with 2 added and 2 removed lines
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/config/SmedereeHubConfig.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/config/SmedereeHubConfig.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/config/SmedereeHubConfig.scala	2025-02-02 10:09:53.542974214 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/config/SmedereeHubConfig.scala	2025-02-02 10:09:53.546974223 +0000
@@ -25,6 +25,7 @@
 import com.comcast.ip4s.{ Host, Port }
 import de.smederee.email._
 import de.smederee.security._
+import de.smederee.ssh._
 import org.http4s.Uri
 import org.slf4j.LoggerFactory
 import pureconfig._
@@ -279,6 +280,8 @@
   *   it runs behind a reverse proxy.
   * @param signup
   *   The configuration for the signup / registration feature.
+  * @param ssh
+  *   Settings for the embedded SSH server component.
   */
 final case class ServiceConfig(
     host: Host,
@@ -288,7 +291,8 @@
     darcs: DarcsConfiguration,
     email: EmailMiddlewareConfiguration,
     external: ExternalLinkConfig,
-    signup: SignupConfiguration
+    signup: SignupConfiguration,
+    ssh: SshServerConfiguration
 )
 
 object ServiceConfig {
@@ -313,7 +317,7 @@
     )
 
   given ConfigReader[ServiceConfig] =
-    ConfigReader.forProduct8(
+    ConfigReader.forProduct9(
       "host",
       "port",
       AuthenticationConfiguration.parentKey.toString,
@@ -321,7 +325,8 @@
       DarcsConfiguration.parentKey.toString,
       "email",
       ExternalLinkConfig.parentKey.toString,
-      SignupConfiguration.parentKey.toString
+      SignupConfiguration.parentKey.toString,
+      SshServerConfiguration.parentKey.toString
     )(ServiceConfig.apply)
 }
 
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/HubServer.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/HubServer.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/HubServer.scala	2025-02-02 10:09:53.542974214 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/HubServer.scala	2025-02-02 10:09:53.546974223 +0000
@@ -29,6 +29,7 @@
 import de.smederee.email.SimpleJavaMailMiddleware
 import de.smederee.hub.config._
 import de.smederee.security._
+import de.smederee.ssh._
 import doobie._
 import org.http4s._
 import org.http4s.dsl.io._
@@ -121,6 +122,7 @@
         configuration.service.darcs,
         darcsWrapper,
         configuration.service.external,
+        configuration.service.ssh,
         vcsMetadataRepo
       )
       protectedRoutesWithFallThrough = authenticationWithFallThrough(
@@ -130,15 +132,30 @@
         Constants.assetsPath.path.toAbsolute.toString -> assetsRoutes,
         "/" -> (protectedRoutesWithFallThrough <+> authenticationRoutes.routes <+> signUpRoutes.routes <+> vcsRepoRoutes.routes <+> landingPages.routes)
       ).orNotFound
+      // Create our ssh server fiber (or a dummy one if disabled).
+      sshServerProvider = configuration.service.ssh.enabled match {
+        case false => None
+        case true  => Option(new SshServerProvider(configuration.service.darcs, configuration.service.ssh))
+      }
+      sshServer = sshServerProvider.fold(IO.unit.as(ExitCode.Success))(
+        _.run().use(server =>
+          IO(log.info(s"SSH-Server started at ${server.getHost()}:${server.getPort()}.")) >> IO.never.as(
+            ExitCode.Success
+          )
+        )
+      )
+      // Create our webserver fiber.
       resource = EmberServerBuilder
         .default[IO]
         .withHost(configuration.service.host)
         .withPort(configuration.service.port)
         .withHttpApp(globalRoutes)
         .build
-      fiber <- resource.use(server =>
+      webServer = resource.use(server =>
         IO(log.info("Server started at {}", server.address)) >> IO.never.as(ExitCode.Success)
       )
-    } yield fiber
+      executeFibers <- (webServer, sshServer).parTupled // We run both fibers.
+      (exitCode, _) = executeFibers
+    } yield exitCode
   }
 }
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-02-02 10:09:53.542974214 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/VcsRepositoryRoutes.scala	2025-02-02 10:09:53.546974223 +0000
@@ -29,6 +29,7 @@
 import de.smederee.hub.config._
 import de.smederee.hub.forms.types.FormErrors
 import de.smederee.html.LinkTools._
+import de.smederee.ssh._
 import org.commonmark.parser.Parser
 import org.commonmark.renderer.html.HtmlRenderer
 import org.http4s._
@@ -48,6 +49,8 @@
   *   A class providing darcs VCS operations.
   * @param linkConfig
   *   The configuration needed to build correct links which are working from the outside.
+  * @param sshConfig
+  *   Settings for the embedded SSH server component.
   * @param vcsMetadataRepo
   *   A repository for handling database operations regarding our vcs repositories and their metadata.
   * @tparam F
@@ -57,6 +60,7 @@
     darcsConfig: DarcsConfiguration,
     darcs: DarcsCommands[F],
     linkConfig: ExternalLinkConfig,
+    sshConfig: SshServerConfiguration,
     vcsMetadataRepo: VcsMetadataRepository[F]
 ) extends Http4sDsl[F] {
   private val log = LoggerFactory.getLogger(getClass)
@@ -168,6 +172,13 @@
           )
         )
       )
+      sshUri <- sshConfig.enabled match {
+        case false => Sync[F].pure(None)
+        case true =>
+          Sync[F].delay(
+            s"SSH_PORT=${sshConfig.port.toString} darcs clone darcs@${linkConfig.host.toString}:${repositoryOwnerName.toString}/${repositoryName.toString}".some
+          )
+      }
       directory <- Sync[F].delay(
         os.Path(
           Paths.get(
@@ -208,7 +219,8 @@
               repo,
               vcsRepositoryHistory = log.stdout.toList.mkString("\n").some,
               vcsRepositoryReadme = readme,
-              vcsRepositoryReadmeFilename = readmeName
+              vcsRepositoryReadmeFilename = readmeName,
+              vcsRepositorySshUri = sshUri
             )
           )
       }
diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/ssh/DarcsSshCommand.scala new-smederee/modules/hub/src/main/scala/de/smederee/ssh/DarcsSshCommand.scala
--- old-smederee/modules/hub/src/main/scala/de/smederee/ssh/DarcsSshCommand.scala	2025-02-02 10:09:53.542974214 +0000
+++ new-smederee/modules/hub/src/main/scala/de/smederee/ssh/DarcsSshCommand.scala	2025-02-02 10:09:53.546974223 +0000
@@ -72,11 +72,11 @@
     val repoDir = Paths.get(owner.toString, repository.toString)
     val cmd = os.proc(
       darcsConfiguration.executable.toString,
-      List("apply", "--all", "--debug", "--repodir", repoDir.toString)
+      List("apply", "--all", "--repodir", repoDir.toString)
     )
-    cmd.call(
+    cmd.spawn(
       cwd = os.Path(darcsConfiguration.repositoriesDirectory.toPath),
-      stdin = this.stdin,
+      stdin = os.ProcessInput.makeSourceInput(this.stdin),
       stdout = os.ProcessOutput((bytes, _) => this.stdout.write(bytes)),
       stderr = os.ProcessOutput((bytes, _) => this.stderr.write(bytes))
     )
@@ -107,9 +107,9 @@
       darcsConfiguration.executable.toString,
       List("transfer-mode", "--repodir", repoDir.toString)
     )
-    cmd.call(
+    cmd.spawn(
       cwd = os.Path(darcsConfiguration.repositoriesDirectory.toPath),
-      stdin = this.stdin,
+      stdin = os.ProcessInput.makeSourceInput(this.stdin),
       stdout = os.ProcessOutput((bytes, _) => this.stdout.write(bytes)),
       stderr = os.ProcessOutput((bytes, _) => this.stderr.write(bytes))
     )
@@ -127,7 +127,7 @@
   private val log = LoggerFactory.getLogger(classOf[DarcsSshCommandFactory])
 
   override def createCommand(channel: ChannelSession, command: String): Command = {
-    log.warn(s"Requested SSH command: $command")
+    log.debug(s"Requested SSH command: $command")
 
     command match {
       case DarcsSshCommandFactory.FilterDarcsApplyCommand("apply", _, _, "--repodir", owner, repository) =>
diff -rN -u old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/showRepositoryOverview.scala.html new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/showRepositoryOverview.scala.html
--- old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/showRepositoryOverview.scala.html	2025-02-02 10:09:53.546974223 +0000
+++ new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/showRepositoryOverview.scala.html	2025-02-02 10:09:53.546974223 +0000
@@ -1,4 +1,4 @@
-@(baseUri: Uri, lang: LanguageCode = LanguageCode("en"))(actionBaseUri: Uri, csrf: Option[CsrfToken] = None, title: Option[String] = None, user: Option[Account])(vcsRepository: VcsRepository, vcsRepositoryHistory: Option[String], vcsRepositoryReadme: Option[String] = None, vcsRepositoryReadmeFilename: Option[String] = None)
+@(baseUri: Uri, lang: LanguageCode = LanguageCode("en"))(actionBaseUri: Uri, csrf: Option[CsrfToken] = None, title: Option[String] = None, user: Option[Account])(vcsRepository: VcsRepository, vcsRepositoryHistory: Option[String], vcsRepositoryReadme: Option[String] = None, vcsRepositoryReadmeFilename: Option[String] = None, vcsRepositorySshUri: Option[String] = None)
 @main(baseUri, lang)()(csrf, title, user) {
 @defining(lang.toLocale) { implicit locale =>
   <div class="content">
@@ -47,7 +47,7 @@
             <dd>
               <form class="pure-form">
                 <fieldset>
-                  <input class="pure-input-1" id="clone-readwrite" type="text" value="NOT YET IMPLEMENTED!" readonly="readonly"/>
+                  <input class="pure-input-1" id="clone-readwrite" type="text" value="@{vcsRepositorySshUri.getOrElse("NOT YET IMPLEMENTED!")}" readonly="readonly"/>
                 </fieldset>
               </form>
             </dd>