-
Notifications
You must be signed in to change notification settings - Fork 2
/
uri.go
95 lines (83 loc) · 2.41 KB
/
uri.go
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
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package cryptoconditions
import (
"fmt"
"net/url"
"strconv"
"strings"
"github.com/kalaspuffar/base64url"
"github.com/pkg/errors"
)
// generateURI generates a URI for the given condition.
func generateURI(condition *Condition) string {
params := make(url.Values)
params.Set("cost", fmt.Sprintf("%d", condition.Cost()))
params.Set("fpt", strings.ToLower(condition.Type().String()))
if condition.Type().IsCompound() {
subtypesString := ""
for _, st := range condition.SubTypes().AllTypes() {
subtypesString += strings.ToLower(st.String()) + ","
}
if subtypesString != "" {
params.Set("subtypes", strings.TrimSuffix(subtypesString, ","))
}
}
encodedFingerprint := base64url.Encode(condition.Fingerprint())
uri := url.URL{
Scheme: "ni",
Path: "/sha-256;" + encodedFingerprint,
RawQuery: params.Encode(),
}
return uri.String()
}
// ParseURI parses a URI into a Condition.
func ParseURI(uri string) (*Condition, error) {
u, err := url.Parse(uri)
if err != nil {
return nil, errors.Wrap(err, "failed to parse URI")
}
params := u.Query()
// Find the condition type.
conditionTypeString := strings.ToUpper(params.Get("fpt"))
conditionType, found := conditionTypeDictionary[conditionTypeString]
if !found {
return nil, errors.Errorf(
"unknown condition type: %s", params.Get("fpt"))
}
// Parse the fingerprint.
pathParts := strings.SplitN(u.Path, ";", 2)
if len(pathParts) != 2 {
return nil, errors.New("incorrectly formatted URI, no semicolon found")
}
fingerprint, err := base64url.Decode(pathParts[1])
if err != nil {
return nil, errors.Wrap(err,
"failed to decode base64url encoded fingerprint")
}
// Parse cost.
parsedInt, err := strconv.ParseInt(params.Get("cost"), 10, 64)
if err != nil {
return nil, errors.Wrapf(err,
"failed to parse cost value %s", params.Get("cost"))
}
cost := int(parsedInt)
// Parse subtypes.
subtypeSet := &ConditionTypeSet{}
if params.Get("subtypes") != "" {
subtypeStrings := strings.Split(params.Get("subtypes"), ",")
for _, subtypeString := range subtypeStrings {
subType, found := conditionTypeDictionary[strings.ToUpper(subtypeString)]
if !found {
return nil, errors.Errorf(
"unknown condition type in subconditions: %s",
subtypeString)
}
subtypeSet.add(subType)
}
}
return &Condition{
conditionType: conditionType,
fingerprint: fingerprint,
cost: cost,
subTypes: *subtypeSet,
}, nil
}