telegabber/e2ee/omemo/libsignal/callbacks.go
2026-07-28 00:38:46 -04:00

293 lines
7.5 KiB
Go

package libsignal
/*
#include <signal_protocol.h>
*/
import "C"
import (
"runtime/cgo"
"unsafe"
)
// storeFromUserData recovers the Store bound to a StoreContext from the
// cgo.Handle round-tripped through the vtable's void *user_data (see
// store.go's NewStoreContext, which is the only place that creates such a
// handle).
func storeFromUserData(userData unsafe.Pointer) (Store, bool) {
if userData == nil {
return nil, false
}
s, ok := cgo.Handle(uintptr(userData)).Value().(Store)
return s, ok
}
// ---- identity key store ----
//export go_get_identity_key_pair
func go_get_identity_key_pair(publicData, privateData **C.signal_buffer, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
pub, priv, err := store.GetIdentityKeyPair()
if err != nil {
return C.int(ErrUnknown)
}
*publicData = bytesToBuffer(pub)
*privateData = bytesToBuffer(priv)
return C.SG_SUCCESS
}
//export go_get_local_registration_id
func go_get_local_registration_id(userData unsafe.Pointer, registrationID *C.uint32_t) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
id, err := store.GetLocalRegistrationID()
if err != nil {
return C.int(ErrUnknown)
}
*registrationID = C.uint32_t(id)
return C.SG_SUCCESS
}
//export go_save_identity
func go_save_identity(address *C.signal_protocol_address, keyData *C.uint8_t, keyLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.SaveIdentity(addressFromC(address), cBytesToGo(keyData, keyLen)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_is_trusted_identity
func go_is_trusted_identity(address *C.signal_protocol_address, keyData *C.uint8_t, keyLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
trusted, err := store.IsTrustedIdentity(addressFromC(address), cBytesToGo(keyData, keyLen))
if err != nil {
return C.int(ErrUnknown)
}
if trusted {
return 1
}
return 0
}
//export go_identity_destroy
func go_identity_destroy(userData unsafe.Pointer) {}
// ---- pre key store ----
//export go_load_pre_key
func go_load_pre_key(record **C.signal_buffer, preKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
data, found, err := store.LoadPreKey(uint32(preKeyID))
if err != nil {
return C.int(ErrUnknown)
}
if !found {
return C.int(ErrInvalidKeyID)
}
*record = bytesToBuffer(data)
return C.SG_SUCCESS
}
//export go_store_pre_key
func go_store_pre_key(preKeyID C.uint32_t, record *C.uint8_t, recordLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.StorePreKey(uint32(preKeyID), cBytesToGo(record, recordLen)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_contains_pre_key
func go_contains_pre_key(preKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return 0
}
if store.ContainsPreKey(uint32(preKeyID)) {
return 1
}
return 0
}
//export go_remove_pre_key
func go_remove_pre_key(preKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.RemovePreKey(uint32(preKeyID)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_pre_key_destroy
func go_pre_key_destroy(userData unsafe.Pointer) {}
// ---- signed pre key store ----
//export go_load_signed_pre_key
func go_load_signed_pre_key(record **C.signal_buffer, signedPreKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
data, found, err := store.LoadSignedPreKey(uint32(signedPreKeyID))
if err != nil {
return C.int(ErrUnknown)
}
if !found {
return C.int(ErrInvalidKeyID)
}
*record = bytesToBuffer(data)
return C.SG_SUCCESS
}
//export go_store_signed_pre_key
func go_store_signed_pre_key(signedPreKeyID C.uint32_t, record *C.uint8_t, recordLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.StoreSignedPreKey(uint32(signedPreKeyID), cBytesToGo(record, recordLen)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_contains_signed_pre_key
func go_contains_signed_pre_key(signedPreKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return 0
}
if store.ContainsSignedPreKey(uint32(signedPreKeyID)) {
return 1
}
return 0
}
//export go_remove_signed_pre_key
func go_remove_signed_pre_key(signedPreKeyID C.uint32_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.RemoveSignedPreKey(uint32(signedPreKeyID)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_signed_pre_key_destroy
func go_signed_pre_key_destroy(userData unsafe.Pointer) {}
// ---- session store ----
//export go_load_session
func go_load_session(record, userRecord **C.signal_buffer, address *C.signal_protocol_address, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
data, found, err := store.LoadSession(addressFromC(address))
if err != nil {
return C.int(ErrUnknown)
}
if !found {
return 0
}
*record = bytesToBuffer(data)
return 1
}
//export go_get_sub_device_sessions
func go_get_sub_device_sessions(sessions **C.signal_int_list, name *C.char, nameLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
deviceIDs, err := store.GetSubDeviceSessions(C.GoStringN(name, C.int(nameLen)))
if err != nil {
return C.int(ErrUnknown)
}
list := C.signal_int_list_alloc()
if list == nil {
return C.int(ErrNoMemory)
}
for _, id := range deviceIDs {
C.signal_int_list_push_back(list, C.int(id))
}
*sessions = list
return C.int(len(deviceIDs))
}
//export go_store_session
func go_store_session(address *C.signal_protocol_address, record *C.uint8_t, recordLen C.size_t, userRecord *C.uint8_t, userRecordLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.StoreSession(addressFromC(address), cBytesToGo(record, recordLen)); err != nil {
return C.int(ErrUnknown)
}
return C.SG_SUCCESS
}
//export go_contains_session
func go_contains_session(address *C.signal_protocol_address, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return 0
}
if store.ContainsSession(addressFromC(address)) {
return 1
}
return 0
}
//export go_delete_session
func go_delete_session(address *C.signal_protocol_address, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
if err := store.DeleteSession(addressFromC(address)); err != nil {
return C.int(ErrUnknown)
}
return 1
}
//export go_delete_all_sessions
func go_delete_all_sessions(name *C.char, nameLen C.size_t, userData unsafe.Pointer) C.int {
store, ok := storeFromUserData(userData)
if !ok {
return C.int(ErrUnknown)
}
count, err := store.DeleteAllSessions(C.GoStringN(name, C.int(nameLen)))
if err != nil {
return C.int(ErrUnknown)
}
return C.int(count)
}
//export go_session_destroy
func go_session_destroy(userData unsafe.Pointer) {}