rpc

package
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: May 9, 2024 License: ISC Imports: 22 Imported by: 0

README

Protocol

Following are the main changes that have been made to the zk protocol.

The high level changes are that servers are now accountless and that clients use ephemeral identities. This essentially makes clients anonymous, provided they uses tor to mask their IP addresses as they connect and communicate with the server.

Clients determine the rendezvous point with other clients in a way that the server can only track the absolute minimum amount of metadata.

All client to server communications are double encrypted using a TLS tunnel as the outer layer and NaCl secretbox as the inner layer.

All client to client communications are encrypted with a double ratchet (a third layer of encryption) with keys that only the clients have. The server cannot read these messages. These messages wrap a new client to client protocol.

For now, the client and server reuse the old initiate/acknowledge protocol that is XDR encoded. This should be reevaluated since XDR has some serious drawbacks.

Client/Server key exchange

The client server key exchange was gutted in favor of creating an anonymous accountless client connection. In order to achieve this the server currently has to identify itself in cleartext (inside the TLS tunnel) since the client must know the server public key before connecting. This portion may have to be rethought.

  1. Client creates TLS tunnel to the server.
  2. Client creates an ephemeral sntrup4591761 encapsulated shared key and send it to the server.
  3. Server receives encapsulated shared key and decapsulates it.
  4. Both the client and server use the shared key to read and write. In order to ensure no reuse of the nonce the nonce space is divided by two.
  5. Server write key starts at 0 and client starts at nonce_space/2. Both keys count up. The nonce space is 24 bytes and thus is large enough to never be reused in a session. Note that the shared key is random and is generated every session.
  6. Both client and server at this point write commands to the other side using the shared key and their respective nonce spaces. Every message that is sent increments the nonce.

Routed messages

The new protocol uses routed messages vs account messages. The client generates the rendezvous point (a collider that both clients can predict) and sends it along with encrypted blob. Currently it uses and HMAC of the send header key where the message number is the key to the HMAC. The server verifies that it is indeed a random 32 byte number that is hex encoded and uses that as the filename to drop the blob on the filesystem. Once a client retrieves a blob from the filesystem it is deleted (this needs to happen after the client ACK at some point). Once a client receives a blob it uses the normal client-to-client ratchet to decrypt it. Inside the decrypted blob is the actual command that the client receives from the other side.

This section is sparce because the rendezvous is currently a bit in flux and has a mechanism built-in to switch between methods. The expectation is that this will be modified as we run into ratchet errors and have to come up with methods on how to work around that.

Out-of-band invites

To get an initial ratchet key exchange kicked off the tool provides a method to export and import a file with enough information to bootstrap that process.

The inviter creates a PublicIdentityInvite structure that contains their entire public identity and keys. In addition this structure contains a 32 byte field called InitialRendezvous which is used to hint the invitee where to send their response. The invitee subscribes to the InitialRendezvous with the server. The PublicIdentityInvite is JSON encoded and NaCl secret box encrypted with a key derived from a trivial PIN.

  1. Alice creates a PublicIdentityInvite with a strong random InitialRendezvous. The PublicIdentityInvite is JSON encoded and NaCl secret box encrypted. This blob is exported as a file which Alice must send to Bob out-of-band. Alice subscribes for notification at the InitialRendezvous route.
  2. Bob receives the encrypted PublicIdentityInvite and decrypts it using the PIN provided by Alice. Bob is prompted to accept Alice's fingerprint and if accepted Bob kicks of the in-band portion of the ratchet key exchange by routing a RMIdentityKX command to the InitialRendezvous. The RMIdentityKX contains Bob's public identity and keys, an InitialRendezvous for Bob to subscribe to, and a half ratchet. Bob routes the RMIdentityKX to the server using the newly generated InitialRendezvous and subscribes to it.
  3. Alice receives the RMIdentityKX command and finalizes the ratchet. Alice routes a RMKX command using Bob's InitialRendezvous which contains the finalized ratchet. Alice subscribes to the HMAC of the send ratchet header key.
  4. Bob receives the RMKX and subscribes to the HMAC send ratchet header key.

Notes: The HMAC of the send header key uses a counter as the key. This jumbles the rendezvous for every command while remaining predictable. If a key has a zero value, which happens once during key exchange, the next send header key is used.

Transitive invites

Consider the following situation: Alice and Bob are communicating and Bob decides that Alice should talk to Charlie. Bob sends Alice a request to speak to Charlie and facilitates delivery of key exchange material. Naturally, this needs to be non-forgeable.

The process is as follows:

  1. Bob sends Alice a RMInvite command with Charlie's public key
  2. Alice responds to Bob with a RMInviteReply that contains an encrypted PublicIdentityInvite. Since Alice received Charlie's public key she can use sntrup4591761 to encapsulate a shared key between Charlie and her. That shared key is then used to encrypt the JSON encoded PublicIdentityInvite blob using NaCl secretbox.
  3. Bob receives the RMInviteReply and forwards it to Charlie. Bob could try to decapsulate the shared key but will not succeed and therefore cannot decrypt the JSON encoded PublicIdentityInvite blob.
  4. Charlie receives the RMInviteReply and decapsulates the shared key using his sntrup4591761 private key. Charlie then uses the shared key to decrypt the NaCl secret box that contains the PublicIdentityInvite. At this point a ratchet key exchange can commence using the same exact mechanism as the out-of-band as described above.

Notes: there is an assumption that people can externally verify identity fingerprints or that the facilitator is trusted.

Resetting the ratchet

Ratchets are brittle and break from time to time. In order to be able to re-establish a ratchet a sideband for communication exists. This sideband is dubbed Emergency and is a well known rendezvous point where the communication mechanism does not use a ratchet but rather a sntrup4591761 generated key.

The rendezvous point is currently not smart and is simply called reset and reset.reply. This will obviously break all kinds of things. This section will be replaced once the rendezvous spec is finalized.

