1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
package guestidentity
import (
"fmt"
"slices"
"strings"
)
type LoginStep string
const (
LoginBind LoginStep = "bind"
LoginChallenge LoginStep = "challenge"
LoginLogin LoginStep = "login"
)
const maximumLoginField = 4096
var loginFields = map[LoginStep][]string{
LoginBind: {"role", "bind_secret", "host_key", "signature"},
LoginChallenge: {"role"},
LoginLogin: {"role", "challenge", "signature"},
}
func ParseLoginStep(step string) (LoginStep, error) {
s := LoginStep(step)
if _, ok := loginFields[s]; !ok {
return "", fmt.Errorf("guestidentity: %q is not a guest login step", step)
}
return s, nil
}
func (s LoginStep) Fields() []string {
fields, ok := loginFields[s]
if !ok {
return nil
}
return append([]string(nil), fields...)
}
func LoginBody(step LoginStep, input map[string]any) (map[string]string, error) {
fields, ok := loginFields[step]
if !ok {
return nil, fmt.Errorf("guestidentity: %q is not a guest login step", step)
}
out := make(map[string]string, len(fields))
for name, value := range input {
if !contains(fields, name) {
return nil, fmt.Errorf("guestidentity: the %s step takes %s, not %s", step, strings.Join(fields, ", "), name)
}
text, ok := value.(string)
if !ok || text == "" || len(text) > maximumLoginField {
return nil, fmt.Errorf("guestidentity: %s must be a string of 1 to %d bytes", name, maximumLoginField)
}
out[name] = text
}
for _, name := range fields {
if out[name] == "" {
return nil, fmt.Errorf("guestidentity: the %s step needs %s", step, name)
}
}
role := out["role"]
if !ValidComputeVM(role) {
return nil, fmt.Errorf("guestidentity: role %q is not a ComputeVM name", role)
}
return out, nil
}
func contains(list []string, value string) bool {
return slices.Contains(list, value)
}