textsecure

package module
v1.1.24 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 26, 2024 License: GPL-3.0 Imports: 53 Imported by: 0

README

TextSecure library and command line test client for Go

This is a Go package implementing the TextSecure push data (i.e. not encrypted SMS) protocol v3 including the Axolotl ratchet.

The included sample command line app can send and receive text messages and attachments and supports group chat.

The API presented by the package is in flux, mainly driven by the needs of https://github.com/nanu-c/axolotl

Automatically generated documentation can be found on GoDoc

Installation

This command will install both the library and the test client.

go get git.yawal.io/imran/textsecurecli/cmd/textsecure

textsecure also depends on crayfish which is a Go library for interacting with the upstream libsignal-client library. It's currently used for registration and decryption of messages. libzkgroup is used for the groupv2 protocol and is add by [this go wrapper] (https://github.com/nanu-c/zkgroup). It has to be added to the LD_LIBRARY_PATH environment variable. Crayfish is built with cago build and has to be placed next to the textsecure binary.

Configuration

Copy cmd/textsecure/.config to a directory and modify it, then run the tool from that directory. It will create .storage to hold all the protocol state. Removing that dir and running the tool again will trigger a reregistration with the server.

Usage

Do not run multiple instances of the app from the same directory, it (and the server) can get confused

This will show the supported command line flags

textsecure -h

Running the command without arguments will put it in receiving mode, and once it receives a message it will be able to talk to that contact.

Discussions

User and developer discussions happen on the mailing list

Documentation

Overview

Copyright (c) 2014 Canonical Ltd. Licensed under the GPLv3, see the COPYING file for details. Groups v1 only working with tel numbers

Copyright (c) 2020 Aaron Kimmig Licensed under the GPLv3, see the COPYING file for details.

Package textsecure implements the TextSecure client protocol.

Index

Constants

This section is empty.

Variables

