-
Notifications
You must be signed in to change notification settings - Fork 36
/
aliases.go
176 lines (143 loc) · 4.6 KB
/
aliases.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
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
package handlers
import (
"encoding/base64"
"encoding/json"
"fmt"
"html/template"
"log"
"net/http"
"net/url"
"github.com/gorilla/mux"
"go.mindeco.de/http/render"
"github.com/ssb-ngi-pointer/go-ssb-room/internal/aliases"
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
)
// aliasHandler implements the public resolve endpoint for HTML and JSON requests.
type aliasHandler struct {
r *render.Renderer
db roomdb.AliasesService
config roomdb.RoomConfig
roomEndpoint network.ServerEndpointDetails
}
func (h aliasHandler) resolve(rw http.ResponseWriter, req *http.Request) {
respEncoding := req.URL.Query().Get("encoding")
var ar aliasResponder
switch respEncoding {
case "json":
ar = newAliasJSONResponder(rw)
default:
ar = newAliasHTMLResponder(h.r, rw, req)
}
ar.UpdateRoomInfo(h.roomEndpoint)
pm, err := h.config.GetPrivacyMode(req.Context())
if err != nil {
ar.SendError(fmt.Errorf("room is running an unknown privacy mode"))
return
}
if pm == roomdb.ModeRestricted {
ar.SendError(fmt.Errorf("this room is restricted, alias resolving is turned off"))
return
}
name := mux.Vars(req)["alias"]
if name == "" && !aliases.IsValid(name) {
ar.SendError(fmt.Errorf("invalid alias"))
return
}
alias, err := h.db.Resolve(req.Context(), name)
if err != nil {
ar.SendError(fmt.Errorf("aliases: failed to resolve name %q: %w", name, err))
return
}
ar.SendConfirmation(alias)
}
// aliasResponder is supposed to handle different encoding types transparently.
// It either sends the signed alias confirmation or an error.
type aliasResponder interface {
SendConfirmation(roomdb.Alias)
SendError(error)
UpdateRoomInfo(netInfo network.ServerEndpointDetails)
}
// aliasJSONResponse dictates the field names and format of the JSON response for the alias web endpoint
type aliasJSONResponse struct {
Status string `json:"status"`
MultiserverAddress string `json:"multiserverAddress"`
RoomID string `json:"roomId"`
UserID string `json:"userId"`
Alias string `json:"alias"`
Signature string `json:"signature"`
}
// handles JSON responses
type aliasJSONResponder struct {
enc *json.Encoder
netInfo network.ServerEndpointDetails
}
func newAliasJSONResponder(rw http.ResponseWriter) aliasResponder {
rw.Header().Set("Content-Type", "application/json")
return &aliasJSONResponder{
enc: json.NewEncoder(rw),
}
}
func (json *aliasJSONResponder) UpdateRoomInfo(netInfo network.ServerEndpointDetails) {
json.netInfo = netInfo
}
func (json aliasJSONResponder) SendConfirmation(alias roomdb.Alias) {
var resp = aliasJSONResponse{
Status: "successful",
RoomID: json.netInfo.RoomID.Ref(),
MultiserverAddress: json.netInfo.MultiserverAddress(),
Alias: alias.Name,
UserID: alias.Feed.Ref(),
Signature: base64.StdEncoding.EncodeToString(alias.Signature),
}
json.enc.Encode(resp)
}
func (json aliasJSONResponder) SendError(err error) {
json.enc.Encode(struct {
Status string `json:"status"`
Error string `json:"error"`
}{"error", err.Error()})
}
// handles HTML responses
type aliasHTMLResponder struct {
renderer *render.Renderer
rw http.ResponseWriter
req *http.Request
netInfo network.ServerEndpointDetails
}
func newAliasHTMLResponder(r *render.Renderer, rw http.ResponseWriter, req *http.Request) aliasResponder {
return &aliasHTMLResponder{
renderer: r,
rw: rw,
req: req,
}
}
func (html *aliasHTMLResponder) UpdateRoomInfo(netInfo network.ServerEndpointDetails) {
html.netInfo = netInfo
}
func (html aliasHTMLResponder) SendConfirmation(alias roomdb.Alias) {
// construct the ssb:experimental?action=consume-alias&... uri for linking into apps
queryParams := url.Values{}
queryParams.Set("action", "consume-alias")
queryParams.Set("roomId", html.netInfo.RoomID.Ref())
queryParams.Set("alias", alias.Name)
queryParams.Set("userId", alias.Feed.Ref())
queryParams.Set("signature", base64.URLEncoding.EncodeToString(alias.Signature))
queryParams.Set("multiserverAddress", html.netInfo.MultiserverAddress())
// html.multiservAddr
ssbURI := url.URL{
Scheme: "ssb",
Opaque: "experimental",
RawQuery: queryParams.Encode(),
}
err := html.renderer.Render(html.rw, html.req, "alias.tmpl", http.StatusOK, struct {
Alias roomdb.Alias
SSBURI template.URL
}{alias, template.URL(ssbURI.String())})
if err != nil {
log.Println("alias-resolve render errr:", err)
}
}
func (html aliasHTMLResponder) SendError(err error) {
html.renderer.Error(html.rw, html.req, http.StatusInternalServerError, err)
}