···
"github.com/go-chi/chi/v5"
···
"tangled.sh/tangled.sh/core/appview/middleware"
"tangled.sh/tangled.sh/core/appview/oauth"
"tangled.sh/tangled.sh/core/appview/pages"
18
+
"tangled.sh/tangled.sh/core/appview/serververify"
"tangled.sh/tangled.sh/core/eventconsumer"
"tangled.sh/tangled.sh/core/idresolver"
23
-
"tangled.sh/tangled.sh/core/knotclient"
"tangled.sh/tangled.sh/core/rbac"
"tangled.sh/tangled.sh/core/tid"
···
Knotstream *eventconsumer.Consumer
42
-
func (k *Knots) Router(mw *middleware.Middleware) http.Handler {
39
+
func (k *Knots) Router() http.Handler {
45
-
r.Use(middleware.AuthMiddleware(k.OAuth))
42
+
r.With(middleware.AuthMiddleware(k.OAuth)).Get("/", k.knots)
43
+
r.With(middleware.AuthMiddleware(k.OAuth)).Post("/register", k.register)
48
-
r.Post("/key", k.generateKey)
45
+
r.With(middleware.AuthMiddleware(k.OAuth)).Get("/{domain}", k.dashboard)
46
+
r.With(middleware.AuthMiddleware(k.OAuth)).Delete("/{domain}", k.delete)
50
-
r.Route("/{domain}", func(r chi.Router) {
51
-
r.Post("/init", k.init)
52
-
r.Get("/", k.dashboard)
53
-
r.Route("/member", func(r chi.Router) {
54
-
r.Use(mw.KnotOwner())
55
-
r.Get("/", k.members)
56
-
r.Put("/", k.addMember)
57
-
r.Delete("/", k.removeMember)
48
+
r.With(middleware.AuthMiddleware(k.OAuth)).Post("/{domain}/retry", k.retry)
49
+
r.With(middleware.AuthMiddleware(k.OAuth)).Post("/{domain}/add", k.addMember)
50
+
r.With(middleware.AuthMiddleware(k.OAuth)).Post("/{domain}/remove", k.removeMember)
64
-
// get knots registered by this user
65
-
func (k *Knots) index(w http.ResponseWriter, r *http.Request) {
66
-
l := k.Logger.With("handler", "index")
55
+
func (k *Knots) knots(w http.ResponseWriter, r *http.Request) {
user := k.OAuth.GetUser(r)
registrations, err := db.RegistrationsByDid(k.Db, user.Did)
71
-
l.Error("failed to get registrations by did", "err", err)
59
+
k.Logger.Error("failed to fetch knot registrations", "err", err)
60
+
w.WriteHeader(http.StatusInternalServerError)
k.Pages.Knots(w, pages.KnotsParams{
···
81
-
func (k *Knots) generateKey(w http.ResponseWriter, r *http.Request) {
82
-
l := k.Logger.With("handler", "generateKey")
70
+
func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) {
71
+
l := k.Logger.With("handler", "dashboard")
user := k.OAuth.GetUser(r)
86
-
l = l.With("did", did)
74
+
l = l.With("user", user.Did)
88
-
// check if domain is valid url, and strip extra bits down to just host
89
-
domain := r.FormValue("domain")
76
+
domain := chi.URLParam(r, "domain")
91
-
l.Error("empty domain")
92
-
http.Error(w, "Invalid form", http.StatusBadRequest)
l = l.With("domain", domain)
97
-
noticeId := "registration-error"
99
-
k.Pages.Notice(w, noticeId, "Failed to generate registration key.")
82
+
registrations, err := db.RegistrationsByDid(k.Db, user.Did)
84
+
l.Error("failed to get registrations", "err", err)
85
+
http.Error(w, "Not found", http.StatusNotFound)
102
-
key, err := db.GenerateRegistrationKey(k.Db, domain, did)
89
+
// Find the specific registration for this domain
90
+
var registration *db.Registration
91
+
for _, reg := range registrations {
92
+
if reg.Domain == domain && reg.ByDid == user.Did && reg.Registered != nil {
98
+
if registration == nil {
99
+
l.Error("registration not found or not verified")
100
+
http.Error(w, "Not found", http.StatusNotFound)
104
+
members, err := k.Enforcer.GetUserByRole("server:member", domain)
104
-
l.Error("failed to generate registration key", "err", err)
106
+
l.Error("failed to get knot members", "err", err)
107
+
http.Error(w, "Not found", http.StatusInternalServerError)
110
+
slices.Sort(members)
109
-
allRegs, err := db.RegistrationsByDid(k.Db, did)
112
+
repos, err := db.GetRepos(
115
+
db.FilterEq("knot", domain),
111
-
l.Error("failed to generate registration key", "err", err)
118
+
l.Error("failed to get knot repos", "err", err)
119
+
http.Error(w, "Not found", http.StatusInternalServerError)
116
-
k.Pages.KnotListingFull(w, pages.KnotListingFullParams{
117
-
Registrations: allRegs,
119
-
k.Pages.KnotSecret(w, pages.KnotSecretParams{
123
+
identsToResolve := make([]string, len(members))
124
+
copy(identsToResolve, members)
125
+
resolvedIds := k.IdResolver.ResolveIdents(r.Context(), identsToResolve)
126
+
didHandleMap := make(map[string]string)
127
+
for _, identity := range resolvedIds {
128
+
if !identity.Handle.IsInvalidHandle() {
129
+
didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String())
131
+
didHandleMap[identity.DID.String()] = identity.DID.String()
135
+
// organize repos by did
136
+
repoMap := make(map[string][]db.Repo)
137
+
for _, r := range repos {
138
+
repoMap[r.Did] = append(repoMap[r.Did], r)
141
+
k.Pages.Knot(w, pages.KnotParams{
142
+
LoggedInUser: user,
143
+
Registration: registration,
146
+
DidHandleMap: didHandleMap,
124
-
// create a signed request and check if a node responds to that
125
-
func (k *Knots) init(w http.ResponseWriter, r *http.Request) {
126
-
l := k.Logger.With("handler", "init")
151
+
func (k *Knots) register(w http.ResponseWriter, r *http.Request) {
user := k.OAuth.GetUser(r)
153
+
l := k.Logger.With("handler", "register")
129
-
noticeId := "operation-error"
130
-
defaultErr := "Failed to initialize knot. Try again later."
155
+
noticeId := "register-error"
156
+
defaultErr := "Failed to register knot. Try again later."
k.Pages.Notice(w, noticeId, defaultErr)
135
-
domain := chi.URLParam(r, "domain")
161
+
domain := r.FormValue("domain")
137
-
http.Error(w, "malformed url", http.StatusBadRequest)
163
+
k.Pages.Notice(w, noticeId, "Incomplete form.")
l = l.With("domain", domain)
167
+
l = l.With("user", user.Did)
142
-
l.Info("checking domain")
169
+
tx, err := k.Db.Begin()
171
+
l.Error("failed to start transaction", "err", err)
177
+
k.Enforcer.E.LoadPolicy()
144
-
registration, err := db.RegistrationByDomain(k.Db, domain)
180
+
err = db.AddKnot(tx, domain, user.Did)
146
-
l.Error("failed to get registration for domain", "err", err)
182
+
l.Error("failed to insert", "err", err)
150
-
if registration.ByDid != user.Did {
151
-
l.Error("unauthorized", "wantedDid", registration.ByDid, "gotDid", user.Did)
152
-
w.WriteHeader(http.StatusUnauthorized)
187
+
err = k.Enforcer.AddKnot(domain)
189
+
l.Error("failed to create knot", "err", err)
156
-
secret, err := db.GetRegistrationKey(k.Db, domain)
194
+
// create record on pds
195
+
client, err := k.OAuth.AuthorizedClient(r)
158
-
l.Error("failed to get registration key for domain", "err", err)
197
+
l.Error("failed to authorize client", "err", err)
163
-
client, err := knotclient.NewSignedClient(domain, secret, k.Config.Core.Dev)
202
+
ex, _ := client.RepoGetRecord(r.Context(), "", tangled.KnotNSID, user.Did, domain)
208
+
// re-announce by registering under same rkey
209
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
210
+
Collection: tangled.KnotNSID,
213
+
Record: &lexutil.LexiconTypeDecoder{
214
+
Val: &tangled.Knot{
215
+
CreatedAt: time.Now().Format(time.RFC3339),
165
-
l.Error("failed to create knotclient", "err", err)
222
+
l.Error("failed to put record", "err", err)
170
-
resp, err := client.Init(user.Did)
172
-
k.Pages.Notice(w, noticeId, fmt.Sprintf("Failed to make request: %s", err.Error()))
173
-
l.Error("failed to make init request", "err", err)
229
+
l.Error("failed to commit transaction", "err", err)
177
-
if resp.StatusCode == http.StatusConflict {
178
-
k.Pages.Notice(w, noticeId, "This knot is already registered")
179
-
l.Error("knot already registered", "statuscode", resp.StatusCode)
234
+
err = k.Enforcer.E.SavePolicy()
236
+
l.Error("failed to update ACL", "err", err)
237
+
k.Pages.HxRefresh(w)
183
-
if resp.StatusCode != http.StatusNoContent {
184
-
k.Pages.Notice(w, noticeId, fmt.Sprintf("Received status %d from knot, expected %d", resp.StatusCode, http.StatusNoContent))
185
-
l.Error("incorrect statuscode returned", "statuscode", resp.StatusCode, "expected", http.StatusNoContent)
241
+
// begin verification
242
+
err = serververify.RunVerification(r.Context(), domain, user.Did, k.Config.Core.Dev)
244
+
l.Error("verification failed", "err", err)
245
+
k.Pages.HxRefresh(w)
189
-
// verify response mac
190
-
signature := resp.Header.Get("X-Signature")
191
-
signatureBytes, err := hex.DecodeString(signature)
249
+
err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Did)
251
+
l.Error("failed to mark verified", "err", err)
252
+
k.Pages.HxRefresh(w)
196
-
expectedMac := hmac.New(sha256.New, []byte(secret))
197
-
expectedMac.Write([]byte("ok"))
256
+
// add this knot to knotstream
257
+
go k.Knotstream.AddSource(
259
+
eventconsumer.NewKnotSource(domain),
263
+
k.Pages.HxRefresh(w)
266
+
func (k *Knots) delete(w http.ResponseWriter, r *http.Request) {
267
+
user := k.OAuth.GetUser(r)
268
+
l := k.Logger.With("handler", "delete")
270
+
noticeId := "operation-error"
271
+
defaultErr := "Failed to delete knot. Try again later."
273
+
k.Pages.Notice(w, noticeId, defaultErr)
199
-
if !hmac.Equal(expectedMac.Sum(nil), signatureBytes) {
200
-
k.Pages.Notice(w, noticeId, "Response signature mismatch, consider regenerating the secret and retrying.")
201
-
l.Error("signature mismatch", "bytes", signatureBytes)
276
+
domain := chi.URLParam(r, "domain")
278
+
l.Error("empty domain")
205
-
tx, err := k.Db.BeginTx(r.Context(), nil)
283
+
registration, err := db.RegistrationByDomain(k.Db, domain)
207
-
l.Error("failed to start tx", "err", err)
285
+
l.Error("failed to retrieve domain registration", "err", err)
290
+
if registration.ByDid != user.Did {
291
+
l.Error("unauthorized", "user", user.Did, "owner", registration.ByDid)
292
+
k.Pages.Notice(w, noticeId, "Failed to delete knot, unauthorized deletion attempt.")
296
+
tx, err := k.Db.Begin()
298
+
l.Error("failed to start txn", "err", err)
213
-
err = k.Enforcer.E.LoadPolicy()
215
-
l.Error("rollback failed", "err", err)
304
+
k.Enforcer.E.LoadPolicy()
219
-
// mark as registered
220
-
err = db.Register(tx, domain)
307
+
err = db.DeleteKnot(
309
+
db.FilterEq("did", user.Did),
310
+
db.FilterEq("domain", domain),
222
-
l.Error("failed to register domain", "err", err)
313
+
l.Error("failed to delete registration", "err", err)
227
-
// set permissions for this did as owner
228
-
reg, err := db.RegistrationByDomain(tx, domain)
230
-
l.Error("failed get registration by domain", "err", err)
318
+
// delete from enforcer if it was registered
319
+
if registration.Registered != nil {
320
+
err = k.Enforcer.RemoveKnot(domain)
322
+
l.Error("failed to update ACL", "err", err)
235
-
// add basic acls for this domain
236
-
err = k.Enforcer.AddKnot(domain)
328
+
client, err := k.OAuth.AuthorizedClient(r)
238
-
l.Error("failed to add knot to enforcer", "err", err)
330
+
l.Error("failed to authorize client", "err", err)
243
-
// add this did as owner of this domain
244
-
err = k.Enforcer.AddKnotOwner(domain, reg.ByDid)
335
+
_, err = client.RepoDeleteRecord(r.Context(), &comatproto.RepoDeleteRecord_Input{
336
+
Collection: tangled.KnotNSID,
246
-
l.Error("failed to add knot owner to enforcer", "err", err)
342
+
l.Error("failed to delete record", "err", err)
253
-
l.Error("failed to commit changes", "err", err)
347
+
l.Error("failed to delete knot", "err", err)
err = k.Enforcer.E.SavePolicy()
260
-
l.Error("failed to update ACLs", "err", err)
354
+
l.Error("failed to update ACL", "err", err)
355
+
k.Pages.HxRefresh(w)
265
-
// add this knot to knotstream
266
-
go k.Knotstream.AddSource(
267
-
context.Background(),
268
-
eventconsumer.NewKnotSource(domain),
359
+
shouldRedirect := r.Header.Get("shouldRedirect")
360
+
if shouldRedirect == "true" {
361
+
k.Pages.HxRedirect(w, "/knots")
271
-
k.Pages.KnotListing(w, pages.KnotListingParams{
272
-
Registration: *reg,
276
-
func (k *Knots) dashboard(w http.ResponseWriter, r *http.Request) {
277
-
l := k.Logger.With("handler", "dashboard")
368
+
func (k *Knots) retry(w http.ResponseWriter, r *http.Request) {
369
+
user := k.OAuth.GetUser(r)
370
+
l := k.Logger.With("handler", "retry")
372
+
noticeId := "operation-error"
373
+
defaultErr := "Failed to verify knot. Try again later."
279
-
w.WriteHeader(http.StatusInternalServerError)
375
+
k.Pages.Notice(w, noticeId, defaultErr)
domain := chi.URLParam(r, "domain")
284
-
http.Error(w, "malformed url", http.StatusBadRequest)
380
+
l.Error("empty domain")
l = l.With("domain", domain)
289
-
user := k.OAuth.GetUser(r)
290
-
l = l.With("did", user.Did)
385
+
l = l.With("user", user.Did)
292
-
// dashboard is only available to owners
293
-
ok, err := k.Enforcer.IsKnotOwner(user.Did, domain)
387
+
registration, err := db.RegistrationByDomain(k.Db, domain)
295
-
l.Error("failed to query enforcer", "err", err)
389
+
l.Error("failed to retrieve domain registration", "err", err)
299
-
http.Error(w, "only owners can view dashboards", http.StatusUnauthorized)
303
-
reg, err := db.RegistrationByDomain(k.Db, domain)
305
-
l.Error("failed to get registration by domain", "err", err)
394
+
if registration.ByDid != user.Did {
395
+
l.Error("unauthorized", "user", user.Did, "owner", registration.ByDid)
396
+
k.Pages.Notice(w, noticeId, "Failed to verify knot, unauthorized verification attempt.")
310
-
var members []string
311
-
if reg.Registered != nil {
312
-
members, err = k.Enforcer.GetUserByRole("server:member", domain)
314
-
l.Error("failed to get members list", "err", err)
400
+
// begin verification
401
+
err = serververify.RunVerification(r.Context(), domain, user.Did, k.Config.Core.Dev)
403
+
l.Error("verification failed", "err", err)
405
+
if errors.Is(err, serververify.FetchError) {
406
+
k.Pages.Notice(w, noticeId, "Failed to verify knot, unable to fetch owner.")
410
+
if e, ok := err.(*serververify.OwnerMismatch); ok {
411
+
k.Pages.Notice(w, noticeId, e.Error())
320
-
repos, err := db.GetRepos(
323
-
db.FilterEq("knot", domain),
324
-
db.FilterIn("did", members),
327
-
l.Error("failed to get repos list", "err", err)
332
-
repoByMember := make(map[string][]db.Repo)
333
-
for _, r := range repos {
334
-
repoByMember[r.Did] = append(repoByMember[r.Did], r)
337
-
var didsToResolve []string
338
-
for _, m := range members {
339
-
didsToResolve = append(didsToResolve, m)
341
-
didsToResolve = append(didsToResolve, reg.ByDid)
342
-
resolvedIds := k.IdResolver.ResolveIdents(r.Context(), didsToResolve)
343
-
didHandleMap := make(map[string]string)
344
-
for _, identity := range resolvedIds {
345
-
if !identity.Handle.IsInvalidHandle() {
346
-
didHandleMap[identity.DID.String()] = fmt.Sprintf("@%s", identity.Handle.String())
348
-
didHandleMap[identity.DID.String()] = identity.DID.String()
419
+
err = serververify.MarkKnotVerified(k.Db, k.Enforcer, domain, user.Did)
421
+
l.Error("failed to mark verified", "err", err)
422
+
k.Pages.Notice(w, noticeId, err.Error())
352
-
k.Pages.Knot(w, pages.KnotParams{
353
-
LoggedInUser: user,
354
-
DidHandleMap: didHandleMap,
357
-
Repos: repoByMember,
426
+
// add this knot to knotstream
427
+
go k.Knotstream.AddSource(
429
+
eventconsumer.NewKnotSource(domain),
362
-
// list members of domain, requires auth and requires owner status
363
-
func (k *Knots) members(w http.ResponseWriter, r *http.Request) {
364
-
l := k.Logger.With("handler", "members")
366
-
domain := chi.URLParam(r, "domain")
368
-
http.Error(w, "malformed url", http.StatusBadRequest)
432
+
shouldRefresh := r.Header.Get("shouldRefresh")
433
+
if shouldRefresh == "true" {
434
+
k.Pages.HxRefresh(w)
371
-
l = l.With("domain", domain)
373
-
// list all members for this domain
374
-
memberDids, err := k.Enforcer.GetUserByRole("server:member", domain)
438
+
// Get updated registration to show
439
+
updatedRegistration, err := db.RegistrationByDomain(k.Db, domain)
376
-
w.Write([]byte("failed to fetch member list"))
441
+
l.Error("failed get updated registration", "err", err)
442
+
k.Pages.HxRefresh(w)
380
-
w.Write([]byte(strings.Join(memberDids, "\n")))
446
+
w.Header().Set("HX-Reswap", "outerHTML")
447
+
k.Pages.KnotListing(w, pages.KnotListingParams{
448
+
Registration: *updatedRegistration,
383
-
// add member to domain, requires auth and requires invite access
func (k *Knots) addMember(w http.ResponseWriter, r *http.Request) {
385
-
l := k.Logger.With("handler", "members")
453
+
user := k.OAuth.GetUser(r)
454
+
l := k.Logger.With("handler", "addMember")
domain := chi.URLParam(r, "domain")
389
-
http.Error(w, "malformed url", http.StatusBadRequest)
458
+
l.Error("empty domain")
459
+
http.Error(w, "Not found", http.StatusNotFound)
l = l.With("domain", domain)
463
+
l = l.With("user", user.Did)
394
-
reg, err := db.RegistrationByDomain(k.Db, domain)
465
+
registration, err := db.RegistrationByDomain(k.Db, domain)
396
-
l.Error("failed to get registration by domain", "err", err)
397
-
http.Error(w, "malformed url", http.StatusBadRequest)
467
+
l.Error("failed to retrieve domain registration", "err", err)
468
+
http.Error(w, "Not found", http.StatusNotFound)
401
-
noticeId := fmt.Sprintf("add-member-error-%d", reg.Id)
402
-
l = l.With("notice-id", noticeId)
472
+
noticeId := fmt.Sprintf("add-member-error-%d", registration.Id)
defaultErr := "Failed to add member. Try again later."
k.Pages.Notice(w, noticeId, defaultErr)
408
-
subjectIdentifier := r.FormValue("subject")
409
-
if subjectIdentifier == "" {
410
-
http.Error(w, "malformed form", http.StatusBadRequest)
478
+
if registration.ByDid != user.Did {
479
+
l.Error("unauthorized", "user", user.Did, "owner", registration.ByDid)
480
+
k.Pages.Notice(w, noticeId, "Failed to add member, unauthorized attempt.")
413
-
l = l.With("subjectIdentifier", subjectIdentifier)
415
-
subjectIdentity, err := k.IdResolver.ResolveIdent(r.Context(), subjectIdentifier)
484
+
member := r.FormValue("member")
486
+
l.Error("empty member")
487
+
k.Pages.Notice(w, noticeId, "Failed to add member, empty form.")
490
+
l = l.With("member", member)
492
+
memberId, err := k.IdResolver.ResolveIdent(r.Context(), member)
417
-
l.Error("failed to resolve identity", "err", err)
494
+
l.Error("failed to resolve member identity to handle", "err", err)
495
+
k.Pages.Notice(w, noticeId, "Failed to add member, identity resolution failed.")
498
+
if memberId.Handle.IsInvalidHandle() {
499
+
l.Error("failed to resolve member identity to handle")
k.Pages.Notice(w, noticeId, "Failed to add member, identity resolution failed.")
421
-
l = l.With("subjectDid", subjectIdentity.DID)
423
-
l.Info("adding member to knot")
425
-
// announce this relation into the firehose, store into owners' pds
client, err := k.OAuth.AuthorizedClient(r)
428
-
l.Error("failed to create client", "err", err)
507
+
l.Error("failed to authorize client", "err", err)
433
-
currentUser := k.OAuth.GetUser(r)
434
-
createdAt := time.Now().Format(time.RFC3339)
435
-
resp, err := client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
514
+
_, err = client.RepoPutRecord(r.Context(), &comatproto.RepoPutRecord_Input{
Collection: tangled.KnotMemberNSID,
437
-
Repo: currentUser.Did,
Record: &lexutil.LexiconTypeDecoder{
Val: &tangled.KnotMember{
441
-
Subject: subjectIdentity.DID.String(),
520
+
CreatedAt: time.Now().Format(time.RFC3339),
443
-
CreatedAt: createdAt,
522
+
Subject: memberId.DID.String(),
448
-
l.Error("failed to write to PDS", "err", err)
527
+
l.Error("failed to add record to PDS", "err", err)
528
+
k.Pages.Notice(w, noticeId, "Failed to add record to PDS, try again later.")
532
+
err = k.Enforcer.AddKnotMember(domain, memberId.DID.String())
534
+
l.Error("failed to add member to ACLs", "err", err)
452
-
l = l.With("at-uri", resp.Uri)
453
-
l.Info("wrote record to PDS")
455
-
secret, err := db.GetRegistrationKey(k.Db, domain)
539
+
err = k.Enforcer.E.SavePolicy()
457
-
l.Error("failed to get registration key", "err", err)
541
+
l.Error("failed to save ACL policy", "err", err)
547
+
k.Pages.HxRedirect(w, fmt.Sprintf("/knots/%s", domain))
550
+
func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) {
551
+
user := k.OAuth.GetUser(r)
552
+
l := k.Logger.With("handler", "removeMember")
554
+
noticeId := "operation-error"
555
+
defaultErr := "Failed to remove member. Try again later."
557
+
k.Pages.Notice(w, noticeId, defaultErr)
560
+
domain := chi.URLParam(r, "domain")
562
+
l.Error("empty domain")
566
+
l = l.With("domain", domain)
567
+
l = l.With("user", user.Did)
462
-
ksClient, err := knotclient.NewSignedClient(domain, secret, k.Config.Core.Dev)
569
+
registration, err := db.RegistrationByDomain(k.Db, domain)
464
-
l.Error("failed to create client", "err", err)
571
+
l.Error("failed to retrieve domain registration", "err", err)
469
-
ksResp, err := ksClient.AddMember(subjectIdentity.DID.String())
576
+
if registration.ByDid != user.Did {
577
+
l.Error("unauthorized", "user", user.Did, "owner", registration.ByDid)
578
+
k.Pages.Notice(w, noticeId, "Failed to remove member, unauthorized attempt.")
582
+
member := r.FormValue("member")
584
+
l.Error("empty member")
585
+
k.Pages.Notice(w, noticeId, "Failed to remove member, empty form.")
588
+
l = l.With("member", member)
590
+
memberId, err := k.IdResolver.ResolveIdent(r.Context(), member)
471
-
l.Error("failed to reach knotserver", "err", err)
472
-
k.Pages.Notice(w, noticeId, "Failed to reach to knotserver.")
592
+
l.Error("failed to resolve member identity to handle", "err", err)
593
+
k.Pages.Notice(w, noticeId, "Failed to remove member, identity resolution failed.")
596
+
if memberId.Handle.IsInvalidHandle() {
597
+
l.Error("failed to resolve member identity to handle")
598
+
k.Pages.Notice(w, noticeId, "Failed to remove member, identity resolution failed.")
476
-
if ksResp.StatusCode != http.StatusNoContent {
477
-
l.Error("status mismatch", "got", ksResp.StatusCode, "expected", http.StatusNoContent)
478
-
k.Pages.Notice(w, noticeId, fmt.Sprintf("Unexpected status code from knotserver %d, expected %d", ksResp.StatusCode, http.StatusNoContent))
602
+
// remove from enforcer
603
+
err = k.Enforcer.RemoveKnotMember(domain, memberId.DID.String())
605
+
l.Error("failed to update ACLs", "err", err)
482
-
err = k.Enforcer.AddKnotMember(domain, subjectIdentity.DID.String())
610
+
client, err := k.OAuth.AuthorizedClient(r)
484
-
l.Error("failed to add member to enforcer", "err", err)
612
+
l.Error("failed to authorize client", "err", err)
490
-
k.Pages.HxRedirect(w, fmt.Sprintf("/knots/%s", domain))
617
+
// TODO: We need to track the rkey for knot members to delete the record
618
+
// For now, just remove from ACLs
493
-
func (k *Knots) removeMember(w http.ResponseWriter, r *http.Request) {
621
+
// commit everything
622
+
err = k.Enforcer.E.SavePolicy()
624
+
l.Error("failed to save ACLs", "err", err)
630
+
k.Pages.HxRefresh(w)