2021-03-24 17:31:37 +00:00
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
2021-03-17 09:46:05 +00:00
|
|
|
package signinwithssb
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"encoding/base64"
|
|
|
|
"encoding/json"
|
|
|
|
"fmt"
|
2021-03-24 17:31:37 +00:00
|
|
|
"strings"
|
2021-03-17 09:46:05 +00:00
|
|
|
|
|
|
|
kitlog "github.com/go-kit/kit/log"
|
|
|
|
"go.cryptoscope.co/muxrpc/v2"
|
|
|
|
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/internal/network"
|
2021-03-24 15:52:58 +00:00
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/internal/signinwithssb"
|
2021-03-17 09:46:05 +00:00
|
|
|
validate "github.com/ssb-ngi-pointer/go-ssb-room/internal/signinwithssb"
|
|
|
|
"github.com/ssb-ngi-pointer/go-ssb-room/roomdb"
|
|
|
|
refs "go.mindeco.de/ssb-refs"
|
|
|
|
)
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// Handler implements the muxrpc methods for the "Sign-in with SSB" calls. SendSolution and InvalidateAllSolutions.
|
2021-03-17 09:46:05 +00:00
|
|
|
type Handler struct {
|
|
|
|
logger kitlog.Logger
|
|
|
|
self refs.FeedRef
|
|
|
|
|
|
|
|
sessions roomdb.AuthWithSSBService
|
|
|
|
members roomdb.MembersService
|
|
|
|
|
2021-03-24 15:52:58 +00:00
|
|
|
bridge *signinwithssb.SignalBridge
|
|
|
|
|
2021-03-17 09:46:05 +00:00
|
|
|
roomDomain string // the http(s) domain of the room to signal redirect addresses
|
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// New returns the muxrpc handler for Sign-in with SSB
|
2021-03-17 09:46:05 +00:00
|
|
|
func New(
|
|
|
|
log kitlog.Logger,
|
|
|
|
self refs.FeedRef,
|
2021-03-24 15:52:58 +00:00
|
|
|
roomDomain string,
|
2021-03-17 09:46:05 +00:00
|
|
|
membersdb roomdb.MembersService,
|
2021-03-24 15:52:58 +00:00
|
|
|
sessiondb roomdb.AuthWithSSBService,
|
|
|
|
bridge *signinwithssb.SignalBridge,
|
|
|
|
) Handler {
|
2021-03-17 09:46:05 +00:00
|
|
|
|
|
|
|
var h Handler
|
|
|
|
h.self = self
|
|
|
|
h.roomDomain = roomDomain
|
|
|
|
h.logger = log
|
|
|
|
h.sessions = sessiondb
|
|
|
|
h.members = membersdb
|
2021-03-24 15:52:58 +00:00
|
|
|
h.bridge = bridge
|
2021-03-17 09:46:05 +00:00
|
|
|
|
|
|
|
return h
|
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// SendSolution implements the receiving end of httpAuth.sendSolution.
|
|
|
|
// It recevies three parameters [sc, cc, sol], does the validation and if it passes creates a token
|
|
|
|
// and signals the created token to the SSE HTTP handler using the signal bridge.
|
2021-03-17 09:46:05 +00:00
|
|
|
func (h Handler) SendSolution(ctx context.Context, req *muxrpc.Request) (interface{}, error) {
|
|
|
|
clientID, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-24 15:52:58 +00:00
|
|
|
member, err := h.members.GetByFeed(ctx, *clientID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("client is not a room member")
|
|
|
|
}
|
|
|
|
|
2021-03-17 09:46:05 +00:00
|
|
|
var params []string
|
|
|
|
if err := json.Unmarshal(req.RawArgs, ¶ms); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if n := len(params); n != 3 {
|
|
|
|
return nil, fmt.Errorf("expected 3 arguments (sc, cc, sol) but got %d", n)
|
|
|
|
}
|
|
|
|
|
|
|
|
var sol validate.ClientRequest
|
|
|
|
sol.ServerID = h.self
|
|
|
|
sol.ServerChallenge = params[0]
|
|
|
|
sol.ClientID = *clientID
|
|
|
|
sol.ClientChallenge = params[1]
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
sig, err := base64.StdEncoding.DecodeString(strings.TrimSuffix(params[2], ".sig.ed25519"))
|
2021-03-17 09:46:05 +00:00
|
|
|
if err != nil {
|
2021-03-24 15:52:58 +00:00
|
|
|
h.bridge.CompleteSession(sol.ServerChallenge, false, "")
|
|
|
|
return nil, fmt.Errorf("signature is not valid base64 data: %w", err)
|
2021-03-17 09:46:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if !sol.Validate(sig) {
|
2021-03-24 15:52:58 +00:00
|
|
|
h.bridge.CompleteSession(sol.ServerChallenge, false, "")
|
2021-03-17 09:46:05 +00:00
|
|
|
return nil, fmt.Errorf("not a valid solution")
|
|
|
|
}
|
|
|
|
|
2021-03-24 15:52:58 +00:00
|
|
|
tok, err := h.sessions.CreateToken(ctx, member.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-03-17 09:46:05 +00:00
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
err = h.bridge.CompleteSession(sol.ServerChallenge, true, tok)
|
|
|
|
if err != nil {
|
|
|
|
h.sessions.RemoveToken(ctx, tok)
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-24 15:52:58 +00:00
|
|
|
return true, nil
|
2021-03-17 09:46:05 +00:00
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// InvalidateAllSolutions implements the muxrpc call httpAuth.invalidateAllSolutions
|
2021-03-17 09:46:05 +00:00
|
|
|
func (h Handler) InvalidateAllSolutions(ctx context.Context, req *muxrpc.Request) (interface{}, error) {
|
|
|
|
// get the feed from the muxrpc connection
|
|
|
|
clientID, err := network.GetFeedRefFromAddr(req.RemoteAddr())
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// lookup the member
|
2021-03-17 09:46:05 +00:00
|
|
|
member, err := h.members.GetByFeed(ctx, *clientID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2021-03-24 17:31:37 +00:00
|
|
|
// delete all SIWSSB sessions of that member
|
2021-03-17 09:46:05 +00:00
|
|
|
err = h.sessions.WipeTokensForMember(ctx, member.ID)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return true, nil
|
|
|
|
}
|