From a670cc4198b510a9bbceeacec049ae4b9b0702d2 Mon Sep 17 00:00:00 2001 From: Tulir Asokan Date: Mon, 17 Jun 2024 14:23:20 +0300 Subject: [PATCH] v2: add method for registering for push notifications --- go.mod | 2 +- go.sum | 4 +- pkg/connector/connector.go | 22 ++++++++++ pkg/signalmeow/pushreg.go | 82 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 107 insertions(+), 3 deletions(-) create mode 100644 pkg/signalmeow/pushreg.go diff --git a/go.mod b/go.mod index 545d155d..8a124e38 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( golang.org/x/exp v0.0.0-20240613232115-7f521ea00fb8 golang.org/x/net v0.26.0 google.golang.org/protobuf v1.34.2 - maunium.net/go/mautrix v0.19.0-beta.1 + maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa nhooyr.io/websocket v1.8.11 ) diff --git a/go.sum b/go.sum index 4667517d..436318e5 100644 --- a/go.sum +++ b/go.sum @@ -93,7 +93,7 @@ gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= maunium.net/go/mauflag v1.0.0 h1:YiaRc0tEI3toYtJMRIfjP+jklH45uDHtT80nUamyD4M= maunium.net/go/mauflag v1.0.0/go.mod h1:nLivPOpTpHnpzEh8jEdSL9UqO9+/KBJFmNRlwKfkPeA= -maunium.net/go/mautrix v0.19.0-beta.1 h1:QGqcafucRwnKv/hPc8stGqUuZYZcHJ4PyCki7shMAXA= -maunium.net/go/mautrix v0.19.0-beta.1/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa h1:9roSXY6+pcSY9jxnUprAi0gbbrUbFYcl5gAQSgNgXVs= +maunium.net/go/mautrix v0.19.0-beta.1.0.20240617115738-3828c08f27fa/go.mod h1:cxv1w6+syudmEpOewHYIQT9yO7TM5UOWmf6xEBVI4H4= nhooyr.io/websocket v1.8.11 h1:f/qXNc2/3DpoSZkHt1DQu6rj4zGC8JmkkLkWss0MgN0= nhooyr.io/websocket v1.8.11/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/pkg/connector/connector.go b/pkg/connector/connector.go index 24a2364e..3b0f44aa 100644 --- a/pkg/connector/connector.go +++ b/pkg/connector/connector.go @@ -102,6 +102,7 @@ type SignalConnector struct { var _ bridgev2.NetworkConnector = (*SignalConnector)(nil) var _ bridgev2.MaxFileSizeingNetwork = (*SignalConnector)(nil) var _ bridgev2.NetworkAPI = (*SignalClient)(nil) +var _ bridgev2.PushableNetworkAPI = (*SignalClient)(nil) var _ msgconv.PortalMethods = (*msgconvPortalMethods)(nil) func NewConnector() *SignalConnector { @@ -232,6 +233,27 @@ type SignalClient struct { Client *signalmeow.Client } +var pushCfg = &bridgev2.PushConfig{ + FCM: &bridgev2.FCMPushConfig{ + // https://github.com/signalapp/Signal-Android/blob/main/app/src/main/res/values/firebase_messaging.xml#L4 + SenderID: "312334754206", + }, + APNs: &bridgev2.APNsPushConfig{ + BundleID: "org.whispersystems.signal", + }, +} + +func (s *SignalClient) GetPushConfigs() *bridgev2.PushConfig { + return pushCfg +} + +func (s *SignalClient) RegisterPushNotifications(ctx context.Context, pushType bridgev2.PushType, token string) error { + if pushType != bridgev2.PushTypeFCM { + return fmt.Errorf("unsupported push type: %s", pushType) + } + return s.Client.RegisterFCM(ctx, token) +} + func (s *SignalClient) LogoutRemote(ctx context.Context) { err := s.Client.StopReceiveLoops() if err != nil { diff --git a/pkg/signalmeow/pushreg.go b/pkg/signalmeow/pushreg.go new file mode 100644 index 00000000..fe457855 --- /dev/null +++ b/pkg/signalmeow/pushreg.go @@ -0,0 +1,82 @@ +// mautrix-signal - A Matrix-signal puppeting bridge. +// Copyright (C) 2024 Tulir Asokan +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. +// +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . + +package signalmeow + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + + "go.mau.fi/mautrix-signal/pkg/signalmeow/web" +) + +type ReqRegisterFCM struct { + GCMRegistrationID string `json:"gcmRegistrationId,omitempty"` + WebSocketChannel bool `json:"webSocketChannel"` +} + +type ReqRegisterAPNs struct { + APNRegistrationID string `json:"apnRegistrationId,omitempty"` + VoIPRegistrationID string `json:"voipRegistrationId,omitempty"` +} + +func (cli *Client) registerPush(ctx context.Context, pushType string, data any) error { + username, password := cli.Store.BasicAuthCreds() + req := &web.HTTPReqOpt{ + Username: &username, + Password: &password, + } + var method string + if data != nil { + method = http.MethodPut + req.ContentType = web.ContentTypeJSON + var err error + req.Body, err = json.Marshal(data) + if err != nil { + return err + } + } else { + method = http.MethodDelete + } + resp, err := web.SendHTTPRequest(ctx, method, "/v1/accounts/"+pushType, req) + if err != nil { + return err + } else if resp.StatusCode >= 300 || resp.StatusCode < 200 { + return fmt.Errorf("unexpected status code %d", resp.StatusCode) + } + return nil +} + +func (cli *Client) RegisterFCM(ctx context.Context, token string) error { + if token == "" { + return cli.registerPush(ctx, "gcm", nil) + } + return cli.registerPush(ctx, "gcm", &ReqRegisterFCM{ + GCMRegistrationID: token, + WebSocketChannel: true, + }) +} + +func (cli *Client) RegisterAPNs(ctx context.Context, token string) error { + if token == "" { + return cli.registerPush(ctx, "apn", nil) + } + return cli.registerPush(ctx, "apn", &ReqRegisterAPNs{ + APNRegistrationID: token, + }) +}