View Source
var (
	SERVICE_REFLECTOR_HOST = "europe-west1-signal-cdn-reflector.cloudfunctions.net"
	SIGNAL_SERVICE_URL     = "http://192.168.202.53:8083"
	SIGNAL_CDN_URL         = "http://192.168.201.233:9000"
	SIGNAL_CDN2_URL        = "http://192.168.201.233:9000"
	DIRECTORY_URL          = "http://192.168.202.53:8085"
	STORAGE_URL            = "http://192.168.202.53:8089"

	// CREATE_ACCOUNT_SMS_PATH   = "/v1/accounts/sms/code/%s?client=%s";
	CREATE_ACCOUNT_VOICE_PATH = "/v1/accounts/voice/code/%s"
	VERIFY_ACCOUNT_CODE_PATH  = "/v1/accounts/code/%s"

	TURN_SERVER_INFO       = "/v1/accounts/turn"
	SET_ACCOUNT_ATTRIBUTES = "/v1/accounts/attributes/"
	PIN_PATH               = "/v1/accounts/pin/"
	REGISTRATION_LOCK_PATH = "/v1/accounts/registration_lock"
	REQUEST_PUSH_CHALLENGE = "/v1/accounts/fcm/preauth/%s/%s"
	WHO_AM_I               = "/v1/accounts/whoami"
	SET_USERNAME_PATH      = "/v1/accounts/username/%s"
	DELETE_USERNAME_PATH   = "/v1/accounts/username"
	DELETE_ACCOUNT_PATH    = "/v1/accounts/me"

	ATTACHMENT_DOWNLOAD_PATH = "/v2/attachments/"

	DIRECTORY_TOKENS_PATH   = "/v1/directory/tokens"
	DIRECTORY_VERIFY_PATH   = "/v1/directory/%s"
	DIRECTORY_AUTH_PATH     = "/v1/directory/auth"
	DIRECTORY_FEEDBACK_PATH = "/v1/directory/feedback-v3/%s"

	MESSAGE_PATH = "/v1/messages/%s"

	SENDER_ACK_MESSAGE_PATH = "/v1/messages/%s/%d"
	UUID_ACK_MESSAGE_PATH   = "/v1/messages/uuid/%s"
	ATTACHMENT_V2_PATH      = "/v2/attachments/form/upload"
	ATTACHMENT_V3_PATH      = "/v3/attachments/form/upload"

	PROFILE_PATH          = "/v1/profile/%s"
	PROFILE_USERNAME_PATH = "/v1/profile/%s"

	SENDER_CERTIFICATE_PATH         = "/v1/certificate/delivery"
	SENDER_CERTIFICATE_NO_E164_PATH = "/v1/certificate/delivery?includeE164=false"

	KBS_AUTH_PATH = "/v1/backup/auth"

	ATTACHMENT_KEY_DOWNLOAD_PATH = "/attachments/%s"
	ATTACHMENT_ID_DOWNLOAD_PATH  = "/attachments/%d"
	ATTACHMENT_UPLOAD_PATH       = "/attachments/"
	AVATAR_UPLOAD_PATH           = ""

	STICKER_MANIFEST_PATH = "/stickers/%s/manifest.proto"
	STICKER_PATH          = "/stickers/%s/full/%d"

	GROUPSV2_CREDENTIAL     = "/v1/certificate/group/%d/%d"
	GROUPSV2_GROUP          = "/v1/groups/"
	GROUPSV2_GROUP_PASSWORD = "/v1/groups/?inviteLinkPassword=%s"
	GROUPSV2_GROUP_CHANGES  = "/v1/groups/logs/%s"
	GROUPSV2_AVATAR_REQUEST = "/v1/groups/avatar/form"
	GROUPSV2_GROUP_JOIN     = "/v1/groups/join/%s"
	GROUPSV2_TOKEN          = "/v1/groups/token"

	ATTESTATION_REQUEST = "/v1/attestation/%s"
	DISCOVERY_REQUEST   = "/v1/discovery/%s"

	SERVER_DELIVERED_TIMESTAMP_HEADER = "X-Signal-Timestamp"
	CDS_MRENCLAVE                     = "c98e00a4e3ff977a56afefe7362a27e4961e4f19e211febfbb19b897e6b80b15"

	CONTACT_DISCOVERY        = "/v1/discovery/%s"
	CDN0              uint32 = 0
)
View Source
var EndSessionFlag uint32 = 1

EndSessionFlag signals that this message resets the session

View Source
var ErrBadPublicKey = errors.New("public key not formatted correctly")

ErrBadPublicKey is raised when a given public key is not in the expected format.

View Source
var ErrInvalidMACForAttachment = errors.New("invalid MAC for attachment")

ErrInvalidMACForAttachment signals that the downloaded attachment has an invalid MAC.

View Source
var ErrInvalidMACForMessage = errors.New("invalid MAC for incoming message")

ErrInvalidMACForMessage signals an incoming message with invalid MAC.

View Source
var ErrNotListening = errors.New("[textsecure] there is no listening connection to stop")

ErrNotListening is returned when trying to stop listening when there's no valid listening connection set up

View Source
var ErrRemoteGone = errors.New("the remote device is gone (probably reinstalled)")

ErrRemoteGone is returned when the peer reinstalled and lost its session state.

View Source
var ErrStoreBadMAC = errors.New("wrong MAC calculated, possibly due to wrong passphrase")

ErrStoreBadMAC occurs when MAC verification fails on the records stored using password based encryption. The probable cause is using a wrong password.

View Source
var GroupLeaveFlag uint32 = 2

GroupLeaveFlag signals that this message is a group leave message

View Source
var GroupUpdateFlag uint32 = 1

GroupUpdateFlag signals that this message updates the group membership or name.

ProfileKeyUpdatedFlag signals that this message updates the profile key

Functions

func AddDevice

func AddDevice(ephemeralID, publicKey, verificationCode string) error

AddDevice links a new device

func AddNewLinkedDevice

func AddNewLinkedDevice(uuid string, publicKey string) error

AddNewLinkedDevice adds a new signal desktop client

func ContactIdentityKey

func ContactIdentityKey(id string, s *Store) ([]byte, error)