The Emergency commands are encrypted as follows: [sntrup4591761 encapsulated key][nonce][encrypted emergency command]. Once the encrypted emergency command is decrypted it contains an embedded command of which reset ratchet is one.

The reset procedure is as follows:

  1. Alice sends Bob an RMEReset command on the emergency rendezvous. Alice deletes ratchet files of disk but not the identity.
  2. Bob receives RMEReset command and deletes ratchets of disk and sends a normal PublicIdentityInvite encrypted reusing the sntrup4591761 shared key to Alice's emergency rendezvous.
  3. At this point the process becomes the same as a out-of-band invite.

Attack vectors

TBD

To do

  1. Receipts
  2. First pass to serve data use case (ala FTP with price attached)

Documentation

Index

Constants

View Source
const (
	RMHeaderVersion = 1

	// Use NoCompression by default
	RMDefaultCompressionLevel = zlib.NoCompression
)

Header that describes the payload that follows.

View Source
const (
	RMCPrivateMessage = "pm"

	RMPrivateMessageModeNormal = 0
	RMPrivateMessageModeMe     = 1 // XXX not rigged up yet
)

Private message to other client

View Source
const (
	ResourceStatusOk         = 200
	ResourceStatusBadRequest = 400
	ResourceStatusNotFound   = 404
)
View Source
const (
	RMCHandshakeSYN    = "handshakesyn"
	RMCHandshakeSYNACK = "handshakesynack"
	RMCHandshakeACK    = "handshakeack"
)
View Source
const (
	RMCFTList = "ftls"

	RMFTDGlobal = "global" // Globally accessible files
	RMFTDShared = "shared" // Files shared between two users
)
View Source
const (
	RMUDescription    = "description"    // User description
	RMUAway           = "away"           // User away message
	RMUProfilePicture = "profilepicture" // User profile picture
)
View Source
const (
	RMPSHeart    = "heart"   // Heart a post
	RMPSComment  = "comment" // Comment on a post
	RMPSHeartYes = "1"       // +1 heart
	RMPSHeartNo  = "0"       // -1 heart
)
View Source
const (
	RMPVersion     = "version"     // Post version
	RMPIdentifier  = "identifier"  // Post identifier
	RMPDescription = "description" // Post description
	RMPMain        = "main"        // Main post body
	RMPTitle       = "title"       // Title of the post
	RMPAttachment  = "attachment"  // Attached file to the post
	RMPStatusFrom  = "statusfrom"  // Status/post update from (author)
	RMPSignature   = "signature"   // Signature for the post/status
	RMPParent      = "parent"      // Parent status/post
	RMPStatusID    = "statusid"    // Status ID in status updates
	RMPNonce       = "nonce"       // Random nonce to avoid equal hashes
	RMPFromNick    = "from_nick"   // Nick of origin for post/status
	RMPTimestamp   = "timestamp"   // Timestamp of the status update
)
View Source
const (
	// pre session phase
	InitialCmdIdentify = "identify"
	InitialCmdSession  = "session"

	// session phase
	SessionCmdWelcome = "welcome"

	// tagged server commands
	TaggedCmdAcknowledge = "ack"
	TaggedCmdPing        = "ping"
	TaggedCmdPong        = "pong"

	// payment cmds
	TaggedCmdGetInvoice      = "getinvoice"
	TaggedCmdGetInvoiceReply = "getinvoicereply"

	TaggedCmdRouteMessage      = "routemessage"
	TaggedCmdRouteMessageReply = "routemessagereply"

	TaggedCmdSubscribeRoutedMessages      = "subscriberoutedmessages"
	TaggedCmdSubscribeRoutedMessagesReply = "subscriberoutedmessagesreply"

	TaggedCmdPushRoutedMessage = "pushroutedmessage"

	// misc
	MessageModeNormal MessageMode = 0
	MessageModeMe     MessageMode = 1

	PaySchemeFree  = "free"
	PaySchemeDCRLN = "dcrln"

	// PingLimit is how long to wait for a ping before disconnect.
	// DefaultPingInterval is how long to wait to send the next ping.
	DefaultPingInterval = 30 * time.Second

	// MaxChunkSize is the maximum size of a file chunk used in file
	// downloads.
	MaxChunkSize = 1024 * 1024 // 1 MiB

	// MinRMPushPayment is the minimum payment amount required to push a payment
	// to the server (in milliatoms).
	MinRMPushPayment uint64 = 1000

	// InvoiceExpiryAffordance is the time before the expiry a client may
	// request a new invoice.
	InvoiceExpiryAffordance = 15 * time.Second
)
View Source
const (
	// Tag Depth is a required property.  It defines maximum outstanding
	// commands.
	PropTagDepth        = "tagdepth"
	PropTagDepthDefault = "10"

	// Server Time is a required property.  It contains the server time
	// stamp.  The client shall warn the user if the client is not time
	// synced.  Clients and proxies really shall run NTP.
	PropServerTime = "servertime"

	// Payment Scheme is a required property. It defines whether the type
	// of payment that the server expects before routing messages.
	PropPaymentScheme        = "payscheme"
	PropPaymentSchemeDefault = "free"

	// Push Payment rate is the required payment rate to push RMs when the
	// payment scheme is not free (in milli-atoms per byte).
	PropPushPaymentRate        = "pushpayrate"
	PropPushPaymentRateDefault = 100 // MilliAtoms/byte

	// Sub payment rate is the required payment rate to sub to RVs when the
	// payment scheme is not free (in milli-atoms per byte).
	PropSubPaymentRate        = "subpayrate"
	PropSubPaymentRateDefault = 1000 // MilliAtoms/sub

	// PropServerLNNode returns the node id of the server.
	PropServerLNNode = "serverlnnode"

	// PropExpirationDays is the number of days after which data is expired
	// from the server automatically.
	PropExpirationDays        = "expirationdays"
	PropExpirationDaysDefault = 7

	// PropPushPaymentLifetime is the maximum duration when a successful
	// payment for a push may be redeemed. After this duration, the push
	// needs to be paid for again. This value is in seconds.
	PropPushPaymentLifetime        = "pushpaymentlifetime"
	PropPushPaymentLifetimeDefault = 60 * 60 * 24 // 24 hours

	// PropMaxPushInvoices is the maximum number of outstanding (unredeemed)
	// push invoices a connected client may request before needing to pay
	// for them.
	PropMaxPushInvoices        = "maxpushinvoices"
	PropMaxPushInvoicesDefault = 8

	// PropMaxMsgSizeVersion is the max message size version supported by
	// the server.
	PropMaxMsgSizeVersion        = "maxmsgsizeversion"
	PropMaxMsgSizeVersionDefault = MaxMsgSizeV0

	// PropPingLimit is the ping limit the server expects, after which it
	// will disconnect a client.
	PropPingLimit        = "pinglimit"
	PropPingLimitDefault = 5 * time.Minute
)
View Source
const FileMetadataVersion = 1
View Source
const OOBCPublicIdentityInvite = "oobpublicidentityinvite"
View Source
const PostMetadataStatusVersion = 1
View Source
const PostMetadataVersion = 1
View Source
const (
	ProtocolVersion = 10
)
View Source
const RMCBlock = "block"
View Source
const RMCFTGet = "ftget"
View Source
const RMCFTGetChunk = "ftgetchunk"
View Source
const RMCFTGetChunkReply = "ftgetchunkreply"
View Source
const RMCFTGetReply = "ftgetreply"
View Source
const RMCFTListReply = "ftlsreply"
View Source
const RMCFTPayForChunk = "ftpayforchunk"
View Source
const RMCFTSendFile = "ftsendfile"
View Source
const RMCFetchResource = "fetchresource"
View Source
const RMCFetchResourceReply = "fetchresourcereply"
View Source
const RMCGetInvoice = "getinvoice"
View Source
const RMCGetPost = "getpost"
View Source
const RMCGroupInvite = "groupinvite"
View Source
const RMCGroupJoin = "groupjoin"
View Source
const RMCGroupKick = "groupkick"
View Source
const RMCGroupKill = "groupkill"
View Source
const RMCGroupList = "grouplist"
View Source
const RMCGroupMessage = "groupmessage"
View Source
const RMCGroupPart = "grouppart"
View Source
const RMCGroupUpgradeVersion = "groupupversion"
View Source
const RMCInvite = "invite"
View Source
const RMCInvoice = "invoice"
View Source
const RMCKXSearch = "kxsearch"
View Source
const RMCKXSearchReply = "kxsearchreply"
View Source
const RMCKXSuggestion = "kxsuggestion"
View Source
const RMCListPosts = "listposts"
View Source
const RMCListPostsReply = "listpostsreply"
View Source
const RMCMediateIdentity = "mediateidentity"
View Source
const RMCPostGet = "postget"
View Source
const RMCPostGetReply = "postgetreply"
View Source
const RMCPostShare = "postshare"
View Source
const RMCPostStatus = "poststatus"
View Source
const RMCPostStatusReply = "poststatusreply"
View Source
const RMCPostsSubscribe = "postssubscribe"
View Source
const RMCPostsSubscribeReply = "postssubscribereply"
View Source
const RMCPostsUnsubscribe = "postsunsubscribe"
View Source
const RMCPostsUnsubscribeReply = "postsunsubscribereply"
View Source
const RMCProfileUpdate = "profileupdt"

RMCProfileUpdate is the command for a RMProfileUpdate.

View Source
const RMCReceiveReceipt = "recvreceipt"

RMCReceiveReceipt is the command for a RMReceiveReceipt value.

View Source
const RMCTransitiveMessage = "transitivemessage"
View Source
const RMCTransitiveMessageForward = "tmessageforward"
View Source
const RMCTransitiveMessageReply = "transitivemessagereply"
View Source
const RMCTransitiveReset = "transitivereset"

RMTransitiveReset ask proxy to forward reset message to another client.

View Source
const RMCTransitiveResetReply = "transitiveresetreply"

RMTransitiveResetReply ask proxy to forward reset message reply to another client.

View Source
const RMCUser = "user"
View Source
const RMCUserReply = "userreply"
View Source
const RMGCGroupUpdateAdmins = "groupupdateadmins"
View Source
const RMOCFullKX = "ofullkx"
View Source
const RMOCHalfKX = "ohalfkx"
View Source
const (
	RMOHeaderVersion = 1
)

Following is the portion of the oob protocol which does travel over the wire.

Variables

View Source
var ErrRMInvoicePayment = errors.New("invoice payment error on RM push")

ErrRMInvoicePayment is generated on servers when an RM push fails due to some payment check failure in the invoice.

Do not change this message as it's used in plain text across the C2S RPC interface.

View Source
var ErrUnableToGenerateInvoice = errors.New("unable to generate payment invoice")

ErrUnableToGenerateInvoice is generated on clients when they are unable to generate an invoice for a remote peer.

Do not change this message as it's used in plain text across the C2C RPC interface.

Functions

func ComposeCompressedRM

func ComposeCompressedRM(fromSigner MessageSigner, rm interface{}, zlibLevel int) ([]byte, error)

ComposeCompressedRM creates a blobified message that has a header and a payload that can then be encrypted and transmitted to the other side. The contents are zlib compressed with the specified level.

func ComposeRM

func ComposeRM(fromSigner MessageSigner, rm interface{}) ([]byte, error)

ComposeRM creates a blobified message that has a header and a payload that can then be encrypted and transmitted to the other side.

func ComposeRMO

