package connector import ( "context" "encoding/base64" "fmt" "io" "os" "maunium.net/go/mautrix/bridgev2" "maunium.net/go/mautrix/bridgev2/networkid" "maunium.net/go/mautrix/mediaproxy" "go.mau.fi/mautrix-signal/pkg/signalid" "go.mau.fi/mautrix-signal/pkg/signalmeow" "go.mau.fi/mautrix-signal/pkg/signalmeow/types" ) var _ bridgev2.DirectMediableNetwork = (*SignalConnector)(nil) func (s *SignalConnector) SetUseDirectMedia() { s.MsgConv.DirectMedia = true } func (s *SignalConnector) Download(ctx context.Context, mediaID networkid.MediaID, params map[string]string) (mediaproxy.GetMediaResponse, error) { log := s.Bridge.Log.With().Str("component", "direct download").Logger() info, err := signalid.ParseDirectMediaInfo(mediaID) if err != nil { return nil, fmt.Errorf("failed to parse direct media id: %w", err) } switch info := info.(type) { case *signalid.DirectMediaAttachment: log.Info(). Uint64("cdn_id", info.CDNID). Str("cdn_key", info.CDNKey). Uint32("cdn_number", info.CDNNumber). Int("key_len", len(info.Key)). Int("digest_len", len(info.Digest)). Bool("plaintext_digest", info.PlaintextDigest). Uint32("size", info.Size). Msg("Direct downloading attachment") return &mediaproxy.GetMediaResponseFile{ Callback: func(w *os.File) (*mediaproxy.FileMeta, error) { _, err := signalmeow.DownloadAttachment( ctx, info.CDNID, info.CDNKey, info.CDNNumber, info.Key, info.Digest, info.PlaintextDigest, info.Size, w, ) if err != nil { return nil, err } return &mediaproxy.FileMeta{}, nil }, }, nil case *signalid.DirectMediaGroupAvatar: log.Info(). Stringer("user_id", info.UserID). Hex("group_id", info.GroupID[:]). Str("group_avatar_path", info.GroupAvatarPath). Msg("Direct downloading group avatar") groupID := types.GroupIdentifier(base64.StdEncoding.EncodeToString(info.GroupID[:])) userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) if err != nil { return nil, fmt.Errorf("failed to get user login: %w", err) } else if userLogin == nil { return nil, bridgev2.ErrNotLoggedIn } client := userLogin.Client.(*SignalClient) groupMasterKey, err := client.Client.Store.GroupStore.MasterKeyFromGroupIdentifier(ctx, groupID) if err != nil { return nil, fmt.Errorf("failed to to get group master key: %w", err) } return &mediaproxy.GetMediaResponseCallback{ Callback: func(w io.Writer) (int64, error) { data, err := client.Client.DownloadGroupAvatar(ctx, info.GroupAvatarPath, groupMasterKey) if err != nil { log.Err(err).Msg("Direct download failed") return 0, err } _, err = w.Write(data) return int64(len(data)), err }, }, nil case *signalid.DirectMediaProfileAvatar: log.Info(). Stringer("user_id", info.UserID). Stringer("contact_id", info.ContactID). Str("profile_avatar_path", info.ProfileAvatarPath). Msg("Direct downloading profile avatar") userLogin, err := s.Bridge.GetExistingUserLoginByID(ctx, signalid.MakeUserLoginID(info.UserID)) if err != nil { return nil, fmt.Errorf("failed to get user login: %w", err) } else if userLogin == nil { return nil, bridgev2.ErrNotLoggedIn } client := userLogin.Client.(*SignalClient) profileKey, err := client.Client.Store.RecipientStore.LoadProfileKey(ctx, info.ContactID) if err != nil { return nil, fmt.Errorf("failed to get contact: %w", err) } else if profileKey == nil { return nil, fmt.Errorf("profile key not found") } return &mediaproxy.GetMediaResponseCallback{ Callback: func(w io.Writer) (int64, error) { data, err := client.Client.DownloadUserAvatar(ctx, info.ProfileAvatarPath, *profileKey) if err != nil { log.Err(err).Msg("Direct download failed") return 0, err } _, err = w.Write(data) return int64(len(data)), err }, }, nil default: return nil, fmt.Errorf("no downloader for direct media type: %T", info) } }