ContactIdentityKey returns the serialized public key of the given contact

func EndSession

func EndSession(uuid string, msg string, s *Store) (uint64, error)

EndSession terminates the session with the given peer.

func GetAvatar

func GetAvatar(uuid string) (io.ReadCloser, error)

func GetAvatarPath

func GetAvatarPath(uuid string) (string, error)

func GetContactForTel

func GetContactForTel(tel string) *contacts.Contact

func GetFingerprint

func GetFingerprint(remoteUUID string, remoteIdentifier string, s *Store) ([]string, []byte, error)

func GetGroupV2MembersForGroup

func GetGroupV2MembersForGroup(group string) ([]*signalservice.DecryptedMember, error)

GetGroupV2MembersForGroup returns the members of a group

func GetMyUUID

func GetMyUUID() (string, error)

GetMyUUID returns the uid from the current user

func GetProfile

func GetProfile(uuid string, profileKey []byte) (*profiles.Profile, error)

func GetProfileAndCredential

func GetProfileAndCredential(uuid string, profileKey []byte) (*profiles.Profile, error)

func GetProfileByUUID

func GetProfileByUUID(uuid string) (*profiles.Profile, error)

func GetRegisteredContacts

func GetRegisteredContacts() ([]contacts.Contact, error)

GetRegisteredContacts returns the subset of the local contacts that are also registered with the server

func JoinGroup

func JoinGroup(hexID string) (*groupsv2.GroupV2, error)

func LeaveGroup

func LeaveGroup(hexid string, s *Store) error

LeaveGroup sends a group quit message to the other members of the given group.

func MIMETypeFromReader

func MIMETypeFromReader(r io.Reader) (mime string, reader io.Reader)

MIMETypeFromReader returns the mime type that is inside the reader

func MyIdentityKey

func MyIdentityKey() []byte

MyIdentityKey returns our serialized public identity key

func NewDeviceVerificationCode

func NewDeviceVerificationCode() (string, error)

NewDeviceVerificationCode returns the verification code for linking devices

func ReadConfig

func ReadConfig(fileName string) (*config.Config, error)

ReadConfig reads a YAML config file

func RefreshConfig

func RefreshConfig()

func RegisterWithCrayfish

func RegisterWithCrayfish(regisrationInfo *registration.RegistrationInfo, phoneNumber, captcha string) error

func RegisterWithUPS

func RegisterWithUPS(token string) error

RegisterWithUPS registers our Ubuntu push client token with the server.

func RemoveGroupKey

func RemoveGroupKey(hexid string) error

RemoveGroupKey removes the group key

func RequestGroupInfo

func RequestGroupInfo(g *Group, s *Store) error

RequestGroupInfo updates the info for the group like members or the avatat

func SendAttachment

func SendAttachment(uuid string, msg string, fp string, r io.Reader, timer uint32, s *Store) (uint64, error)

SendAttachment sends the contents of a reader, along with an optional message to a given contact.

func SendGroupAttachment

func SendGroupAttachment(hexid string, msg string, r io.Reader, timer uint32, s *Store) (uint64, error)

SendGroupAttachment sends an attachment to a given group.

func SendGroupMessage

func SendGroupMessage(hexid string, msg string, timer uint32, s *Store) (uint64, error)

SendGroupMessage sends a text message to a given group.

func SendGroupVoiceNote

func SendGroupVoiceNote(hexid string, msg string, r io.Reader, timer uint32, s *Store) (uint64, error)

SendGroupVoiceNote sends an voice note to a group

func SendMessage

func SendMessage(uuid, msg string, timer uint32, s *Store) (uint64, error)

SendMessage sends the given text message to the given contact.

func SendVoiceNote

func SendVoiceNote(uuid, msg string, r io.Reader, timer uint32, s *Store) (uint64, error)

SendVoiceNote sends a voice note

func SetAccountCapabilities

func SetAccountCapabilities(capabilities config.AccountCapabilities) error

SetAccountCapabilities lets the client decide when it's ready for new functions to support for example groupsv2

func SetUsername