func ComposeRMO(rm interface{}, zlibLevel int) ([]byte, error)

ComposeRMO creates a blobified oob message that has a header and a payload that can then be encrypted and transmitted to the other side.

func DecryptOOB

func DecryptOOB(packed []byte, key *zkidentity.FixedSizeSntrupPrivateKey, maxDecompressSize uint) (interface{}, error)

func EncryptRMO

func EncryptRMO(x interface{}, theirKey *zkidentity.FixedSizeSntrupPublicKey, zlibLevel int) ([]byte, error)

EncryptRMO returns an encrypted blob from x. The returned blob is packed and prefixed with a sntrup ciphertext followed by an encrypted JSON objecti; or [sntrup ciphertext][encrypted JSON object].

func EstimateRoutedRMWireSize added in v0.1.3

func EstimateRoutedRMWireSize(compressedRMSize int) int

EstimateRoutedRMWireSize estimates the final wire size of a compressed RM (with compression set to its lowest value, which effectively disables it).

func IsPostStatus

func IsPostStatus(attrs map[string]string) bool

IsPostStatus returns true when the map of attributes (possibly) corresponds to a post status update.

func MarshalOOBPublicIdentityInvite

func MarshalOOBPublicIdentityInvite(pii *OOBPublicIdentityInvite) ([]byte, error)

MarshalOOBPublicIdentityInvite returns a JSON encoded OOBPublicIdentityInvite.

func MaxMsgSizeForVersion added in v0.1.10

func MaxMsgSizeForVersion(v MaxMsgSizeVersion) uint

MaxMsgSizeForVersion returns the max message size according to the given max message size version. It returns 0 for unknown versions.

func MaxPayloadSizeForVersion added in v0.1.10

func MaxPayloadSizeForVersion(v MaxMsgSizeVersion) uint

MaxPayloadSizeForVersion returns the (approximate) max payload size according to the given max message size version. It returns 0 for unknown versions.

It is approximate because due to encoding and compression, the actual payload may be slightly greater than this, but clients should not attempt to send more than this amount of data.

func NewFullRatchetKX

NewFullRatchetKX creates a new full ratchet between two identities. It returns the completed full ratchet.

ourPrivKey should be the private key that corresponds to the local client's full identity.

func NewHalfRatchetKX

NewHalfRatchetKX creates a new half ratchet between two identities. It returns the half ratchet and a random key exchange structure.

ourPrivKey should be the local client's private key from their full identity.

func ParseErrUnpaidSubscriptionRV

func ParseErrUnpaidSubscriptionRV(s string) error

ParseErrUnpaidSubscriptionRV attempts to parse a string as an ErrUnpaidSubscriptionRV. If this fails, it returns a nil error. If it succeeds, the return value is an instance of ErrUnpaidSubscriptionRV.

func SetLog added in v0.1.3

func SetLog(v slog.Logger)

SetLog sets the package-level logger.

Types

type Acknowledge

type Acknowledge struct {
	Error     string
	ErrorCode int // optional error to be used as a hint
}

Acknowledge is sent to acknowledge commands and Error is set if the command failed.

type ErrUnpaidSubscriptionRV

type ErrUnpaidSubscriptionRV ratchet.RVPoint

ErrUnpaidSubscriptionRV is an error returned while attempting to subscribe to an RV that wasn't previously paid.

func (ErrUnpaidSubscriptionRV) Error

func (err ErrUnpaidSubscriptionRV) Error() string

func (ErrUnpaidSubscriptionRV) Is

func (err ErrUnpaidSubscriptionRV) Is(other error) bool

type FileManifest

type FileManifest struct {
	Index uint64 `json:"index"`
	Size  uint64 `json:"size"`
	Hash  []byte `json:"hash"`
}

type FileMetadata

type FileMetadata struct {
	Version     uint64            `json:"version"`
	Cost        uint64            `json:"cost"`
	Size        uint64            `json:"size"`
	Directory   string            `json:"directory"`
	Filename    string            `json:"filename"`
	Description string            `json:"description"`
	Hash        string            `json:"hash"`
	Manifest    []FileManifest    `json:"manifest"` // len == number of chunks
	Signature   string            `json:"signature"`
	Attributes  map[string]string `json:"attributes,omitempty"`
}

func (*FileMetadata) MetadataHash

func (fm *FileMetadata) MetadataHash() [32]byte

MetadataHash calculates the hash of the metadata info. Note that the specific information that is hashed depends on the version of the metadata.

type GetInvoice

type GetInvoice struct {
	PaymentScheme string           // LN, on-chain, whatever
	Action        GetInvoiceAction // push or subscribe
}

type GetInvoiceAction

type GetInvoiceAction string

GetInvoiceAction is the action the client wants to perform and needs an invoice for.

const (
	InvoiceActionPush GetInvoiceAction = "push"
	InvoiceActionSub  GetInvoiceAction = "sub"
)

type GetInvoiceReply

type GetInvoiceReply struct {
	Invoice string // Depends on payment scheme
}

type InviteFunds added in v0.1.7

type InviteFunds struct {
	Tx         TxHash `json:"txid"`
	Index      uint32 `json:"index"`
	Tree       int8   `json:"tree"`
	PrivateKey string `json:"private_key"`
	HeightHint uint32 `json:"height_hint"`
	Address    string `json:"address"`
}

type MaxMsgSizeVersion added in v0.1.10

type MaxMsgSizeVersion uint

MaxMsgSizeVersion tracks defined versions of max msg size.

