1
1
# SaltyRTC WebRTC Task for Java
2
2
3
- [ ![ Java Version] ( https://img.shields.io/badge/java-8%2B-orange.svg )] ( https://github.com/saltyrtc/saltyrtc-client-java )
4
- [ ![ License] ( https://img.shields.io/badge/license-MIT%20%2F%20Apache%202.0-blue.svg )] ( https://github.com/saltyrtc/saltyrtc-client-java )
3
+ [ ![ Build status] ( https://circleci.com/gh/saltyrtc/saltyrtc-task-webrtc-java.svg?style=shield&circle-token=:circle-token )] ( https://circleci.com/gh/saltyrtc/saltyrtc-task-webrtc-java )
4
+ [ ![ Java Version] ( https://img.shields.io/badge/java-8%2B-orange.svg )] ( https://github.com/saltyrtc/saltyrtc-task-webrtc-java )
5
+ [ ![ License] ( https://img.shields.io/badge/license-MIT%20%2F%20Apache%202.0-blue.svg )] ( https://github.com/saltyrtc/saltyrtc-task-webrtc-java )
5
6
[ ![ Chat on Gitter] ( https://badges.gitter.im/saltyrtc/Lobby.svg )] ( https://gitter.im/saltyrtc/Lobby )
6
7
7
8
This is a [ SaltyRTC] ( https://github.com/saltyrtc/saltyrtc-meta ) [ WebRTC
8
9
task] ( https://github.com/saltyrtc/saltyrtc-meta/blob/master/Task-WebRTC.md )
9
10
implementation for Java 8+.
10
11
11
- For now, as long as ` RTCPeerConnection ` only works on Android, this library
12
- will not work outside of projects.
13
-
14
- The development is still ongoing, the current version is only at alpha-level
15
- and should not be used for production yet.
16
-
17
12
For an application example, please see our [ demo
18
13
application] ( https://github.com/saltyrtc/saltyrtc-demo ) .
19
14
20
15
21
16
## Installing
22
17
23
18
The package is available [ on
24
- Bintray] ( https://bintray.com/saltyrtc/maven/saltyrtc-client/ ) .
19
+ Bintray] ( https://bintray.com/saltyrtc/maven/saltyrtc-task-webrtc ) .
25
20
26
21
Gradle:
27
22
@@ -43,70 +38,171 @@ Maven:
43
38
44
39
## Usage
45
40
46
- Instantiate the task.
41
+ To create the task instance, you need to use the ` WebRTCTaskBuilder ` instance
42
+ which can be used to configure the task before creating it.
43
+
44
+ The below configuration represents the default values chosen by the builder as
45
+ if you had not configured the builder and just called ` .build() ` directly.
47
46
48
47
``` java
49
- final WebRTCTask task = new WebRTCTask ();
48
+ final WebRTCTask task = new WebRTCTaskBuilder ()
49
+ .withVersion(WebRTCTaskVersion . V1 )
50
+ .withHandover(true )
51
+ .withMaxChunkLength(262144 )
52
+ .build();
50
53
```
51
54
52
- Then, register a message handler:
55
+ To send offers, answers and candidates, use the following task methods:
56
+
57
+ * ` task.sendOffer(offer: @NonNull Offer): void `
58
+ * ` task.sendAnswer(answer: @NonNull Answer): void `
59
+ * ` task.sendCandidates(candidate: @NonNull Candidate[]): void `
60
+
61
+ You can register an event handler in the following way:
53
62
54
63
``` java
55
64
task. setMessageHandler(new MessageHandler () {
56
65
@Override
57
- public void onOffer (SessionDescription sd ) {
66
+ public void onOffer (@NonNull Offer offer ) {
58
67
// Handle offer
59
68
}
60
69
61
70
@Override
62
- public void onAnswer (SessionDescription sd ) {
71
+ public void onAnswer (@NonNull Answer answer ) {
63
72
// Handle answer
64
73
}
65
74
66
75
@Override
67
- public void onCandidates (List<IceCandidate > candidates ) {
68
- for (IceCandidate candidate : candidates) {
69
- peerConnection. addIceCandidate(candidate);
70
- }
76
+ public void onCandidates (@NonNull Candidate [] candidates ) {
77
+ // Handle candidates
71
78
}
72
79
});
73
80
```
74
81
75
- Finally, pass the task instance to the ` SaltyRTCBuilder ` through the
76
- ` .usingTasks(...) ` method.
82
+ ### Data Channel Crypto Context
83
+
84
+ The task provides another security layer for data channels which can be
85
+ leveraged by usage of a ` DataChannelCryptoContext ` instance. To retrieve such
86
+ an instance, call:
87
+
88
+ ``` java
89
+ final DataChannelCryptoContext context = task. createCryptoContext(dataChannel. id);
90
+ ```
91
+
92
+ You can encrypt messages on the sending end in the following way:
93
+
94
+ ``` java
95
+ final Box box = context. encrypt(yourData);
96
+ dataChannel. send(ByteBuffer . wrap(box. toBytes()));
97
+ ```
98
+
99
+ On the receiving end, decrypt the message by the use of the crypto context:
100
+
101
+ ``` java
102
+ final Box box = new Box (message);
103
+ final byte [] yourData = context. decrypt(
104
+ box, DataChannelCryptoContext . NONCE_LENGTH );
105
+ ```
77
106
78
- Once the signaling channel is open, create offer/answer/candidates as usual and
79
- send them through the signaling channel using the corresponding methods:
107
+ Note, that you should not use a crypto context for a data channel that is being
108
+ used for handover. The task will take care of encryption and decryption itself.
80
109
81
- - ` task.sendOffer(offer) `
82
- - ` task.sendAnswer(answer) `
83
- - ` task.sendCandidates(candidates) `
110
+ ### Handover
111
+
112
+ Before initiating the handover, the application needs to fetch the
113
+ ` SignalingTransportLink ` instance which contains the necessary information to
114
+ create a data channel.
115
+
116
+ ``` java
117
+ final SignalingTransportLink link = task. getTransportLink();
118
+
119
+ final DataChannel . Init parameters = new DataChannel .Init ();
120
+ parameters. id = link. getId();
121
+ parameters. negotiated = true ;
122
+ parameters. ordered = true ;
123
+ parameters. protocol = link. getProtocol();
124
+
125
+ final DataChannel dataChannel = peerConnection. createDataChannel(
126
+ link. getLabel(), parameters);
127
+ ```
128
+
129
+ Note that the data channel used for handover ** must** be created with the
130
+ label and parameters as shown in the above code snippet.
131
+
132
+ Now that you have created the channel, you need to implement the
133
+ ` ISignalingTransportHandler ` interface. Below is a minimal handler that forwards
134
+ the necessary events and messages to the created data channel.
135
+
136
+ ``` java
137
+ final ISignalingTransportHandler handler = new ISignalingTransportHandler () {
138
+ @Override
139
+ public long getMaxMessageSize () {
140
+ return peerConnection. sctp(). getMaxMessageSize();
141
+ }
142
+
143
+ @Override
144
+ public void close () {
145
+ dataChannel. close();
146
+ }
147
+
148
+ @Override
149
+ public void send (@NonNull final ByteBuffer message ) {
150
+ // Note: Always send binary
151
+ dataChannel. send(new DataChannel .Buffer (message, true ));
152
+ }
153
+ };
154
+ ```
84
155
85
- As soon as the data channel is open, request a handover of the signaling channel:
156
+ Furthermore, you have to bind all necessary events in order to connect the data
157
+ channel to the ` SignalingTransportLink ` .
86
158
87
159
``` java
88
- dc . registerObserver(new DataChannel .Observer () {
89
- // ...
160
+ dataChannel . registerObserver(new DataChannel .Observer () {
161
+ // [ ...]
90
162
91
163
@Override
92
164
public void onStateChange () {
93
- if (dc. state() == DataChannel . State . OPEN ) {
94
- task. handover();
165
+ switch (dataChannel. state()) {
166
+ case OPEN :
167
+ task. handover(handler);
168
+ break ;
169
+ case CLOSING :
170
+ link. closing();
171
+ break ;
172
+ case CLOSED :
173
+ link. closed();
174
+ break ;
95
175
}
96
176
}
177
+
178
+ @Override
179
+ public void onMessage (@NonNull final DataChannel .Buffer buffer ) {
180
+ if (! buffer. binary) {
181
+ // Note: This should be handled as a protocol error
182
+ task. close(CloseCode . PROTOCOL_ERROR );
183
+ } else {
184
+ link. receive(buffer. data);
185
+ }
186
+ }
187
+
188
+ // [...]
97
189
});
98
190
```
99
191
100
- To know when the handover is done, subscribe to the SaltyRTC ` handover ` event.
192
+ The above setup will forward the ` CLOSING ` /` CLOSED ` state and all messages to
193
+ the task by the use of the ` SignalingTransportLink ` . On ` OPEN ` , the handover
194
+ will be initiated.
101
195
196
+ To be signalled once the handover is finished, you need to register the
197
+ ` handover ` event on the SaltyRTC client instance.
102
198
103
- ## Logging
199
+ ### Logging
104
200
105
201
The library uses the slf4j logging API. Configure a logger (e.g. slf4j-simple)
106
202
to see the log output.
107
203
108
204
109
- ## Testing
205
+ ## Manual Testing
110
206
111
207
To try a development version of the library, you can build a local version to
112
208
the maven repository at ` /tmp/maven ` :
@@ -121,7 +217,76 @@ Include it in your project like this:
121
217
}
122
218
123
219
124
- ## Hashes
220
+ ## Coding Guidelines
221
+
222
+ Unfortunately we cannot use all Java 8 features, in order to be compatible with
223
+ Android API <24. Please avoid using the following APIs:
224
+
225
+ - ` java.lang.annotation.Repeatable `
226
+ - ` AnnotatedElement.getAnnotationsByType(Class) `
227
+ - ` java.util.stream `
228
+ - ` java.lang.FunctionalInterface `
229
+ - ` java.lang.reflect.Method.isDefault() `
230
+ - ` java.util.function `
231
+
232
+ The CI tests contains a script to ensure that these APIs aren't being called.
233
+ You can also run it manually:
234
+
235
+ bash .circleci/check_android_support.sh
236
+
237
+
238
+ ## Automated Testing
239
+
240
+ ### 1. Preparing the Server
241
+
242
+ First, clone the ` saltyrtc-server-python ` repository.
243
+
244
+ git clone https://github.com/saltyrtc/saltyrtc-server-python
245
+ cd saltyrtc-server-python
246
+
247
+ Then create a test certificate for localhost, valid for 5 years.
248
+
249
+ openssl req -new -newkey rsa:1024 -nodes -sha256 \
250
+ -out saltyrtc.csr -keyout saltyrtc.key \
251
+ -subj '/C=CH/O=SaltyRTC/CN=localhost/'
252
+ openssl x509 -req -days 1825 \
253
+ -in saltyrtc.csr \
254
+ -signkey saltyrtc.key -out saltyrtc.crt
255
+
256
+ Create a Java keystore containing this certificate.
257
+
258
+ keytool -import -trustcacerts -alias root \
259
+ -file saltyrtc.crt -keystore saltyrtc.jks \
260
+ -storetype JKS -storepass saltyrtc -noprompt
261
+
262
+ Create a Python virtualenv with dependencies:
263
+
264
+ python3 -m virtualenv venv
265
+ venv/bin/pip install .[logging]
266
+
267
+ Finally, start the server with the following test permanent key:
268
+
269
+ export SALTYRTC_SERVER_PERMANENT_KEY=0919b266ce1855419e4066fc076b39855e728768e3afa773105edd2e37037c20 # Public: 09a59a5fa6b45cb07638a3a6e347ce563a948b756fd22f9527465f7c79c2a864
270
+ venv/bin/saltyrtc-server -v 5 serve -p 8765 \
271
+ -sc saltyrtc.crt -sk saltyrtc.key \
272
+ -k $SALTYRTC_SERVER_PERMANENT_KEY
273
+
274
+ ### 2. Running Tests
275
+
276
+ Make sure that the certificate keystore from the server is copied or symlinked
277
+ to this repository:
278
+
279
+ ln -s path/to/saltyrtc-server-python/saltyrtc.jks
280
+
281
+ With the server started in the background and the ` saltyrtc.jks ` file in the
282
+ current directory, run the tests:
283
+
284
+ ./gradlew test
285
+
286
+
287
+ ## Security
288
+
289
+ ### Release Checksums
125
290
126
291
These are the SHA256 hashes for the published releases of this project:
127
292
@@ -152,6 +317,22 @@ You can use tools like [gradle
152
317
witness] ( https://github.com/WhisperSystems/gradle-witness ) to make sure that
153
318
your application always gets the correct version of this library.
154
319
320
+ ### Responsible Disclosure / Reporting Security Issues
321
+
322
+ Please report security issues directly to one or both of the following contacts:
323
+
324
+ - Danilo Bargen
325
+
326
+ - Threema: EBEP4UCA
327
+ - GPG: [ EA456E8BAF0109429583EED83578F667F2F3A5FA] [ keybase-dbrgn ]
328
+ - Lennart Grahl
329
+
330
+ - Threema: MSFVEW6C
331
+ - GPG: [ 3FDB14868A2B36D638F3C495F98FBED10482ABA6] [ keybase-lgrahl ]
332
+
333
+ [ keybase-dbrgn ] : https://keybase.io/dbrgn
334
+ [ keybase-lgrahl ] : https://keybase.io/lgrahl
335
+
155
336
156
337
## License
157
338
0 commit comments