Initial commit: AetherForge Linux (forge-mesh) v0.1.0-dev
Some checks failed
Test / test (push) Has been cancelled
Some checks failed
Test / test (push) Has been cancelled
This commit is contained in:
138
internal/api/handlers/public.go
Normal file
138
internal/api/handlers/public.go
Normal file
@@ -0,0 +1,138 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"text/template"
|
||||
"net/http"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"forge-mesh/internal/forge"
|
||||
)
|
||||
|
||||
// PublicHandlers serves unauthenticated summon routes.
|
||||
type PublicHandlers struct {
|
||||
DB *sql.DB
|
||||
ArtifactsDir string
|
||||
PublicKeyHex string
|
||||
FleetSecret string
|
||||
Version string
|
||||
InstallTmpl *template.Template
|
||||
DeckURL func(r *http.Request) string
|
||||
}
|
||||
|
||||
type installData struct {
|
||||
DeckURL string
|
||||
PublicKey string
|
||||
FleetSecret string
|
||||
Pin string
|
||||
Campaign string
|
||||
}
|
||||
|
||||
func NewPublicHandlers(db *sql.DB, artifactsDir, publicKeyHex string, installTmplPath string) (*PublicHandlers, error) {
|
||||
tmplBytes, err := os.ReadFile(installTmplPath)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("read install template: %w", err)
|
||||
}
|
||||
|
||||
tmpl, err := template.New("install.sh").Parse(string(tmplBytes))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("parse install template: %w", err)
|
||||
}
|
||||
|
||||
return &PublicHandlers{
|
||||
DB: db,
|
||||
ArtifactsDir: artifactsDir,
|
||||
PublicKeyHex: publicKeyHex,
|
||||
InstallTmpl: tmpl,
|
||||
DeckURL: func(r *http.Request) string {
|
||||
scheme := "http"
|
||||
if r.TLS != nil || r.Header.Get("X-Forwarded-Proto") == "https" {
|
||||
scheme = "https"
|
||||
}
|
||||
return fmt.Sprintf("%s://%s", scheme, r.Host)
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *PublicHandlers) InstallSh(w http.ResponseWriter, r *http.Request) {
|
||||
data := installData{
|
||||
DeckURL: h.DeckURL(r),
|
||||
PublicKey: h.PublicKeyHex,
|
||||
FleetSecret: h.FleetSecret,
|
||||
Pin: r.URL.Query().Get("pin"),
|
||||
Campaign: r.URL.Query().Get("c"),
|
||||
}
|
||||
|
||||
var buf bytes.Buffer
|
||||
if err := h.InstallTmpl.Execute(&buf, data); err != nil {
|
||||
http.Error(w, "template error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "text/x-shellscript; charset=utf-8")
|
||||
w.Write(buf.Bytes())
|
||||
}
|
||||
|
||||
func (h *PublicHandlers) GetRedirect(w http.ResponseWriter, r *http.Request) {
|
||||
target := "/install.sh"
|
||||
if q := r.URL.RawQuery; q != "" {
|
||||
target += "?" + q
|
||||
}
|
||||
http.Redirect(w, r, target, http.StatusFound)
|
||||
}
|
||||
|
||||
func (h *PublicHandlers) LatestBuild(w http.ResponseWriter, r *http.Request) {
|
||||
osName := r.URL.Query().Get("os")
|
||||
arch := r.URL.Query().Get("arch")
|
||||
if osName == "" {
|
||||
osName = "linux"
|
||||
}
|
||||
if arch == "" {
|
||||
arch = "amd64"
|
||||
}
|
||||
|
||||
build, err := forge.LatestPublic(h.DB, osName, arch)
|
||||
if err != nil {
|
||||
if err == sql.ErrNoRows {
|
||||
http.Error(w, "no public build", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
http.Error(w, "internal error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
fmt.Fprintf(w, `{"id":%q,"os":%q,"arch":%q,"version":%q,"checksum":%q,"signature":%q,"download_url":"/api/v1/public/download/%s"}`,
|
||||
build.ID, build.OS, build.Arch, build.Version, build.Checksum, build.Signature, build.ID)
|
||||
}
|
||||
|
||||
func (h *PublicHandlers) Download(w http.ResponseWriter, r *http.Request) {
|
||||
id := r.PathValue("id")
|
||||
if strings.Contains(id, "..") {
|
||||
http.Error(w, "bad request", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
build, err := forge.GetBuild(h.DB, id)
|
||||
if err != nil {
|
||||
http.Error(w, "not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
if !build.Public {
|
||||
http.Error(w, "forbidden", http.StatusForbidden)
|
||||
return
|
||||
}
|
||||
if build.Path == "" {
|
||||
http.Error(w, "artifact missing", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
w.Header().Set("Content-Type", "application/octet-stream")
|
||||
w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="forge-mesh-agent-%s-%s"`, build.OS, build.Arch))
|
||||
if err := forge.CopyArtifact(build.Path, w); err != nil {
|
||||
http.Error(w, "read error", http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user