const (
	// MaxMsgSizeV0 is the first version of the max size of a message.
	// This was determined as enough to contain a base64 encoded version of
	// 1MiB (1024*1024 bytes), along with the necessary overhead of
	// headers, encodings and frames needed by the encrypted routed
	// messages with some room to spare, when sending with compression
	// turned off.
	MaxMsgSizeV0 MaxMsgSizeVersion = 0

	// MaxMsgSizeV1 is the second version of the max size of a message.
	// This was determined as enough to contain a base64 encoded version
	// of 10 MiB (10*1024*1024 bytes), along with the necessary overhead of
	// headers, encodings and frames needed by the encrypted routed mesasges
	// with some room to spare, when sending with compression turned off.
	MaxMsgSizeV1 MaxMsgSizeVersion = 1
)

type Message

type Message struct {
	Command   string // discriminator
	TimeStamp int64  // originator timestamp
	Cleartext bool   // If set Payload is in clear text, proxy use only
	Tag       uint32 // client generated tag, shall be unique

}

Message is the generic command that flows between a server and client and vice versa. Its purpose is to add a discriminator to simplify payload decoding. Additionally it has a tag that the recipient shall return unmodified when replying. The tag is originated by the sender and shall be unique provided an answer is expected. The receiver shall not interpret or use the tag in any way. The Cleartext flag indicates that the payload is in clear text. This flag should only be used for proxy commands (e.g. ratchet reset).

type MessageMode

type MessageMode uint32

type MessageSigner added in v0.2.0

type MessageSigner func(message []byte) zkidentity.FixedSizeSignature

type MessageVerifier added in v0.2.0

type MessageVerifier func(msg []byte, sig *zkidentity.FixedSizeSignature) bool

type OOBPublicIdentityInvite

type OOBPublicIdentityInvite struct {
	Public            zkidentity.PublicIdentity `json:"public"`
	InitialRendezvous zkidentity.ShortID        `json:"initialrendezvous"`
	ResetRendezvous   zkidentity.ShortID        `json:"resetrendezvous"`
	Funds             *InviteFunds              `json:"funds,omitempty"`
}

OOBPublicIdentityInvite is an unencrypted OOB command which contains all information to kick of an initial KX. This command is NOT part of the wire protocol. This is provided out-of-band. With this the other side can commence a KX by issuing a RMOCHalfKX command to the provided InitialRendezvous.

func CreateOOBPublicIdentityInvite

func CreateOOBPublicIdentityInvite(pi zkidentity.PublicIdentity) (*OOBPublicIdentityInvite, error)

CreateOOBPublicIdentityInvite returns a OOBPublicIdentityInvite structure with a random initial and reset rendezvous.

func DecryptOOBPublicIdentityInvite

func DecryptOOBPublicIdentityInvite(packed []byte, key *zkidentity.FixedSizeSntrupPrivateKey, maxDecompressSize uint) (*OOBPublicIdentityInvite, error)

func UnmarshalOOBPublicIdentityInviteFile

func UnmarshalOOBPublicIdentityInviteFile(filename string) (*OOBPublicIdentityInvite, error)

UnmarshalOOBPublicIdentityInviteFile returns an OOBPublicIdentityInvite from a file.

type Ping

type Ping struct{}

Ping is a PRPC that is used to determine if the server is alive. This command must be acknowledged by the remote side.

type Pong

type Pong struct{}

type PostListItem

type PostListItem struct {
	ID    zkidentity.ShortID `json:"id"`
	Title string             `json:"title"`
}

type PostMetadata

type PostMetadata struct {
	Version    uint64            `json:"version"`
	Attributes map[string]string `json:"attributes,omitempty"`
}

func (*PostMetadata) Hash

func (pm *PostMetadata) Hash() [32]byte

type PostMetadataStatus

type PostMetadataStatus struct {
	Version    uint64            `json:"version"`
	From       string            `json:"from"` // Who sent update
	Link       string            `json:"link"` // Original post ID
	Attributes map[string]string `json:"attributes,omitempty"`
}

func (*PostMetadataStatus) Hash

func (pm *PostMetadataStatus) Hash() [32]byte

type PushRoutedMessage

type PushRoutedMessage struct {
	Payload   []byte
	RV        ratchet.RVPoint
	Timestamp int64
	Error     string
}

type RMBlock

type RMBlock struct {
}

type RMFTGet

type RMFTGet struct {
	Directory string `json:"directory"` // Which directory **DEPRECATED
	Filename  string `json:"filename"`  // Which file **DEPRECATED
	Tag       uint32 `json:"tag"`       // Tag to copy in replies
	FileID    string `json:"file_id"`   // Equals metadata hash
}

RMFTGet attempts to retrieve a file from another user

type RMFTGetChunk

type RMFTGetChunk struct {
	FileID string `json:"file_id"`
	Hash   []byte `json:"hash"` // Chunk to retrieve
	Index  int    `json:"index"`
	Tag    uint32 `json:"tag"` // Tag to copy in replies
}

RMFTGetChunk attempts to retrieve a file chunk from another user.

type RMFTGetChunkReply

type RMFTGetChunkReply struct {
	FileID string  `json:"file_id"`
	Index  int     `json:"index"`
	Chunk  []byte  `json:"chunk"` // Actual data, needs to be hashed to verify
	Tag    uint32  `json:"tag"`
	Error  *string `json:"error,omitempty"`
}

RMFTGetChunkReply chunked file get reply

type RMFTGetReply

type RMFTGetReply struct {
	Metadata FileMetadata `json:"metadata"`
	Tag      uint32       `json:"tag"`
	Error    *string      `json:"error,omitempty"`
}

RMFTGetReply file metadata get reply

type RMFTList

type RMFTList struct {
	Directories []string `json:"directories"`      // Which directories to obtain
	Filter      string   `json:"filter,omitempty"` // Filter list by this regex
	Tag         uint32   `json:"tag"`              // Tag to copy in replies
}

RMFTList asks other side for a list of files. Directories are constants that describe which directories it should access. Currently only "global" and "shared" are allowed.

type RMFTListReply

