166 lines
3.7 KiB
Go
166 lines
3.7 KiB
Go
// 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 <https://www.gnu.org/licenses/>.
|
|
|
|
package libsignalgo
|
|
|
|
/*
|
|
#cgo LDFLAGS: -lsignal_ffi -ldl -lm
|
|
#include "./libsignal-ffi.h"
|
|
#include <stdlib.h>
|
|
*/
|
|
import "C"
|
|
import (
|
|
"database/sql/driver"
|
|
"fmt"
|
|
"strings"
|
|
"unsafe"
|
|
|
|
"github.com/google/uuid"
|
|
"github.com/rs/zerolog"
|
|
)
|
|
|
|
func init() {
|
|
if C.SignalUUID_LEN != 16 {
|
|
panic("libsignal-ffi uuid type size mismatch")
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
var EmptyServiceID ServiceID
|
|
|
|
func NewPNIServiceID(uuid uuid.UUID) ServiceID {
|
|
return ServiceID{
|
|
Type: ServiceIDTypePNI,
|
|
UUID: uuid,
|
|
}
|
|
}
|
|
|
|
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
|
|
}
|
|
}
|
|
|
|
func (s ServiceID) IsEmpty() bool {
|
|
return s.UUID == uuid.Nil
|
|
}
|
|
|
|
func (s ServiceID) Address(deviceID uint) (*Address, error) {
|
|
return newAddress(s.String(), deviceID)
|
|
}
|
|
|
|
func (s ServiceID) Bytes() []byte {
|
|
if s.Type == ServiceIDTypeACI {
|
|
return s.UUID[:]
|
|
}
|
|
return append([]byte{byte(s.Type)}, s.UUID[:]...)
|
|
}
|
|
|
|
func (s ServiceID) Value() (driver.Value, error) {
|
|
return s.String(), nil
|
|
}
|
|
|
|
func (s ServiceID) String() string {
|
|
if s.Type == ServiceIDTypeACI {
|
|
return s.UUID.String()
|
|
}
|
|
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) MarshalZerologObject(e *zerolog.Event) {
|
|
e.Stringer("type", s.Type)
|
|
e.Stringer("uuid", s.UUID)
|
|
}
|
|
|
|
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 {
|
|
return EmptyServiceID, fmt.Errorf("invalid UUID string: %s", val)
|
|
}
|
|
if strings.ToUpper(val[:4]) == "PNI:" {
|
|
parsed, err := uuid.Parse(val[4:])
|
|
if err != nil {
|
|
return EmptyServiceID, err
|
|
}
|
|
return NewPNIServiceID(parsed), nil
|
|
} else {
|
|
parsed, err := uuid.Parse(val)
|
|
if err != nil {
|
|
return EmptyServiceID, err
|
|
}
|
|
return NewACIServiceID(parsed), nil
|
|
}
|
|
}
|
|
|
|
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()))
|
|
}
|