func SetUsername(name string)

SetUsername sets the profile name

func StartListening

func StartListening(c config.Config, r registration.RegistrationInfo, s *Store) error

StartListening connects to the server and handles incoming websocket messages.

func SyncContacts

func SyncContacts(s *Store) error

SyncContacts syncs the contacts

func UnlinkDevice

func UnlinkDevice(id int) error

UnlinkDevice removes a linked device

func WriteConfig

func WriteConfig(filename string, cfg *config.Config) error

WriteConfig saves a config to a file

Types

type AccountAttributes

type AccountAttributes struct {
	SignalingKey                   string                     `json:"signalingKey" yaml:"signalingKey"`
	FetchesMessages                bool                       `json:"fetchesMessages" yaml:"fetchesMessages"`
	RegistrationID                 uint32                     `json:"registrationId" yaml:"registrationId"`
	Name                           string                     `json:"name" yaml:"name"`
	Video                          bool                       `json:"video" yaml:"video"`
	Voice                          bool                       `json:"voice" yaml:"voice"`
	Pin                            *string                    `json:"pin" yaml:"pin"` // deprecated
	BasicStorageCredentials        transport.AuthCredentials  `json:"basicStorageCredentials" yaml:"basicStorageCredentials"`
	Capabilities                   config.AccountCapabilities `json:"capabilities" yaml:"capabilities"`
	DiscoverableByPhoneNumber      bool                       `json:"discoverableByPhoneNumber" yaml:"discoverableByPhoneNumber"`
	UnrestrictedUnidentifiedAccess bool                       `json:"unrestrictedUnidentifiedAccess"`
	UnidentifiedAccessKey          *[]byte                    `json:"unidentifiedAccessKey"`
}

AccountAttributes describes what features are supported

type AccountIdentityResponse added in v1.1.8

type AccountIdentityResponse struct {
	UUID           string `json:"uuid"`
	Number         string `json:"number"`
	PNI            string `json:"pni"`
	UsernameHash   []byte `json:"usernameHash,omitempty"`
	StorageCapable bool   `json:"storageCapable"`
}

type Attachment

type Attachment struct {
	R        io.Reader
	MimeType string
	FileName string
}

Attachment represents an attachment received from a peer

type Client

type Client struct {
	GetPhoneNumber        func() string
	GetVerificationCode   func() string
	GetPin                func() string
	GetStoragePassword    func() string
	GetCaptchaToken       func() string
	GetConfig             func() (*config.Config, error)
	GetLocalContacts      func() ([]contacts.Contact, error)
	MessageHandler        func(*Message, string, string)
	TypingMessageHandler  func(*Message)
	ReceiptMessageHandler func(*Message)
	CallMessageHandler    func(*Message)
	ReceiptHandler        func(string, uint32, uint64)
	SyncReadHandler       func(string, uint64)
	SyncSentHandler       func(*Message, uint64)
	RegistrationDone      func()
	GetUsername           func() string
}

Client contains application specific data and callbacks.

type Conn

type Conn struct {
	// contains filtered or unexported fields
}

Conn is a wrapper for the websocket connection

type ContactDiscoveryRequest

type ContactDiscoveryRequest struct {
	AdressCount int
	Commitment  string
	Data        string
	Iv          string
	Mac         string
	Envelopes   Envelopes
}

type DeviceInfo

type DeviceInfo struct {
	ID       uint32 `json:"id"`
	Name     string `json:"name"`
	Created  uint64 `json:"created"`
	LastSeen uint64 `json:"lastSeen"`
}

func LinkedDevices

func LinkedDevices() ([]DeviceInfo, error)

LinkedDevices returns the list of linked devices

type DiscoveryContact

type DiscoveryContact struct {
	Data      string
	Iv        string
	Mac       string
	RequestId string
}

type Envelopes

type Envelopes map[string]DiscoveryContact

{"clientPublic":"DtZ1bEvFbDPgueDL30P3gh34GLeDAWCSIIXRECU7TCk="}

type Group

