Files
Hammerhead/server.go
T

162 lines
9.0 KiB
Go

package hammerhead
import (
_ "embed"
"net/http"
)
//go:embed web/index.html
var indexHTML []byte
func page(html []byte) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
h := w.Header()
h.Set("Content-Type", "text/html; charset=utf-8")
h.Set("Cache-Control", "no-store")
h.Set("X-Frame-Options", "DENY")
h.Set("X-Content-Type-Options", "nosniff")
h.Set("Referrer-Policy", "no-referrer")
h.Set("Content-Security-Policy", "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'")
w.Write(html)
}
}
// dashboardPaths are the addresses the dashboard shows pages at. They all serve the same app,
// which reads the path to decide what to show. Keep in step with TAB_PATH in web/index.html.
var dashboardPaths = map[string]bool{
"/": true, "/apps": true, "/resources": true, "/sites": true, "/domains": true, "/mail-egress": true,
"/alerts": true, "/access": true, "/logs": true, "/account": true,
"/server/edges": true, "/server/organizations": true, "/server/users": true, "/server/sso": true,
"/server/settings": true, "/server/alerts": true, "/server/audit": true,
}
func isDashboardPath(p string) bool { return dashboardPaths[p] }
func (s *Server) Handler() http.Handler {
mux := http.NewServeMux()
index := page(indexHTML)
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
if !isDashboardPath(r.URL.Path) {
http.NotFound(w, r)
return
}
index(w, r)
})
s.registerAlertRoutes(mux)
mux.HandleFunc("GET /metrics", s.metrics)
// public
mux.HandleFunc("GET /api/public", s.publicInfo)
mux.HandleFunc("POST /api/setup", s.setup)
mux.HandleFunc("POST /api/login", s.login)
mux.HandleFunc("POST /api/login/totp", s.loginTOTP)
mux.HandleFunc("GET /api/invites/{token}", s.inviteInfo)
mux.HandleFunc("POST /api/invites/accept", s.acceptInvite)
mux.HandleFunc("GET /auth/oidc/{id}/start", s.oidcStart)
mux.HandleFunc("GET /auth/oidc/callback", s.oidcCallback)
// visitor login for protected ports
res := page(resourceHTML)
mux.HandleFunc("GET /auth/r/{id}", res)
mux.HandleFunc("GET /auth/r/{id}/info", s.resourceInfo)
mux.HandleFunc("POST /auth/r/{id}/password", s.resourceAuth("password", s.resourcePassword))
mux.HandleFunc("POST /auth/r/{id}/pin", s.resourceAuth("pin", s.resourcePin))
mux.HandleFunc("POST /auth/r/{id}/sso", s.resourceAuth("sso", s.resourceSSO))
mux.HandleFunc("POST /auth/r/{id}/share", s.resourceAuth("share", s.resourceShare))
mux.HandleFunc("POST /auth/r/{id}/email/start", s.resourceAuth("emailstart", s.resourceEmailStart))
mux.HandleFunc("POST /auth/r/{id}/email/verify", s.resourceAuth("emailverify", s.resourceEmailVerify))
// any signed-in user
mux.HandleFunc("POST /api/logout", s.withUser(s.logout))
mux.HandleFunc("GET /api/me", s.withUser(s.me))
mux.HandleFunc("PUT /api/me", s.withUser(s.updateMe))
mux.HandleFunc("POST /api/me/password", s.withUser(s.changePassword))
mux.HandleFunc("POST /api/me/2fa/setup", s.withUser(s.totpSetup))
mux.HandleFunc("POST /api/me/2fa/enable", s.withUser(s.totpEnable))
mux.HandleFunc("POST /api/me/2fa/disable", s.withUser(s.totpDisable))
mux.HandleFunc("GET /api/me/resources", s.withUser(s.myResources))
mux.HandleFunc("GET /api/me/sessions", s.withUser(s.mySessions))
mux.HandleFunc("DELETE /api/me/sessions/{id}", s.withUser(s.endSession))
mux.HandleFunc("POST /api/me/sessions/revoke-others", s.withUser(s.endOtherSessions))
mux.HandleFunc("GET /api/edges", s.withUser(s.listEdges))
// server administrators
mux.HandleFunc("POST /api/edges", s.withServerAdmin(s.saveEdge))
mux.HandleFunc("PUT /api/edges/{id}", s.withServerAdmin(s.saveEdge))
mux.HandleFunc("DELETE /api/edges/{id}", s.withServerAdmin(s.deleteEdge))
mux.HandleFunc("POST /api/orgs", s.withServerAdmin(s.createOrg))
mux.HandleFunc("GET /api/admin/users", s.withServerAdmin(s.adminUsers))
mux.HandleFunc("POST /api/admin/users", s.withServerAdmin(s.adminCreateUser))
mux.HandleFunc("PUT /api/admin/users/{id}", s.withServerAdmin(s.adminUpdateUser))
mux.HandleFunc("DELETE /api/admin/users/{id}", s.withServerAdmin(s.adminDeleteUser))
mux.HandleFunc("GET /api/admin/idps", s.withServerAdmin(s.listIdPs))
mux.HandleFunc("POST /api/admin/idps", s.withServerAdmin(s.saveIdP))
mux.HandleFunc("PUT /api/admin/idps/{id}", s.withServerAdmin(s.saveIdP))
mux.HandleFunc("DELETE /api/admin/idps/{id}", s.withServerAdmin(s.deleteIdP))
mux.HandleFunc("GET /api/admin/settings", s.withServerAdmin(s.getSettings))
mux.HandleFunc("PUT /api/admin/settings", s.withServerAdmin(s.putSettings))
mux.HandleFunc("POST /api/admin/settings/test-mail", s.withServerAdmin(s.testMail))
mux.HandleFunc("GET /api/admin/update", s.withServerAdmin(s.checkUpdate))
mux.HandleFunc("POST /api/admin/update/apply", s.withServerAdmin(s.applyUpdate))
mux.HandleFunc("GET /api/admin/update/status", s.withServerAdmin(s.updateStatus))
mux.HandleFunc("GET /api/versions", s.withUser(s.latestVersions))
mux.HandleFunc("GET /api/edges/{id}/update/log", s.withServerAdmin(s.edgeUpdateLog))
mux.HandleFunc("GET /api/orgs/{org}/sites/{id}/update/log", s.withOrg(true, s.siteUpdateLog))
mux.HandleFunc("POST /api/edges/{id}/update", s.withServerAdmin(s.updateEdge))
mux.HandleFunc("POST /api/orgs/{org}/sites/{id}/update", s.withOrg(true, s.updateSite))
mux.HandleFunc("GET /api/admin/audit", s.withServerAdmin(func(w http.ResponseWriter, r *http.Request, p *principal) {
writeJSON(w, 200, s.logs.queryAudit("", 300, 0))
}))
// organization scope: members read, admins write
mux.HandleFunc("GET /api/orgs/{org}/state", s.withOrg(false, s.orgState))
mux.HandleFunc("PUT /api/orgs/{org}", s.withOrg(true, s.updateOrg))
mux.HandleFunc("DELETE /api/orgs/{org}", s.withOrg(true, s.deleteOrg))
mux.HandleFunc("GET /api/orgs/{org}/roles", s.withOrg(false, s.listRoles))
mux.HandleFunc("POST /api/orgs/{org}/roles", s.withOrg(true, s.saveRole))
mux.HandleFunc("PUT /api/orgs/{org}/roles/{role}", s.withOrg(true, s.saveRole))
mux.HandleFunc("DELETE /api/orgs/{org}/roles/{role}", s.withOrg(true, s.deleteRole))
mux.HandleFunc("GET /api/orgs/{org}/members", s.withOrg(true, s.listMembers))
mux.HandleFunc("PUT /api/orgs/{org}/members/{user}", s.withOrg(true, s.setMemberRole))
mux.HandleFunc("DELETE /api/orgs/{org}/members/{user}", s.withOrg(true, s.removeMember))
mux.HandleFunc("GET /api/orgs/{org}/invites", s.withOrg(true, s.listInvites))
mux.HandleFunc("POST /api/orgs/{org}/invites", s.withOrg(true, s.createInvite))
mux.HandleFunc("DELETE /api/orgs/{org}/invites/{id}", s.withOrg(true, s.deleteInvite))
mux.HandleFunc("GET /api/orgs/{org}/apikeys", s.withOrg(true, s.listKeys))
mux.HandleFunc("POST /api/orgs/{org}/apikeys", s.withOrg(true, s.createKey))
mux.HandleFunc("DELETE /api/orgs/{org}/apikeys/{id}", s.withOrg(true, s.deleteKey))
mux.HandleFunc("POST /api/orgs/{org}/sites", s.withOrg(true, s.addSite))
mux.HandleFunc("PUT /api/orgs/{org}/sites/{id}", s.withOrg(true, s.putSite))
mux.HandleFunc("DELETE /api/orgs/{org}/sites/{id}", s.withOrg(true, s.deleteSite))
mux.HandleFunc("GET /api/orgs/{org}/sites/{id}/containers", s.withOrg(true, s.siteContainers))
mux.HandleFunc("POST /api/orgs/{org}/domains", s.withOrg(true, s.addDomain))
mux.HandleFunc("DELETE /api/orgs/{org}/domains/{id}", s.withOrg(true, s.deleteDomain))
mux.HandleFunc("POST /api/orgs/{org}/domains/{id}/check", s.withOrg(true, s.checkDomain))
mux.HandleFunc("POST /api/orgs/{org}/mappings", s.withOrg(true, s.addMapping))
mux.HandleFunc("PUT /api/orgs/{org}/mappings/{id}", s.withOrg(true, s.putMapping))
mux.HandleFunc("DELETE /api/orgs/{org}/mappings/{id}", s.withOrg(true, s.deleteMapping))
mux.HandleFunc("GET /api/orgs/{org}/mappings/{id}/shares", s.withOrg(true, s.listShares))
mux.HandleFunc("POST /api/orgs/{org}/mappings/{id}/shares", s.withOrg(true, s.createShare))
mux.HandleFunc("POST /api/orgs/{org}/mappings/{id}/revoke", s.withOrg(true, s.revokeVisitors))
mux.HandleFunc("DELETE /api/orgs/{org}/mappings/{id}/shares/{share}", s.withOrg(true, s.deleteShare))
mux.HandleFunc("POST /api/orgs/{org}/mail-egress", s.withOrg(true, s.saveMailEgress))
mux.HandleFunc("PUT /api/orgs/{org}/mail-egress/{id}", s.withOrg(true, s.saveMailEgress))
mux.HandleFunc("DELETE /api/orgs/{org}/mail-egress/{id}", s.withOrg(true, s.deleteMailEgress))
mux.HandleFunc("GET /api/orgs/{org}/dkim", s.withOrg(true, s.listDKIM))
mux.HandleFunc("POST /api/orgs/{org}/dkim", s.withOrg(true, s.createDKIM))
mux.HandleFunc("DELETE /api/orgs/{org}/dkim/{id}", s.withOrg(true, s.deleteDKIM))
mux.HandleFunc("GET /api/orgs/{org}/logs", s.withOrg(true, s.orgLogs))
mux.HandleFunc("GET /api/orgs/{org}/stats", s.withOrg(false, s.orgStats))
mux.HandleFunc("GET /api/orgs/{org}/traffic", s.withOrg(false, s.orgTraffic))
mux.HandleFunc("GET /api/orgs/{org}/traffic/{id}", s.withOrg(false, s.orgTrafficDetail))
// agents
mux.HandleFunc("GET /edge/config", s.edgeConfig)
mux.HandleFunc("POST /edge/report", s.edgeReport)
mux.HandleFunc("POST /edge/logs", s.edgeLogs)
mux.HandleFunc("GET /site/config", s.siteConfig)
mux.HandleFunc("POST /site/report", s.siteReport)
return mux
}