gitoriaLog in with ident

gitoria

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commit4a2d71254a2d7125initial commitmre4a2d7125/sshgate.hl

2.6 KB

  1. // sshgate.hl — WHAT THE SSHD CONTAINER ASKS THIS APP (ticket gitoria#7; docker/sshd). Two internal function routes, only for the
  2. // container: every request must carry the shared secret (`X-Gitoria-Secret` = GITORIA_SSH_SECRET); without the secret set they
  3. // do not exist (404), and a request that came through the public proxy (it carries X-Forwarded-For / X-Real-IP) is refused.
  4. // GET /__git/keys?type=<ssh-ed25519>&key=<base64> sshd AuthorizedKeysCommand: the authorized_keys line for a known key
  5. // (`restrict,command="gitoria-shell <user id>" <type> <key>`), empty for an unknown one
  6. // GET /__git/access?user=<id>&slug=<slug>&write=0|1 gitoria-shell before it starts git: `ok` or 403. Read = every repo (public);
  7. // write = the repo's owner only — the same rule as the token on HTTPS (transport.hl)
  8. import { Response } from 'hl:http1'
  9. import { slugError, repoBySlug } from './repos.hl'
  10. import { userRecord } from './users.hl'
  11. import { sshSecret, sshEnabled, userOfKey } from './sshkeys.hl'
  12. static NL = "
  13. "
  14. static reply = (status, text) => {
  15. return new Response(text, { status = status headers = { 'Content-Type' = 'text/plain; charset=utf-8' 'Cache-Control' = 'no-store' } })
  16. }
  17. // null when the caller may ask, else the refusing answer
  18. static guard = (req) => {
  19. if (!sshEnabled) { return reply(404, 'not found' + NL) }
  20. if (req.method != 'GET') { return reply(405, 'GET only' + NL) }
  21. if (req.headers['x-forwarded-for'] != null || req.headers['x-real-ip'] != null) { return reply(403, 'internal only' + NL) }
  22. let given = req.headers['x-gitoria-secret']
  23. if (given == null || hlTypeName(given) != 'String' || given != sshSecret) { return reply(403, 'wrong secret' + NL) }
  24. return null
  25. }
  26. static gitKeys = (route, req) => {
  27. let no = guard(req)
  28. if (no != null) { return no }
  29. let q = req.query != null ? req.query : {}
  30. let userId = userOfKey(q.type, q.key)
  31. if (userId == null || userRecord(userId) == null) { return reply(200, '') }
  32. return reply(200, 'restrict,command="/usr/local/bin/gitoria-shell ' + userId + '" ' + q.type + ' ' + q.key + NL)
  33. }
  34. static gitAccess = (route, req) => {
  35. let no = guard(req)
  36. if (no != null) { return no }
  37. let q = req.query != null ? req.query : {}
  38. let slug = q.slug
  39. if (slug == null || hlTypeName(slug) != 'String' || slugError(slug) != null) { return reply(404, 'no such repository' + NL) }
  40. let repo = repoBySlug(slug)
  41. if (repo == null) { return reply(404, 'no such repository' + NL) }
  42. if (q.write == '1') {
  43. if (userRecord(q.user) == null || repo.owner != q.user) { return reply(403, 'only the owner of this repository can push to it' + NL) }
  44. }
  45. return reply(200, 'ok' + NL)
  46. }

Branches

Latest commits

  • 4a2d7125initial commitmre