type Group struct {
	ID      []byte
	Hexid   string
	Flags   uint32
	Name    string
	Members []string
	Avatar  []byte
}

Group holds group metadata.

func GetGroupById

func GetGroupById(hexID string) (*Group, error)

GetGroupById returns a group by it's id

func NewGroup

func NewGroup(name string, members []string, s *Store) (*Group, error)

NewGroup creates a group and notifies its members. Our phone number is automatically added to members.

func UpdateGroup

func UpdateGroup(hexid, name string, members []string, s *Store) (*Group, error)

UpdateGroup updates the group name and/or membership. Our phone number is automatically added to members.

type Message

type Message struct {
	// contains filtered or unexported fields
}

Message represents a message received from the peer. It can optionally include attachments and be sent to a group.

func (*Message) Attachments

func (m *Message) Attachments() []*Attachment

Attachments returns the list of attachments on the message.

func (*Message) ChatID

func (m *Message) ChatID() string

ChatID returns the ChatID of the sender of the message.

func (*Message) Contact

func (m *Message) Contact() []*signalservice.DataMessage_Contact

Contact returns the contact in the message

func (*Message) ExpireTimer

func (m *Message) ExpireTimer() uint32

ExpireTimer returns the expire timer in the message

func (*Message) Flags

func (m *Message) Flags() uint32

Flags returns the flags in the message

func (*Message) Group

func (m *Message) Group() *Group

Group returns group information.

func (*Message) GroupV2

func (m *Message) GroupV2() *groupsv2.GroupV2

GroupV2 returns group information.

func (*Message) Message

func (m *Message) Message() string

Message returns the message body.

func (*Message) Quote

Quote returns the quote in the message

func (*Message) Reaction

Reaction returns the reaction in the message

func (*Message) Source

func (m *Message) Source() string

Source returns the ID of the sender of the message.

func (*Message) SourceUUID

func (m *Message) SourceUUID() string

SourceUUID returns the UUID of the sender of the message.

func (*Message) Sticker

Sticker returns the sticker in the message

func (*Message) Timestamp

func (m *Message) Timestamp() uint64

Timestamp returns the timestamp of the message

type MessageTypeNotImplementedError

type MessageTypeNotImplementedError struct {
	// contains filtered or unexported fields
}

MessageTypeNotImplementedError is raised in the unlikely event that an unhandled protocol message type is received.

func (MessageTypeNotImplementedError) Error

type RegistrationLockFailure

type RegistrationLockFailure struct {
	TimeRemaining uint32                    `json:"timeRemaining"`
	Credentials   transport.AuthCredentials `json:"backupCredentials"`
}

type RemoteAttestationRequest

type RemoteAttestationRequest struct {
	ClientPublic string
}

type Store

type Store struct {
	sync.Mutex
	// contains filtered or unexported fields
}

Store implements the PreKeyStore, SignedPreKeyStore, IdentityStore and SessionStore interfaces from the axolotl package Blobs are encrypted with AES-128 and authenticated with HMAC-SHA1

func Setup

Setup initializes the package.

func (*Store) ContainsPreKey

func (s *Store) ContainsPreKey(id uint32) bool

func (*Store) ContainsSession

func (s *Store) ContainsSession(recipientID string, deviceID uint32) bool

func (*Store) ContainsSignedPreKey

func (s *Store) ContainsSignedPreKey(id uint32) bool

func (*Store) DeleteAllSessions

func (s *Store) DeleteAllSessions(recipientID string)

func (*Store) DeleteSession

func (s *Store) DeleteSession(recipientID string, deviceID uint32)

func (*Store) GetIdentityKeyPair

func (s *Store) GetIdentityKeyPair() (*axolotl.IdentityKeyPair, error)

func (*Store) GetLocalRegistrationID

func (s *Store) GetLocalRegistrationID() (uint32, error)

func (*Store) GetSubDeviceSessions

func (s *Store) GetSubDeviceSessions(recipientID string) []uint32

func (*Store) IsTrustedIdentity

func (s *Store) IsTrustedIdentity(id string, key *axolotl.IdentityKey) bool

