-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathpike.go
154 lines (127 loc) · 4.41 KB
/
pike.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
package paymail
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"strings"
)
// PikeContactRequestResponse is PIKE wrapper for StandardResponse
type PikeContactRequestResponse struct {
StandardResponse
}
// PikeContactRequestPayload is a payload used to request a contact
type PikeContactRequestPayload struct {
FullName string `json:"fullName"`
Paymail string `json:"paymail"`
}
// PikePaymentOutputsPayload is a payload needed to get payment outputs
type PikePaymentOutputsPayload struct {
SenderPaymail string `json:"senderPaymail"`
Amount uint64 `json:"amount"`
}
// PikePaymentOutputsResponse is a response which contain output templates
type PikePaymentOutputsResponse struct {
Outputs []*OutputTemplate `json:"outputs"`
Reference string `json:"reference"`
}
// OutputTemplate is a single output template with satoshis
type OutputTemplate struct {
Script string `json:"script"`
Satoshis uint64 `json:"satoshis"`
}
func (c *Client) AddContactRequest(url, alias, domain string, request *PikeContactRequestPayload) (*PikeContactRequestResponse, error) {
if err := c.validateUrlWithPaymail(url, alias, domain); err != nil {
return nil, err
}
if err := request.validate(); err != nil {
return nil, err
}
// Set the base url and path, assuming the url is from the prior GetCapabilities() request
// https://<host-discovery-target>/{alias}@{domain.tld}/id
reqURL := replaceAliasDomain(url, alias, domain)
response, err := c.postRequest(reqURL, request)
if err != nil {
return nil, err
}
if response.StatusCode != http.StatusOK && response.StatusCode != http.StatusCreated {
if response.StatusCode == http.StatusNotFound {
return nil, errors.New("paymail address not found")
} else {
return nil, c.prepareServerErrorResponse(&response)
}
}
return &PikeContactRequestResponse{response}, nil
}
func (c *Client) validateUrlWithPaymail(url, alias, domain string) error {
if len(url) == 0 || !strings.HasPrefix(url, "https://") {
return fmt.Errorf("invalid url: %s", url)
} else if alias == "" {
return errors.New("missing alias")
} else if domain == "" {
return errors.New("missing domain")
}
return nil
}
func (c *Client) prepareServerErrorResponse(response *StandardResponse) error {
var details string
serverError := &ServerError{}
if err := json.Unmarshal(response.Body, serverError); err != nil || serverError.Message == "" {
details = fmt.Sprintf("body: %s", string(response.Body))
} else {
details = fmt.Sprintf("message: %s", serverError.Message)
}
return fmt.Errorf("bad response from paymail provider: code %d, %s", response.StatusCode, details)
}
func (r *PikeContactRequestPayload) validate() error {
if r.FullName == "" {
return errors.New("missing full name")
}
if r.Paymail == "" {
return errors.New("missing paymail address")
}
return ValidatePaymail(r.Paymail)
}
// GetOutputsTemplate calls the PIKE capability outputs subcapability
func (c *Client) GetOutputsTemplate(pikeURL, alias, domain string, payload *PikePaymentOutputsPayload) (response *PikePaymentOutputsResponse, err error) {
// Require a valid URL
if len(pikeURL) == 0 || !strings.Contains(pikeURL, "https://") {
err = fmt.Errorf("invalid url: %s", pikeURL)
return
}
// Basic requirements for request
if payload == nil {
err = errors.New("payload cannot be nil")
return
} else if payload.Amount == 0 {
err = errors.New("amount is required")
return
} else if len(alias) == 0 {
err = errors.New("missing alias")
return
} else if len(domain) == 0 {
err = errors.New("missing domain")
return
}
// Set the base URL and path, assuming the URL is from the prior GetCapabilities() request
reqURL := replaceAliasDomain(pikeURL, alias, domain)
// Fire the POST request
var resp StandardResponse
if resp, err = c.postRequest(reqURL, payload); err != nil {
return
}
// Test the status code
if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("bad response from PIKE outputs: code %d", resp.StatusCode)
}
// Decode the body of the response
outputs := &PikePaymentOutputsResponse{}
if err = json.Unmarshal(resp.Body, outputs); err != nil {
return nil, err
}
return outputs, nil
}
// AddInviteRequest sends a contact request using the invite URL from capabilities
func (c *Client) AddInviteRequest(inviteURL, alias, domain string, request *PikeContactRequestPayload) (*PikeContactRequestResponse, error) {
return c.AddContactRequest(inviteURL, alias, domain, request)
}