type RMFTListReply struct {
	Global []FileMetadata `json:"global,omitempty"`
	Shared []FileMetadata `json:"shared,omitempty"`
	Tag    uint32
	Error  *string `json:"error,omitempty"`
}

type RMFTPayForChunk

type RMFTPayForChunk struct {
	Tag     uint32  `json:"tag"`
	FileID  string  `json:"file_id"`
	Invoice string  `json:"invoice"`
	Index   int     `json:"index"`
	Hash    []byte  `json:"hash"`
	Error   *string `json:"error,omitempty"`
}

type RMFTSendFile

type RMFTSendFile struct {
	Metadata FileMetadata `json:"metadata"`
}

type RMFetchResource added in v0.1.8

type RMFetchResource struct {
	Path  []string          `json:"path"`
	Meta  map[string]string `json:"meta"`
	Tag   ResourceTag       `json:"tag"`
	Data  json.RawMessage   `json:"data"`
	Index uint32            `json:"index"`
	Count uint32            `json:"count"`
}

type RMFetchResourceReply added in v0.1.8

type RMFetchResourceReply struct {
	Tag    ResourceTag       `json:"tag"`
	Status ResourceStatus    `json:"status"`
	Meta   map[string]string `json:"meta"`
	Data   []byte            `json:"data"`
	Index  uint32            `json:"index"`
	Count  uint32            `json:"count"`
}

type RMGetInvoice

type RMGetInvoice struct {
	PayScheme  string
	MilliAtoms uint64
	Tag        uint32
}

type RMGetPost

type RMGetPost struct {
	ID            zkidentity.ShortID `json:"id"`
	IncludeStatus bool               `json:"include_status"`
}

type RMGroupInvite

type RMGroupInvite struct {
	ID          zkidentity.ShortID `json:"id"`          // group id
	Name        string             `json:"name"`        // requested group name
	Token       uint64             `json:"token"`       // invite token
	Description string             `json:"description"` // group description
	Expires     int64              `json:"expires"`     // unix time when this invite expires
	Version     uint8              `json:"version"`     // version the GC is running on
}

RMGroupInvite invites a user to a group chat.

type RMGroupJoin

type RMGroupJoin struct {
	// XXX who sent this?
	ID    zkidentity.ShortID `json:"id"`    // group id
	Token uint64             `json:"token"` // invite token, implicitly identifies sender
	Error string             `json:"error"` // accept or deny Invite
}

RMGroupJoin instructs inviter that a user did or did not join the group.

type RMGroupKick

type RMGroupKick struct {
	Member       [zkidentity.IdentitySize]byte `json:"member"`       // kickee
	Reason       string                        `json:"reason"`       // why member was kicked
	Parted       bool                          `json:"parted"`       // kicked/parted
	NewGroupList RMGroupList                   `json:"newgrouplist"` // new GroupList
}

RMGroupKick kicks a naughty member out of the group chat.

type RMGroupKill

type RMGroupKill struct {
	// XXX who sent this?
	ID     zkidentity.ShortID `json:"id"`     // group id
	Reason string             `json:"reason"` // reason to disassemble group
}

RMGroupKill, sender is implicit to CRPC

type RMGroupList

type RMGroupList struct {
	ID         zkidentity.ShortID `json:"id"` // group id
	Name       string             `json:"name"`
	Generation uint64             `json:"generation"` // incremented every time list changes
	Timestamp  int64              `json:"timestamp"`  // unix time last generation changed
	Version    uint8              `json:"version"`    // version of the rules for GC op

	// Members is the list of GC participants. Members[0] is the "owner"
	// of the GC and has power over admins.
	Members []zkidentity.ShortID `json:"members"`

	// ExtraAdmins are additional admins. Members[0] is still considered
	// an admin in version 1 GCs.
	ExtraAdmins []zkidentity.ShortID `json:"extra_admins"`
}

RMGroupList defines a Group Chat channel.

type RMGroupMessage

type RMGroupMessage struct {
	ID         zkidentity.ShortID `json:"id"`         // group name
	Generation uint64             `json:"generation"` // Generation used
	Message    string             `json:"message"`    // Actual message
	Mode       MessageMode        `json:"mode"`       // 0 regular mode, 1 /me
}

RMGroupMessage is a message to a group.

type RMGroupPart

type RMGroupPart struct {
	// XXX who sent this?
	ID     zkidentity.ShortID `json:"id"`     // group id
	Reason string             `json:"reason"` // reason to depart group
}

RMGroupPart is sent to tell the group chat that a user has departed.

type RMGroupUpdateAdmins added in v0.1.6

type RMGroupUpdateAdmins struct {
	Reason       string      `json:"reason"`
	NewGroupList RMGroupList `json:"newgrouplist"`
}

RMGroupUpdateAdmins updates the list of extra admins in the GC.

type RMGroupUpgradeVersion added in v0.1.6

type RMGroupUpgradeVersion struct {
	NewGroupList RMGroupList `json:"newgrouplist"`
}

type RMHandshakeACK added in v0.1.8

type RMHandshakeACK struct{}

type RMHandshakeSYN added in v0.1.8

type RMHandshakeSYN struct{}

type RMHandshakeSYNACK added in v0.1.8

type RMHandshakeSYNACK struct{}

type RMHeader

type RMHeader struct {
	Version   uint64 `json:"version"`
	Timestamp int64  `json:"timestamp"`
	Command   string `json:"command"`
	Tag       uint32 `json:"tag"`

	Signature zkidentity.FixedSizeSignature `json:"signature,omitempty"`
}

func DecomposeRM

func DecomposeRM(msgVerifier MessageVerifier, mb []byte, maxDecompressSize uint) (*RMHeader, interface{}, error)

DecomposeRM decodes a message of up to maxDecompressSize bytes from mb.

type RMInvite

type RMInvite struct {
	Invitee zkidentity.PublicIdentity `json:"invitee"` // XXX why aren't we using Identity here?
}