func (*Store) LoadPreKey

func (s *Store) LoadPreKey(id uint32) (*axolotl.PreKeyRecord, error)

func (*Store) LoadSession

func (s *Store) LoadSession(recipientID string, deviceID uint32) (*axolotl.SessionRecord, error)

func (*Store) LoadSignedPreKey

func (s *Store) LoadSignedPreKey(id uint32) (*axolotl.SignedPreKeyRecord, error)

func (*Store) LoadSignedPreKeys

func (s *Store) LoadSignedPreKeys() []axolotl.SignedPreKeyRecord

func (*Store) RemovePreKey

func (s *Store) RemovePreKey(id uint32)

func (*Store) RemoveSignedPreKey

func (s *Store) RemoveSignedPreKey(id uint32)

func (*Store) SaveIdentity

func (s *Store) SaveIdentity(id string, key *axolotl.IdentityKey) error

func (*Store) SetIdentityKeyPair

func (s *Store) SetIdentityKeyPair(ikp *axolotl.IdentityKeyPair) error

func (*Store) SetLocalRegistrationID

func (s *Store) SetLocalRegistrationID(id uint32)

func (*Store) StorePreKey

func (s *Store) StorePreKey(id uint32, record *axolotl.PreKeyRecord) error

func (*Store) StoreSession

func (s *Store) StoreSession(recipientID string, deviceID uint32, record *axolotl.SessionRecord) error

func (*Store) StoreSignedPreKey

func (s *Store) StoreSignedPreKey(id uint32, record *axolotl.SignedPreKeyRecord) error

type UnknownContactError

type UnknownContactError struct {
	// contains filtered or unexported fields
}

UnknownContactError is returned when an unknown group id is encountered

func (UnknownContactError) Error

func (err UnknownContactError) Error() string

type UnknownGroupIDError

type UnknownGroupIDError struct {
	// contains filtered or unexported fields
}

UnknownGroupIDError is returned when an unknown group id is encountered

func (UnknownGroupIDError) Error

func (err UnknownGroupIDError) Error() string

type UpdateAccountAttributes

type UpdateAccountAttributes struct {
	SignalingKey                   *string                    `json:"signalingKey" yaml:"signalingKey"`
	FetchesMessages                bool                       `json:"fetchesMessages" yaml:"fetchesMessages"`
	RegistrationID                 uint32                     `json:"registrationId" yaml:"registrationId"`
	Name                           string                     `json:"name" yaml:"name"`
	Pin                            *string                    `json:"pin" yaml:"pin"` // deprecated
	RegistrationLock               *string                    `json:"registrationLock" yaml:"registrationLock"`
	UnidentifiedAccessKey          *[]byte                    `json:"unidentifiedAccessKey"`
	UnrestrictedUnidentifiedAccess bool                       `json:"unrestrictedUnidentifiedAccess"`
	Capabilities                   config.AccountCapabilities `json:"capabilities" yaml:"capabilities"`
	DiscoverableByPhoneNumber      bool                       `json:"discoverableByPhoneNumber" yaml:"discoverableByPhoneNumber"`
	Video                          bool                       `json:"video" yaml:"video"`
	Voice                          bool                       `json:"voice" yaml:"voice"`
}

Directories

Path Synopsis
Package axolotl implements the Axolotl ratchet as used by TextSecure protocol version 3.
Package axolotl implements the Axolotl ratchet as used by TextSecure protocol version 3.
Package curve25519sign implements a signature scheme based on Curve25519 keys.
Package curve25519sign implements a signature scheme based on Curve25519 keys.
Based on https://gist.github.com/nanu-c/f885b928b9e43a7167258dd70dc186d6 from nanu-c which is based on https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/fingerprint/NumericFingerprintGenerator.java
Based on https://gist.github.com/nanu-c/f885b928b9e43a7167258dd70dc186d6 from nanu-c which is based on https://github.com/signalapp/libsignal-protocol-java/blob/master/java/src/main/java/org/whispersystems/libsignal/fingerprint/NumericFingerprintGenerator.java

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL