// SPDX-License-Identifier: AGPL-3.0-or-later package fcm import ( "context" "encoding/base64" firebase "firebase.google.com/go/v4" "firebase.google.com/go/v4/messaging" "google.golang.org/api/option" ) type Sender struct { client *messaging.Client } func New(ctx context.Context, keyPath string) (*Sender, error) { app, err := firebase.NewApp(ctx, nil, option.WithCredentialsFile(keyPath)) if err != nil { return nil, err } mc, err := app.Messaging(ctx) if err != nil { return nil, err } return &Sender{client: mc}, nil } // SendCiphertext delivers a ciphertext to a single FCM token as a data-only // push (no `notification` field) so the phone decrypts and renders locally — // Google never sees plaintext. func (s *Sender) SendCiphertext(ctx context.Context, fcmToken string, ciphertext []byte) error { msg := &messaging.Message{ Token: fcmToken, Data: map[string]string{ "ciphertext": base64.StdEncoding.EncodeToString(ciphertext), }, Android: &messaging.AndroidConfig{ Priority: "high", }, } _, err := s.client.Send(ctx, msg) return err }