Skip to content
File

Blob: tun/client/formatter.go

go132 lines
1package client
2 
3import (
4 "encoding/json"
5 "io"
6 "time"
7 
8 "go.miragespace.co/specter/spec/protocol"
9 
10 "github.com/miekg/dns"
11)
12 
13type listTunnelItem struct {
14 Hostname string `json:"hostname"`
15 Target string `json:"target"`
16 HeaderHost string `json:"headerHost"`
17}
18 
19func (c *Client) FormatList(hostnames []string, output io.Writer) {
20 items := make([]listTunnelItem, 0)
21 
22 tunnelMap := make(map[string]Tunnel)
23 curr := c.GetCurrentConfig()
24 for _, t := range curr.Tunnels {
25 tunnelMap[t.Hostname] = t
26 }
27 
28 for _, h := range hostnames {
29 item := listTunnelItem{
30 Hostname: h,
31 }
32 t, ok := tunnelMap[h]
33 if ok {
34 item.Target = t.Target
35 item.HeaderHost = t.ProxyHeaderHost
36 } else {
37 item.Target = "(unused)"
38 }
39 items = append(items, item)
40 }
41 
42 encoder := json.NewEncoder(output)
43 encoder.SetIndent("", " ")
44 encoder.Encode(&items)
45}
46 
47type acmeItem struct {
48 Message string `json:"message"`
49 Record string `json:"record"`
50 Type string `json:"type"`
51 Content string `json:"content"`
52}
53 
54func (c *Client) FormatAcme(resp *protocol.InstructionResponse, output io.Writer) {
55 item := acmeItem{
56 Message: "Please add the following DNS record to validate ownership",
57 Record: resp.GetName(),
58 Type: "CNAME",
59 Content: resp.GetContent(),
60 }
61 
62 encoder := json.NewEncoder(output)
63 encoder.SetIndent("", " ")
64 encoder.Encode(&item)
65}
66 
67func (c *Client) FormatValidate(hostname string, resp *protocol.ValidateResponse, output io.Writer) {
68 item := acmeItem{
69 Message: "Ownership validated! Please add the following DNS record to be used with specter",
70 Record: dns.Fqdn(hostname),
71 Type: "CNAME",
72 Content: resp.GetApex(),
73 }
74 
75 encoder := json.NewEncoder(output)
76 encoder.SetIndent("", " ")
77 encoder.Encode(&item)
78}
79 
80type domainToken struct {
81 ID string `json:"id"`
82 Hostname string `json:"hostname"`
83 ExpiresAt string `json:"expiresAt,omitempty"`
84 Incomplete bool `json:"incomplete"`
85}
86 
87func formatDomainToken(grant *protocol.DelegationGrant) domainToken {
88 item := domainToken{
89 ID: grant.GetId(),
90 Hostname: grant.GetHostname(),
91 Incomplete: grant.GetIncomplete(),
92 }
93 if grant.GetExpiresAt() != 0 {
94 item.ExpiresAt = time.Unix(grant.GetExpiresAt(), 0).UTC().Format(time.RFC3339)
95 }
96 return item
97}
98 
99func formatDelegationJSON(output io.Writer, value any) error {
100 encoder := json.NewEncoder(output)
101 encoder.SetIndent("", " ")
102 return encoder.Encode(value)
103}
104 
105func (c *Client) FormatDelegations(resp *protocol.ListDelegationsResponse, output io.Writer) error {
106 items := make([]domainToken, 0, len(resp.GetGrants()))
107 for _, grant := range resp.GetGrants() {
108 items = append(items, formatDomainToken(grant))
109 }
110 return formatDelegationJSON(output, items)
111}
112 
113func (c *Client) FormatMintedDelegation(resp *protocol.MintDelegationResponse, output io.Writer) error {
114 return formatDelegationJSON(output, struct {
115 Grant domainToken `json:"grant"`
116 Token string `json:"token"`
117 }{
118 Grant: formatDomainToken(resp.GetGrant()),
119 Token: resp.GetToken(),
120 })
121}
122 
123func (c *Client) FormatRevokedDelegation(resp *protocol.RevokeDelegationResponse, output io.Writer) error {
124 return formatDelegationJSON(output, struct {
125 Revoked bool `json:"revoked"`
126 IndexError string `json:"indexError,omitempty"`
127 }{
128 Revoked: resp.GetRevoked(),
129 IndexError: resp.GetIndexError(),
130 })
131}