129 lines
2.7 KiB
Go

package lib
import (
"bytes"
"crypto/tls"
"encoding/json"
"fmt"
"io"
"net/http"
)
type PVEServer struct {
HostName string
Port int
Username string
Password string
}
type PVERequestInit struct {
Body map[string]string
Ticket string
CSRF string
}
func fetch(method string, url string, cfg *PVERequestInit) ([]byte, error) {
var body io.Reader
if cfg.Body != nil {
json, _ := json.Marshal(cfg.Body)
body = bytes.NewBuffer(json)
}
req, _ := http.NewRequest(method, url, body)
if cfg.Ticket != "" {
req.Header.Add("Cookie", "PVEAuthCookie="+cfg.Ticket)
}
if cfg.CSRF != "" {
req.Header.Add("CSRFPreventionToken", cfg.CSRF)
}
if body != nil {
req.Header.Add("Content-Type", "application/json")
}
tr := &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
}
client := &http.Client{
Transport: tr,
}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("request failed with status code %d", resp.StatusCode)
}
return io.ReadAll(resp.Body)
}
type PVEAccessTicket struct {
CSRFPreventionToken string `json:"CSRFPreventionToken"`
Ticket string `json:"ticket"`
Username string `json:"username"`
}
func (pve *PVEServer) GetAccessTicket() (*PVEAccessTicket, error) {
url := fmt.Sprintf("https://%s:%d/api2/json/access/ticket", pve.HostName, pve.Port)
// note for myself: don't forget the realm
body, err := fetch("POST", url, &PVERequestInit{Body: map[string]string{
"username": pve.Username,
"password": pve.Password,
}})
if err != nil {
return nil, err
}
var res struct {
Data PVEAccessTicket `json:"data"`
}
if err := json.Unmarshal(body, &res); err != nil {
return nil, err
}
return &res.Data, nil
}
type PVEInstance struct {
Type string `json:"type"` // "qemu" | "lxc"
Node string `json:"node"`
VMID string `json:"vmid"`
}
type PVEVNCTicketData struct {
Port string `json:"port"`
User string `json:"user"`
Ticket string `json:"ticket"`
CERT string `json:"cert"`
Upid string `json:"upid"`
}
func (pve *PVEServer) GetVNCTicket(access *PVEAccessTicket, instance *PVEInstance, isVNC bool) (*PVEVNCTicketData, error) {
proxyType := "termproxy"
if isVNC {
proxyType = "vncproxy"
}
url := fmt.Sprintf("https://%s:%d/api2/json/nodes/%s/%s/%s/%s",
pve.HostName, pve.Port, instance.Node, instance.Type, instance.VMID, proxyType)
body, err := fetch("POST", url, &PVERequestInit{Ticket: access.Ticket, CSRF: access.CSRFPreventionToken})
if err != nil {
return nil, err
}
var res struct {
Data PVEVNCTicketData `json:"data"`
}
if err := json.Unmarshal(body, &res); err != nil {
return nil, err
}
return &res.Data, nil
}