1
0
Fork 0
mirror of https://github.com/mautrix/signal.git synced 2026-05-15 05:36:53 -04:00
mautrix-signal/pkg/libsignalgo/serviceid.go

186 lines
4.3 KiB
Go
Raw Permalink Normal View History

2023-12-17 15:54:35 +02:00
// mautrix-signal - A Matrix-signal puppeting bridge.
2024-03-15 15:30:44 +02:00
// Copyright (C) 2024 Tulir Asokan
2023-12-17 15:54:35 +02:00
//
// 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 <https://www.gnu.org/licenses/>.
package libsignalgo
/*
#include "./libsignal-ffi.h"
#include <stdlib.h>
*/
import "C"
import (
"database/sql/driver"
"fmt"
2024-03-15 15:30:44 +02:00
"strings"
"unsafe"
2023-12-22 14:47:07 +02:00
"github.com/google/uuid"
"github.com/rs/zerolog"
)
2024-03-15 15:30:44 +02:00
type ServiceIDType byte
const (
ServiceIDTypeACI ServiceIDType = 0
ServiceIDTypePNI ServiceIDType = 1
)
func (st ServiceIDType) String() string {
switch st {
case ServiceIDTypeACI:
return "ACI"
case ServiceIDTypePNI:
return "PNI"
default:
panic(fmt.Sprintf("invalid ServiceIDType: %d", st))
}
}
func (st ServiceIDType) GoString() string {
return fmt.Sprintf("libsignalgo.ServiceIDType%s", st.String())
}
type ServiceID struct {
Type ServiceIDType
UUID uuid.UUID
}
2024-03-22 15:37:21 +02:00
var EmptyServiceID ServiceID
2024-03-15 15:30:44 +02:00
func NewPNIServiceID(uuid uuid.UUID) ServiceID {
return ServiceID{
Type: ServiceIDTypePNI,
UUID: uuid,
}
}
2024-03-15 15:30:44 +02:00
func NewACIServiceID(uuid uuid.UUID) ServiceID {
return ServiceID{
Type: ServiceIDTypeACI,
UUID: uuid,
}
}
func (s ServiceID) ToACIAndPNI() (aci, pni uuid.UUID) {
if s.Type == ServiceIDTypeACI {
return s.UUID, uuid.Nil
} else {
return uuid.Nil, s.UUID
}
}
2024-03-22 15:37:21 +02:00
func (s ServiceID) IsEmpty() bool {
return s.UUID == uuid.Nil
}
2024-03-15 15:30:44 +02:00
func (s ServiceID) Address(deviceID uint) (*Address, error) {
if s.IsEmpty() {
return nil, fmt.Errorf("cannot create address from empty ServiceID")
}
2024-03-15 15:30:44 +02:00
return newAddress(s.String(), deviceID)
}
func (s ServiceID) Bytes() []byte {
if s.Type == ServiceIDTypeACI {
return s.UUID[:]
2023-12-22 14:47:07 +02:00
}
2024-03-15 15:30:44 +02:00
return append([]byte{byte(s.Type)}, s.UUID[:]...)
}
func (s ServiceID) Value() (driver.Value, error) {
return s.String(), nil
}
2024-03-15 15:30:44 +02:00
func (s ServiceID) String() string {
if s.Type == ServiceIDTypeACI {
return s.UUID.String()
}
2024-03-15 15:30:44 +02:00
return fmt.Sprintf("%s:%s", s.Type, s.UUID)
}
func (s ServiceID) GoString() string {
return fmt.Sprintf(`libsignalgo.ServiceID{Type: %#v, UUID: uuid.MustParse("%s")}`, s.Type, s.UUID)
}
func (s ServiceID) MarshalText() ([]byte, error) {
return []byte(s.String()), nil
}
func (s *ServiceID) UnmarshalText(text []byte) error {
parsed, err := ServiceIDFromString(string(text))
if err != nil {
return err
}
*s = parsed
return nil
}
func (s ServiceID) MarshalZerologObject(e *zerolog.Event) {
e.Stringer("type", s.Type)
e.Stringer("uuid", s.UUID)
}
2024-03-15 15:30:44 +02:00
type ServiceIDFixedBytes [17]byte
func (s ServiceID) FixedBytes() *ServiceIDFixedBytes {
var result ServiceIDFixedBytes
result[0] = byte(s.Type)
copy(result[1:], s.UUID[:])
return &result
}
func ServiceIDFromString(val string) (ServiceID, error) {
if len(val) < 36 {
2024-03-22 15:37:21 +02:00
return EmptyServiceID, fmt.Errorf("invalid UUID string: %s", val)
2024-03-15 15:30:44 +02:00
}
if strings.ToUpper(val[:4]) == "PNI:" {
parsed, err := uuid.Parse(val[4:])
if err != nil {
2024-03-22 15:37:21 +02:00
return EmptyServiceID, err
2024-03-15 15:30:44 +02:00
}
return NewPNIServiceID(parsed), nil
} else {
parsed, err := uuid.Parse(val)
if err != nil {
2024-03-22 15:37:21 +02:00
return EmptyServiceID, err
2024-03-15 15:30:44 +02:00
}
return NewACIServiceID(parsed), nil
}
}
func ServiceIDFromBytes(bytes []byte) (ServiceID, error) {
if len(bytes) == 16 {
return NewACIServiceID(uuid.UUID(bytes)), nil
} else if len(bytes) == 17 {
return ServiceID{
Type: ServiceIDType(bytes[0]),
UUID: uuid.UUID(bytes[1:]),
}, nil
}
return EmptyServiceID, fmt.Errorf("invalid ServiceID byte length: %d (expected 16 or 17)", len(bytes))
}
2024-03-15 15:30:44 +02:00
func ServiceIDFromCFixedBytes(serviceID *C.SignalServiceIdFixedWidthBinaryBytes) ServiceID {
var id ServiceID
fixedBytes := (*ServiceIDFixedBytes)(unsafe.Pointer(serviceID))
id.Type = ServiceIDType(fixedBytes[0])
copy(id.UUID[:], fixedBytes[1:])
return id
}
func (s ServiceID) CFixedBytes() cPNIType {
return cPNIType(unsafe.Pointer(s.FixedBytes()))
}