RMInvite request an invite for third party.

type RMInvoice

type RMInvoice struct {
	Invoice string
	Tag     uint32
	Error   *string `json:"error,omitempty"`
}

type RMKXSearch

type RMKXSearch struct {
	Refs []RMKXSearchRef `json:"refs"`
}

RMKXSearch is sent when a user wishes to perform a transitive/recursive KX search for someone.

type RMKXSearchRef

type RMKXSearchRef struct {
	Type RMKXSearchRefType `json:"type"`
	Ref  string            `json:"ref"`
}

RMKXSearchRef identifies a specific reference that is being used to search for a user.

type RMKXSearchRefType

type RMKXSearchRefType string

RMKXSearchRefType identifies the type of a reference used in a kx search message.

const (
	KXSRTPostAuthor RMKXSearchRefType = "postauthor"
)

type RMKXSearchReply

type RMKXSearchReply struct {
	TargetID zkidentity.ShortID   `json:"target_id"`
	IDs      []zkidentity.ShortID `json:"ids"`
}

RMKXSearchReply is sent with a list of candidates the user might attempt to use to connect to target.

type RMKXSuggestion

type RMKXSuggestion struct {
	Target zkidentity.PublicIdentity
}

type RMListPosts

type RMListPosts struct{}

type RMListPostsReply

type RMListPostsReply struct {
	Posts []PostListItem `json:"posts"`
}

type RMMediateIdentity

type RMMediateIdentity struct {
	Identity [zkidentity.IdentitySize]byte `json:"identity"`
}

RMMediateIdentity as target to send a RMInvite on the caller's behalf. This should kick of an autokx.

type RMOFullKX

type RMOFullKX struct {
	FullKX ratchet.KeyExchange `json:"fullkx"`
}

RMOFullKX

func DecryptOOBFullKXBlob

func DecryptOOBFullKXBlob(packed []byte, key *zkidentity.FixedSizeSntrupPrivateKey, maxDecompressSize uint) (*RMOFullKX, error)

DecryptOOBFullKXBlob decrypts a packed RMOFullKX blob.

func NewFullKX

func NewFullKX(fkx *ratchet.KeyExchange) (*RMOFullKX, error)

NewFullKX creates a RMOFullKX structure from a full ratchet.

type RMOHalfKX

type RMOHalfKX struct {
	Public            zkidentity.PublicIdentity `json:"public"`
	HalfKX            ratchet.KeyExchange       `json:"halfkx"`
	InitialRendezvous ratchet.RVPoint           `json:"initialrendezvous"`
	ResetRendezvous   ratchet.RVPoint           `json:"resetrendezvous"`
}

RMOHalfKX is the command that flows after receiving an OOBPublicIdentityInvite.

func DecryptOOBHalfKXBlob

func DecryptOOBHalfKXBlob(packed []byte, key *zkidentity.FixedSizeSntrupPrivateKey, maxDecompressSize uint) (*RMOHalfKX, error)

DecryptOOBHalfKXBlob decrypts a packed RMOHalfKX blob.

func NewHalfKX

NewHalfKX creates a RMOHalfKX structure from a half ratchet.

us should be the public identity that is derived from the local client's full identity.

type RMOHeader

type RMOHeader struct {
	Version   uint64 `json:"version"`
	Timestamp int64  `json:"timestamp"`
	Command   string `json:"command"`
}

RMOHeader describes which command follows this structure.

func DecomposeRMO

func DecomposeRMO(mb []byte, maxDecompressSize uint) (*RMOHeader, interface{}, error)

type RMPostGet

type RMPostGet struct {
	Link string `json:"link"`
}

type RMPostGetReply

type RMPostGetReply struct {
	Attributes map[string]string `json:"attributes"`
	Error      *string           `json:"error,omitempty"`
}

type RMPostShare

type RMPostShare struct {
	Version    uint64            `json:"version"`
	Attributes map[string]string `json:"attributes"`
}

RMPostShare creates a new post.

type RMPostStatus

type RMPostStatus struct {
	Link       string            `json:"link"` // Link to post
	Attributes map[string]string `json:"attributes"`
}

RMPostStatusReply sets attributes such as status on a post. Attributes is a key value store that is used to describe the update attributes.

type RMPostStatusReply

type RMPostStatusReply struct {
	Error *string `json:"error,omitempty"`
}

type RMPostsSubscribe

type RMPostsSubscribe struct {
	// GetPost is an optional post to send to the client, assuming
	// subscribing to the posts worked.
	GetPost *zkidentity.ShortID `json:"get_post,omitempty"`

	// IncludeStatus also sends the post status updates if GetPost != nil.
	IncludeStatus bool `json:"include_status,omitempty"`
}

RMPostSubscribe subscribes to new posts from a user.

type RMPostsSubscribeReply

type RMPostsSubscribeReply struct {
	Error *string `json:"error,omitempty"`
}

type RMPostsUnsubscribe

type RMPostsUnsubscribe struct{}

RMPostUnsubscribe unsubscribes to new posts from a user.

type RMPostsUnsubscribeReply

type RMPostsUnsubscribeReply struct {
	Error *string `json:"error,omitempty"`
}

type RMPrivateMessage

type RMPrivateMessage struct {
	Mode    uint32 `json:"mode"`
	Message string `json:"message"`
}

type RMProfileUpdate added in v0.2.0

type RMProfileUpdate struct {
	// Avatar is the user's avatar. If set to nil, the avatar is not
	// updated. If set to an empty slice, the avatar is cleared.
	Avatar []byte `json:"avatar"`
}

RMProfileUpdate is a message sent by a client when it has updated one of its profile fields.

type RMReceiptDomain added in v0.1.10

type RMReceiptDomain string

RMReceiptDomain are the valid read receipt domains.

