~jan0sch/smederee
Showing details for patch 4d12aa1b8e9a98244da555a20e975421606c096c.
diff -rN -u old-smederee/modules/hub/src/main/resources/assets/css/main.css new-smederee/modules/hub/src/main/resources/assets/css/main.css --- old-smederee/modules/hub/src/main/resources/assets/css/main.css 2025-02-01 21:54:00.179323407 +0000 +++ new-smederee/modules/hub/src/main/resources/assets/css/main.css 2025-02-01 21:54:00.183323417 +0000 @@ -13,10 +13,18 @@ padding: 0px 10px; } +.ssh-key-item { + padding: 10px 5px 10px 5px; +} + .ssh-key-item-icon { margin-right: 5px; } +.ssh-key-comment { + word-wrap: break-word; +} + .validate-email-form { border: 1px solid black; padding: 0px 10px; diff -rN -u old-smederee/modules/hub/src/main/resources/messages_en.properties new-smederee/modules/hub/src/main/resources/messages_en.properties --- old-smederee/modules/hub/src/main/resources/messages_en.properties 2025-02-01 21:54:00.179323407 +0000 +++ new-smederee/modules/hub/src/main/resources/messages_en.properties 2025-02-01 21:54:00.183323417 +0000 @@ -69,6 +69,8 @@ form.ssh.add.key.placeholder=The content of your key file (usually located in ~/.ssh/id_rsa.pub) starting with ssh-rsa or ssh-ed25519. form.ssh.add.name=Name form.ssh.add.name.help=If left empty it will be taken from the ssh key comment (if that exists). +form.ssh.delete.button.submit=Delete key +form.ssh.delete.i-am-sure=Yes, I'm sure! # Global / generic translations global.alpha=Alpha Notice @@ -189,6 +191,7 @@ user.settings.ssh.description=Here you can manage your SSH keys. user.settings.ssh.key.created=Uploaded on {0,date,yyyy-MM-dd (E)} user.settings.ssh.key.last-used=Last used on {0,date,yyyy-MM-dd (E)} +user.settings.ssh.list.title=Manage your existing ssh keys. +user.settings.ssh.list.empty=You haven''t uploaded any ssh keys yet. user.settings.ssh.title=SSH-Keys user.settings.title=Settings - diff -rN -u old-smederee/modules/hub/src/main/scala/de/smederee/hub/AccountManagementRoutes.scala new-smederee/modules/hub/src/main/scala/de/smederee/hub/AccountManagementRoutes.scala --- old-smederee/modules/hub/src/main/scala/de/smederee/hub/AccountManagementRoutes.scala 2025-02-01 21:54:00.179323407 +0000 +++ new-smederee/modules/hub/src/main/scala/de/smederee/hub/AccountManagementRoutes.scala 2025-02-01 21:54:00.183323417 +0000 @@ -40,6 +40,8 @@ import org.http4s.twirl.TwirlInstances._ import org.slf4j.LoggerFactory +import scala.util.Try + /** Routes for user account self management which should provide every functionality needed by users to manage their * account. * @@ -261,6 +263,40 @@ } } + private val deleteSshKey: AuthedRoutes[Account, F] = AuthedRoutes.of { + case ar @ POST -> Root / "user" / "settings" / "ssh" / "delete" as user => + ar.req.decodeStrict[F, UrlForm] { urlForm => + for { + csrf <- Sync[F].delay(ar.req.getCsrfToken) + formData <- Sync[F].delay { + urlForm.values.map { t => + val (key, values) = t + ( + key, + values.headOption.getOrElse("") + ) // Pick the first value (a field might get submitted multiple times)! + } + } + actionBaseUri <- Sync[F].delay(configuration.external.createFullUri(uri"user/settings")) + userIsSure <- Sync[F].delay(formData.get("i-am-sure").exists(_ === "yes")) + sshKeyId <- Sync[F].delay { + Try(formData.get("ssh-key-id").map(UUID.fromString)) match { + case scala.util.Failure(error) => + log.error("Error while parsing ssh key id upon key delete request.", error) + None + case scala.util.Success(Some(keyId)) => Option(keyId) + case _ => None + } + } + _ <- userIsSure match { + case false => Sync[F].pure(None) + case true => sshKeyId.traverse(id => accountManagementRepo.deleteSshKey(id, user.uid)) + } + resp <- SeeOther(Location(actionBaseUri.addSegment("ssh"))) + } yield resp + } + } + private val sendValidationEmail: AuthedRoutes[Account, F] = AuthedRoutes.of { case ar @ POST -> Root / "user" / "settings" / "email" / "validate" as user => for { @@ -334,7 +370,7 @@ } val protectedRoutes = - addSshKey <+> deleteAccount <+> sendValidationEmail <+> showAccountSettings <+> showAccountSshSettings + addSshKey <+> deleteAccount <+> deleteSshKey <+> sendValidationEmail <+> showAccountSettings <+> showAccountSshSettings val routes = validateEmailAddress diff -rN -u old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/account/sshSettings.scala.html new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/account/sshSettings.scala.html --- old-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/account/sshSettings.scala.html 2025-02-01 21:54:00.179323407 +0000 +++ new-smederee/modules/hub/src/main/twirl/de/smederee/hub/views/account/sshSettings.scala.html 2025-02-01 21:54:00.183323417 +0000 @@ -47,7 +47,7 @@ </div> <div class="pure-control-group"> <label for="@{fieldKey}">@Messages("form.ssh.add.key")</label> - <textarea class="pure-input-1" id="@{fieldKey}" name="@{fieldKey}" placeholder="@Messages("form.ssh.add.key.placeholder")" maxlength="4096" rows="8">@{formData.get(fieldKey)}</textarea> + <textarea class="pure-input-1" id="@{fieldKey}" name="@{fieldKey}" placeholder="@Messages("form.ssh.add.key.placeholder")" maxlength="4096" rows="8" required="">@{formData.get(fieldKey)}</textarea> <span class="pure-form-message" id="@{fieldKey}.help"><strong>@Messages("form.ssh.add.key.help")</strong></span> @renderFormErrors(fieldKey, formErrors) </div> @@ -64,21 +64,36 @@ <div class="pure-u-1-1 pure-u-md-1-1"> <div class="l-box"> <div class="ssh-key-list"> - @for(key <- keys) { - <div class="ssh-key-item"> - <div class="ssh-key-item-icon left-floated"> - <i class="fa-solid fa-key fa-3x"></i> - </div> - <div class="ssh-key-item-details"> - <strong>@key.comment</strong> - <pre>SHA256:@key.fingerprint</pre> - <div class="ssh-key-item-timestamps"> - @Messages("user.settings.ssh.key.created", java.util.Date.from(key.createdAt.toInstant)) @key.lastUsedAt.map(timestamp => Messages("user.settings.ssh.key.last-used", java.util.Date.from(timestamp.toInstant))) + <h4>@Messages("user.settings.ssh.list.title")</h4> + @if(keys.size === 0) { + <div class="alert alert-info">@Messages("user.settings.ssh.list.empty")</div> + } else { + @for(key <- keys) { + <div class="ssh-key-item"> + <div class="ssh-key-item-icon left-floated"> + <i class="fa-solid fa-key fa-3x"></i> + </div> + <div class="ssh-key-item-form right-floated pure-u-1-3"> + <form action="@deleteAction" class="pure-form" method="POST" accept-charset="UTF-8"> + <fieldset> + <input type="hidden" id="ssh-key-id-@key.id" name="ssh-key-id" readonly="" value="@key.id"> + <label for="i-am-sure-@key.id"><input id="i-am-sure-@key.id" name="i-am-sure" required="" type="checkbox" value="yes"/> @Messages("form.ssh.delete.i-am-sure")</label> + @csrfToken(csrf) + <button type="submit" class="button-warning pure-button">@Messages("form.ssh.delete.button.submit")</button> + </fieldset> + </form> + </div> + <div class="ssh-key-item-details"> + <div class="ssh-key-comment"><strong>@key.comment</strong></div> + <div class="ssh-key-fingerprint">SHA256:@key.fingerprint</div> + <div class="ssh-key-item-timestamps"> + @Messages("user.settings.ssh.key.created", java.util.Date.from(key.createdAt.toInstant)) @key.lastUsedAt.map(timestamp => Messages("user.settings.ssh.key.last-used", java.util.Date.from(timestamp.toInstant))) + </div> + </div> + <div class="clearfix"></div> </div> - </div> - <div class="clearfix"></div> - </div> - } + } + } </div> </div> </div>