mirror of
https://github.com/twofas/2fas-server.git
synced 2024-12-04 16:20:13 +01:00
parent
bc22800bf4
commit
7bf9bfb906
@ -156,16 +156,19 @@ func browserExtensionRequestSync(token string) (RequestSyncResponse, error) {
|
||||
return resp, nil
|
||||
}
|
||||
|
||||
func browserExtensionPushToMobile(token string) error {
|
||||
func browserExtensionPush(token, body string) (string, error) {
|
||||
var resp struct {
|
||||
Response string `json:"response"`
|
||||
}
|
||||
req := struct {
|
||||
Body string `json:"push_body"`
|
||||
}{
|
||||
Body: "sent from browser extension",
|
||||
}
|
||||
resp := struct{}{}
|
||||
if err := request("POST", "/browser_extension/sync/push", token, req, &resp); err != nil {
|
||||
return fmt.Errorf("failed to configure browser: %w", err)
|
||||
Body: body,
|
||||
}
|
||||
|
||||
return nil
|
||||
if err := request("POST", "/browser_extension/sync/push", token, req, &resp); err != nil {
|
||||
return "", fmt.Errorf("failed to send push notification: %w", err)
|
||||
}
|
||||
|
||||
return resp.Response, nil
|
||||
}
|
||||
|
@ -33,6 +33,13 @@ func TestSyncHappyFlow(t *testing.T) {
|
||||
return
|
||||
}
|
||||
|
||||
pushResp, err := browserExtensionPush(requestSyncResp.BrowserExtensionWaitToken, "body")
|
||||
if err != nil {
|
||||
t.Errorf("Error when Browser Extension tried to send push notification: %v", err)
|
||||
return
|
||||
}
|
||||
t.Logf("Push response: %v", pushResp)
|
||||
|
||||
confirmMobileChannel <- requestSyncResp.MobileConfirmToken
|
||||
|
||||
proxyToken, err := browserExtensionWaitForSyncConfirm(requestSyncResp.BrowserExtensionWaitToken)
|
||||
|
@ -9,7 +9,7 @@ import (
|
||||
)
|
||||
|
||||
func main() {
|
||||
addrFlag := flag.String("addr", ":80;:8081;:8082", "list of addresses to check sep by ;")
|
||||
addrFlag := flag.String("addr", ":80;:8081;:8082;:8088", "list of addresses to check sep by ;")
|
||||
flag.Parse()
|
||||
|
||||
addresses := strings.Split(*addrFlag, ";")
|
||||
|
72
internal/pass/fcm/client.go
Normal file
72
internal/pass/fcm/client.go
Normal file
@ -0,0 +1,72 @@
|
||||
package fcm
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
firebase "firebase.google.com/go/v4"
|
||||
"firebase.google.com/go/v4/messaging"
|
||||
"google.golang.org/api/option"
|
||||
|
||||
"github.com/twofas/2fas-server/internal/common/logging"
|
||||
)
|
||||
|
||||
// Response is returned from firebsase for push request.
|
||||
type Response string
|
||||
|
||||
type Client interface {
|
||||
Send(ctx context.Context, message *messaging.Message) (Response, error)
|
||||
}
|
||||
|
||||
type client struct {
|
||||
FcmMessaging *messaging.Client
|
||||
}
|
||||
|
||||
func NewClient(ctx context.Context, credentials string) (*client, error) {
|
||||
opt := option.WithCredentialsJSON([]byte(credentials))
|
||||
app, err := firebase.NewApp(ctx, nil, opt)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create firebase app: %w", err)
|
||||
}
|
||||
fcmClient, err := app.Messaging(ctx)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to create fcm client: %w", err)
|
||||
}
|
||||
return &client{FcmMessaging: fcmClient}, nil
|
||||
}
|
||||
|
||||
func (c *client) Send(ctx context.Context, message *messaging.Message) (Response, error) {
|
||||
contextWithTimeout, cancel := context.WithTimeout(ctx, 20*time.Second)
|
||||
defer cancel()
|
||||
|
||||
logging.FromContext(ctx).Info()
|
||||
|
||||
response, err := c.FcmMessaging.Send(contextWithTimeout, message)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to send push message: %w", err)
|
||||
}
|
||||
|
||||
return Response(response), nil
|
||||
}
|
||||
|
||||
type FakePushClient struct {
|
||||
}
|
||||
|
||||
func NewFakePushClient() *FakePushClient {
|
||||
return &FakePushClient{}
|
||||
}
|
||||
|
||||
func (p *FakePushClient) Send(ctx context.Context, message *messaging.Message) (Response, error) {
|
||||
data, err := json.Marshal(message)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("failed to marshal message: %w", err)
|
||||
}
|
||||
|
||||
logging.WithFields(logging.Fields{
|
||||
"notification": string(data),
|
||||
}).Debug("Sending fake push notifications")
|
||||
|
||||
return "ok", nil
|
||||
}
|
@ -4,18 +4,16 @@ import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
firebase "firebase.google.com/go/v4"
|
||||
"firebase.google.com/go/v4/messaging"
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
"github.com/aws/aws-sdk-go/service/kms"
|
||||
"github.com/gin-gonic/gin"
|
||||
"google.golang.org/api/option"
|
||||
|
||||
"github.com/twofas/2fas-server/config"
|
||||
httphelpers "github.com/twofas/2fas-server/internal/common/http"
|
||||
"github.com/twofas/2fas-server/internal/common/recovery"
|
||||
"github.com/twofas/2fas-server/internal/pass/connection"
|
||||
"github.com/twofas/2fas-server/internal/pass/fcm"
|
||||
"github.com/twofas/2fas-server/internal/pass/pairing"
|
||||
"github.com/twofas/2fas-server/internal/pass/sign"
|
||||
"github.com/twofas/2fas-server/internal/pass/sync"
|
||||
@ -55,25 +53,20 @@ func NewServer(cfg config.PassConfig) *Server {
|
||||
}
|
||||
|
||||
ctx := context.Background()
|
||||
var fcmClient *messaging.Client
|
||||
var fcmClient fcm.Client
|
||||
if cfg.FirebaseServiceAccount != "" {
|
||||
opt := option.WithCredentialsJSON([]byte(cfg.FirebaseServiceAccount))
|
||||
app, err := firebase.NewApp(ctx, nil, opt)
|
||||
if err != nil {
|
||||
log.Fatalf("Error initializing FCM App: %v", err)
|
||||
}
|
||||
fcmClient, err = app.Messaging(ctx)
|
||||
fcmClient, err = fcm.NewClient(ctx, cfg.FirebaseServiceAccount)
|
||||
if err != nil {
|
||||
log.Fatalf("Error initializing Messaging Client: %v", err)
|
||||
}
|
||||
} else {
|
||||
fcmClient = fcm.NewFakePushClient()
|
||||
}
|
||||
// TODO: use client in later phase.
|
||||
_ = fcmClient
|
||||
|
||||
pairingApp := pairing.NewApp(signSvc, cfg.PairingRequestTokenValidityDuration)
|
||||
proxyPairingApp := connection.NewProxyServer("device_id")
|
||||
|
||||
syncApp := sync.NewApp(signSvc, cfg.FakeMobilePush)
|
||||
syncApp := sync.NewApp(signSvc, fcmClient)
|
||||
proxySyncApp := connection.NewProxyServer("fcm_token")
|
||||
|
||||
router := gin.New()
|
||||
|
@ -64,9 +64,16 @@ func ExtensionRequestPush(syncingApp *Syncing) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
log.Infof("Send push to mobile %q: %q", fcmToken, req.Body)
|
||||
resp, err := syncingApp.SendPush(gCtx, fcmToken, req.Body)
|
||||
if err != nil {
|
||||
log.Errorf("Failed to send push message: %v", err)
|
||||
gCtx.Status(http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
gCtx.Status(http.StatusOK)
|
||||
gCtx.JSON(http.StatusOK, map[string]string{
|
||||
"response": string(resp),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ func (s *MemoryStore) ConfirmSync(fcmToken string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func (s *MemoryStore) IsSyncCofirmed(fcmToken string) bool {
|
||||
func (s *MemoryStore) IsSyncConfirmed(fcmToken string) bool {
|
||||
v, ok := s.getItem(fcmToken)
|
||||
if !ok {
|
||||
return false
|
||||
|
@ -7,29 +7,33 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"firebase.google.com/go/v4/messaging"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/gorilla/websocket"
|
||||
|
||||
"github.com/twofas/2fas-server/internal/common/logging"
|
||||
"github.com/twofas/2fas-server/internal/pass/connection"
|
||||
"github.com/twofas/2fas-server/internal/pass/fcm"
|
||||
"github.com/twofas/2fas-server/internal/pass/sign"
|
||||
)
|
||||
|
||||
type Syncing struct {
|
||||
store store
|
||||
signSvc *sign.Service
|
||||
store store
|
||||
signSvc *sign.Service
|
||||
fcmClient fcm.Client
|
||||
}
|
||||
|
||||
type store interface {
|
||||
RequestSync(fmtToken string)
|
||||
ConfirmSync(fmtToken string) bool
|
||||
IsSyncCofirmed(fmtToken string) bool
|
||||
RequestSync(fcmToken string)
|
||||
ConfirmSync(fcmToken string) bool
|
||||
IsSyncConfirmed(fcmToken string) bool
|
||||
}
|
||||
|
||||
func NewApp(signService *sign.Service, fakeMobilePush bool) *Syncing {
|
||||
func NewApp(signService *sign.Service, fcmClient fcm.Client) *Syncing {
|
||||
return &Syncing{
|
||||
store: NewMemoryStore(),
|
||||
signSvc: signService,
|
||||
store: NewMemoryStore(),
|
||||
signSvc: signService,
|
||||
fcmClient: fcmClient,
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,7 +100,7 @@ func (s *Syncing) ServeSyncingRequestWS(w http.ResponseWriter, r *http.Request,
|
||||
}
|
||||
|
||||
func (s *Syncing) isSyncConfirmed(ctx context.Context, fcmToken string) bool {
|
||||
return s.store.IsSyncCofirmed(fcmToken)
|
||||
return s.store.IsSyncConfirmed(fcmToken)
|
||||
}
|
||||
|
||||
func (s *Syncing) requestSync(ctx context.Context, fcmToken string) {
|
||||
@ -178,3 +182,18 @@ func (s *Syncing) RequestSync(ctx *gin.Context, token string) (RequestSyncRespon
|
||||
MobileConfirmToken: mobileConfirmToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Syncing) SendPush(ctx *gin.Context, token string, body string) (fcm.Response, error) {
|
||||
msg := &messaging.Message{
|
||||
Token: token,
|
||||
Android: &messaging.AndroidConfig{
|
||||
Notification: &messaging.AndroidNotification{
|
||||
Title: "2pass push request",
|
||||
},
|
||||
Data: map[string]string{
|
||||
"data": body,
|
||||
},
|
||||
},
|
||||
}
|
||||
return s.fcmClient.Send(ctx, msg)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user