const (
	ReceiptDomainPosts        RMReceiptDomain = "posts"
	ReceiptDomainPostComments RMReceiptDomain = "postcomments"
)

type RMReceiveReceipt added in v0.1.10

type RMReceiveReceipt struct {
	// Domain is the type of receipt.
	Domain RMReceiptDomain

	// ID is the main ID of the receipt. Depends on the domain.
	//
	// post, postcomments : ID of the post.
	ID *zkidentity.ShortID

	// SubID is the secondary id of the receipt. Depends on the domain.
	//
	// posts: nil
	// postcomments: ID of the comment.
	SubID *zkidentity.ShortID

	// ClientTime is the unix millisecond timestamp of when the client
	// received.
	ClientTime int64
}

RMReceiveReceipt is a receipt sent by a client when it has received an RM for something. The fields set and their interpretation depends on the domain.

type RMTransitiveMessage

type RMTransitiveMessage struct {
	// For is the invitee identity and the corresponding public key that
	// was used to encrypt the InviteBlob.
	For zkidentity.ShortID `json:"for"`

	// CipherText contains a sntrup4591761 encapsulated shared key that is
	// used to encrypt the message. This ciphertext is decrypted by the
	// intended final recipient.
	CipherText zkidentity.FixedSizeSntrupCiphertext `json:"ciphertext,omitempty"`

	// Message is an encrypted json encoded structure.
	Message []byte `json:"message,omitempty"`
}

RMTransitiveMessage is a request to forward a message

type RMTransitiveMessageForward

type RMTransitiveMessageForward struct {
	// From is the sender identity. This is used as a hint to verify the
	// signature and identity inside Message.
	From zkidentity.ShortID `json:"from"`

	// CipherText contains a sntrup4591761 encapsulated shared key that is
	// used to encrypt the InviteBlob.
	CipherText zkidentity.FixedSizeSntrupCiphertext `json:"ciphertext"`

	// Message is an encrypted json encoded structure.
	Message []byte `json:"message"`
}

RMTransitiveMessageForward forwards a transitive message to a user.

type RMTransitiveMessageReply

type RMTransitiveMessageReply struct {
	// For is the intended recipient that needs Message routed.
	For zkidentity.ShortID `json:"for"`

	// Error is set if the other side encountered an error.
	Error *string `json:"error,omitempty"`
}

RMTransitiveMessageReply is a reply to a transitive message.

type RMTransitiveReset

type RMTransitiveReset struct {
	HalfKX ratchet.KeyExchange `json:"halfkx"` // Half ratchet
}

type RMTransitiveResetReply

type RMTransitiveResetReply struct {
	FullKX ratchet.KeyExchange `json:"fullkx"` // Full ratchet
}

type RMUser

type RMUser struct{}

RMUser retrieves user attributes such as status, profile etc. Attributes is a key value store that is used to describe the user attributes.

type RMUserReply

type RMUserReply struct {
	Identity   [sha256.Size]byte `json:"identity"`
	Attributes map[string]string `json:"attributes"`
}

type ResourceStatus added in v0.1.8

type ResourceStatus uint16

func (ResourceStatus) String added in v0.1.8

func (rs ResourceStatus) String() string

type ResourceTag added in v0.1.8

type ResourceTag uint64

func (*ResourceTag) FromString added in v0.1.8

func (tag *ResourceTag) FromString(s string) error

func (ResourceTag) MarshalJSON added in v0.1.8

func (tag ResourceTag) MarshalJSON() ([]byte, error)

MarshalJSON marshals the id into a json string.

func (ResourceTag) String added in v0.1.8

func (tag ResourceTag) String() string

func (*ResourceTag) UnmarshalJSON added in v0.1.8

func (tag *ResourceTag) UnmarshalJSON(b []byte) error

UnmarshalJSON unmarshals the json representation of a ShortID.

type RouteMessage

type RouteMessage struct {
	Rendezvous    ratchet.RVPoint
	PaidInvoiceID []byte
	Message       []byte
}

RouteMessage is a hack

type RouteMessageReply

type RouteMessageReply struct {
	Error       string
	NextInvoice string
}

type ServerProperty

type ServerProperty struct {
	Key      string // name of property
	Value    string // value of property
	Required bool   // if true client must handle this entry
}

func SupportedServerProperties

func SupportedServerProperties() []ServerProperty

type SubscribeRoutedMessages

type SubscribeRoutedMessages struct {
	AddRendezvous []ratchet.RVPoint // Add to subscribed RVs
	DelRendezvous []ratchet.RVPoint // Del from subscribed RVs
	MarkPaid      []ratchet.RVPoint // Mark paid but do not subscribe
}

type SubscribeRoutedMessagesReply

type SubscribeRoutedMessagesReply struct {
	NextInvoice string
	Error       string
}

type TxHash added in v0.1.7

type TxHash chainhash.Hash

func (*TxHash) FromString added in v0.1.7

func (u *TxHash) FromString(s string) error

FromString decodes s into a TxHash. s must contain an hex-encoded ID of the correct length.

func (TxHash) MarshalJSON added in v0.1.7

func (u TxHash) MarshalJSON() ([]byte, error)

MarshalJSON marshals the id into a json string.

func (TxHash) String added in v0.1.7

func (u TxHash) String() string

String returns the string representation of the tx hash.

func (*TxHash) UnmarshalJSON added in v0.1.7

func (u *TxHash) UnmarshalJSON(b []byte) error

UnmarshalJSON unmarshals the json representation of a ShortID.

type Welcome

type Welcome struct {
	Version    int   // protocol version
	ServerTime int64 // server timestamp

	// Client shall ensure it is compatible with the server requirements
	Properties []ServerProperty // server properties
}

Welcome is written immediately following a key exchange. This command purpose is to detect if the key exchange completed on the client side. If the key exchange failed the server will simply disconnect.

Jump to

Keyboard shortcuts

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