saltyrtc / saltyrtc-meta

Protocol description and organisational information for SaltyRTC implementations.
MIT License
74 stars 8 forks source link

Public API for clients #38

Closed dbrgn closed 8 years ago

dbrgn commented 8 years ago

This is not directly something related to the protocol, but should be implemented consistently across all clients. Therefore the issue in the meta repo.

How should we design the public API?

Right now, it works as follows in the Java version:

// create new instance
KeyStore permanentKey = new KeyStore();
SaltyRTC salty = new SaltyRTC(permanentKey, host, port, sslContext);
salty.connect()

// Wait until connected
salty.events.signalingStateChanged.register(new EventHandler<SignalingStateChangedEvent>() {
    @Override
    public boolean handle(SignalingStateChangedEvent event) {
        if (event.getState() == SignalingState.CONNECTED) {
            LOG.info("Connected!");
        }
    }
});

// Retrieve public permanent key and auth token
byte[] key = salty.getPublicPermanentKey();
byte[] token = salty.getAuthToken();

// Get current state
SignalingState state = salty.getSignalingState();

// Get current signaling channel
SignalingChannel channel = salty.getSignalingChannel();

// Send signaling data (e.g. offer, answer, ICE candidates)
salty.sendSignalingData(new Data("offer", "offer-string"));

// Wait for data (e.g. offer, answer, ICE candidates)
salty.events.data.register(new EventHandler<DataEvent>() {
    @Override
    public boolean handle(DataEvent event) {
        if (event.getData().getType() == "answer") {
            // handle
        }
    }
});

// Do handover
salty.handover(peerConnection);

Now the question is how to send user data. One approach is to wrap a data channel.

SecureDataChannel sc = salty.wrap(dataChannel);

The other approach would be to send data through the SaltyRTC instance.

salty.sendData(dataChannel, data);

I'd favor the second approach because it does not require wrapping (more code, more complexity, presence of encryption is not directly visible, more complexity decreases security). Otherwise users might mix up secure and non-secure data channels.

(Note that this does not yet consider the tasks system. But tasks need to be implementable outside of SaltyRTC, so it would not change much about the basics.)

lgrahl commented 8 years ago

I believe we should discuss what changes must be made to the API to support tasks first and then decide which way to follow. The result of this discussion should probably end up as a recommended API in the spec.

dbrgn commented 8 years ago

Another issue: Should we allow sending of strings through the wrapped data channel?

The current browser API supports sending of strings, blobs and arraybuffers. By simply encrypting and passing on data, we can handle arraybuffers, but not the other two. The problem is that we always encrypt bytes. If we encrypt multiple possible types, the receiver must know the type of the encoding.

I'm not sure how the DataChannel itself handles it, but we can't rely on that, as we always send encoded bytes. A workaround would be to prepend an encoding byte to the message before encrypting it.

Status quo: The user can only send binary data. That means that JSON must be manually encoded to UTF-8 on one side and decoded on the other side.

The other option would be to always use msgpack encoding instead of leaving the encoding up to the user. This way the user could also send simple objects directly through the data channel without worrying about encoding. (Note that this is not something that's supported by the data channel API.)

And a third option would be to offer both APIs: The regular secureDataChannel.send(data: ArrayBuffer) method and additionally a secureDataChannel.sendObject(data: string | object) method that would use msgpack.

I tend to stick to binary data only. Making it hard to send JSON is the biggest downside though.

lgrahl commented 8 years ago

The underlying SCTP protocol tells the data channels whether data is binary or string. That doesn't help us though as the data will always be binary.

For me it would be fine to tell the user that we only accept binary for now. I'd also be okay with a task that negotiates this (either binary only or a byte indicating which type is being used). But that's an improvement we can add to the specific task later on.

dbrgn commented 8 years ago

Let's close this, as the implementations are already done. If the need for API changes arises, we can still open tickets for that.