-
Notifications
You must be signed in to change notification settings - Fork 7
/
index.bs
856 lines (645 loc) · 35.9 KB
/
index.bs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
<pre class='metadata'>
Title: Local Peer-to-Peer API
Shortname: local-peer-to-peer
Level: 1
Status: CG-DRAFT
Group: WICG
Repository: WICG/local-peer-to-peer
URL: https://WICG.github.io/local-peer-to-peer/
Editor: Anssi Kostiainen, Intel https://intel.com, anssi.kostiainen@intel.com
Editor: Belem Zhang, Intel https://intel.com, belem.zhang@intel.com
Editor: Michiel De Backker, Twintag https://twintag.com, mail@backkem.me
Editor: Wei Wang, Intel https://intel.com, wei4.wang@intel.com
!Tests: <a href=https://github.com/w3c/web-platform-tests/tree/master/local-peer-to-peer>web-platform-tests local-peer-to-peer/</a> (<a href=https://github.com/w3c/web-platform-tests/labels/local-peer-to-peer>ongoing work</a>)
Abstract: Local Peer-to-Peer is a Web platform API proposal for local communication between browsers without the aid of a server.
Markup Shorthands: markdown yes, dfn yes, idl yes, markup yes
</pre>
Note: This specification is under active development and therefore incomplete. If you're looking for an overview of the proposal, please refer to the [Explainer](https://github.com/WICG/local-peer-to-peer/blob/main/EXPLAINER.md).
Introduction {#intro}
=====================
*This section is non-normative.*
The Local Peer-to-Peer API aims to give browsers the means to communicate directly, without the aid of a server in the middle. It is designed to enable this communication within the confines of a [=local communication medium=].
Many modern Web security measures rely on the presence of naming, signaling and certificate authorities. Local use-cases where these authorities are not readily available have started lagging behind in user experience or are not supported altogether. The Local Peer-to-Peer API aims to bring back first-class support for local communication use-cases while working within the same strict user-friendliness, security and privacy requirements.
Examples of potential uses of this API include: Collaboration tools that work during an internet outage or emergency situations, connecting to your NAS, your home security system, your robotic assistant doing the dishes or your GPU farm in the basement that's running your personalized virtual assistant. See also [Use Cases](https://github.com/WICG/local-peer-to-peer/blob/main/EXPLAINER.md#use-cases).
This specification aims to strike a balance between creating a powerful new building block for developers and providing a seamless, secure and privacy preserving experience for browser users. As an example: while the API doesn't provide raw socket access, it does aim to give developers the flexibility to innovate on top by providing a persistent, two-way communication channel with little overhead.
The API is designed to be backed by an authenticated, streams-based transport. As a commitment to an open standards-based implementation path, this specification describes how the API can be implemented on top of the [[!openscreenprotocol|Open Screen Protocol]]. While not described here, the API is expected to be implementable on top of other transports when technically feasible.
Terminology {#terminology}
======================================================
The term <dfn>local communication medium</dfn> refers to a communication medium that provides a local, direct communication channel between the communicating devices. This is a purposefully broad term that covers any medium that can be used to establish a an authenticated, streams-based transport between the devices. Examples may include but are not limited to: a wired or wireless local area network, a Thread network, Bluetooth Low Energy or Wi-Fi Direct. This spec will not mandate which underlying technologies must be supported.
The term <dfn>local communication</dfn> refers to data communication over the [=local communication medium=].
The term <dfn>communication medium topology</dfn> refers to the composition of the [=local communication medium=] which may include sensitive information such as IP or other address information or the number of devices connected to the medium.
Permission Policy Integration {#permission-policy-integration}
======================================================
The Local Peer-to-Peer API defines a [=policy-controlled feature=] identified by the token "local-peer-to-peer". Its [=default allowlist=] is `"self"`.
Workers (dedicated and shared) adhere to the permission policy set by their owning document(s):
<ul>
<li>
Dedicated workers can be created from other workers, in which case the permission policy of the first owning document (in case of a dedicated worker) or owning documents (in case of a shared worker) up the owner chain will be used.
</li>
<li>
Shared workers often have multiple owning documents as they can be obtained by other documents with the [=same origin=]. In this case, all owning documents must be [=allowed to use=] the [=policy-controlled feature=] defined by this specification.
</li>
</ul>
Note: There has been discussion on allowing setting permission policy directly on a worker on creation, in which case that would have to be consulted as well.
The [=policy-controlled feature/default allowlist=] of `"self"` allows usage in same-origin nested frames but prevents third-party content from using the feature. Third-party content usage can be selectively enabled by adding `allow="local-peer-to-peer"` attribute to the frame container element:
<pre class="example" title= "Enabling Local Peer-to-Peer API on third-party content" highlight='js'>
<iframe src="https://third-party.com" allow="local-peer-to-peer"/></iframe>
</pre>
Alternatively, the Local Peer-to-Peer API can be disabled completely by specifying the permissions policy in a HTTP response header:
<pre class="example" title="Permission Policy over HTTP" highlight='js'>
Permissions-Policy: local-peer-to-peer=()
</pre>
See [[!PERMISSIONS-POLICY]] for more details.
Peer Management {#peer-management}
==================================
Note: This section and its subsections use RFC 2119 terminology in a relaxed manner. These sections will be converted into well-defined algorithmic normative prose informed by further implementation experience. For now, this relaxed description better allows for rapid prototyping.
The user agent is in charge of managing peers.
A <dfn>peer</dfn> is an equal participant in the [=local communication=]. These nodes can communicate without the need for a central coordination by a server.
A user agent has an associated <dfn>local peer-to-peer manager</dfn> in charge of managing [=peers=]. Its responsibility is to [=start local peer discovery=], [=establish local peer connections=] and [=acquire a local peer grant=] on a per-origin basis. This is done to avoid exposing information about the [=communication medium topology=].
Known peers {#known-peers}
--------------------------
The user agent should maintain a list of peers that it has knowledge of.
The [=local peer-to-peer manager=] has an associated <dfn>known peers map</dfn>, an [=/ordered map=] of [=known peers=]. Each <dfn>known peer</dfn> is a [=peer=] that has an associated <dfn>authentication state</dfn> and <dfn>peer grant state</dfn>. The user agent keeps track of the [=authentication state=] per peer and the [=peer grant state=] per peer, per origin. Unless [=persisted=], both the states are initially false.
Note: The [=peer grant state=] is origin-level while the [=authentication state=] is peer-level. The rationale is to not require the user to undergo authentication multiple times between the same peers. This design may change informed by security and privacy considerations.
Issue(wicg/local-peer-to-peer#24): See also related
The user agent may persist known peers, their [=authentication states=] and/or [=peer grant states=]. If the user agent chooses to do so, it must do so in accordance with the [[!openscreenprotocol|Open Screen Protocol]] Persistent State rules. Such a peer or its state is said to be <dfn>persisted</dfn>.
Peer advertisement {#peer-advertisement}
----------------------------------------
The user agent can make itself discoverable by advertising using the [=session/advertise agent=] capability.
Note: The user agent must get the user's explicit consent in order to start advertising.
When advertising, the user agent must listen for incoming peer connections. In case a connection is received, the peer is added to the [=known peers map=]. The user agent must not directly provide access to the incoming peer connection to any origin. Instead, the user agent must prompt to [grant peer](#peer-grant) access to the origin that initiated peer advertisement.
Peer discovery {#peer-discovery}
--------------------------------
The user agent can discover local peers using the [=session/discover agents=] capability.
When asked to <dfn>start local peer discovery</dfn>, the user agent discovers local peers using the [=session/discover agents=] capability.
If a peer is discovered, the user agent should add it to the [=known peers map=]. The user agent must never expose the full result of peer discovery with an origin. Instead, the user agent must [=acquire a local peer grant=] to grant access to a peer for the origin that initiated the peer request.
Peer authentication {#peer-authentication}
------------------------------------------
The user agent can initiate authentication with a peer using the [=session/authenticate an agent=] capability.
When asked to <dfn>authenticate a local peer</dfn>, the user agent must initiate authentication with a local peer using the [=session/authenticate an agent=] capability. The peer's [=authentication state=] must be set to true if authentication succeeds, otherwise false.
A peer is said to be <dfn>authenticated</dfn> when its [=authentication state=] is true.
Peer grant {#peer-grant}
------------------------------------
The user agent, with the user's consent, must [=acquire a local peer grant=] for an origin to get access to a peer.
Note: The user agent must get the user's explicit consent in order to grant an origin access to a peer. For enhanced privacy protection, the user agent must provide means to dismiss any related user interface and this action must not be detectable by script or have script-observable side-effects. The user interface may provide means to revoke the grant or to make the grant [=persisted=].
When asked to <dfn>acquire a local peer grant</dfn>, the user agent displays the [=known peers=] to the user through its native user interface. When the user selects a peer from the user interface, the user agent must check the selected peer is [=authenticated=], and run the [=authenticate a local peer=] algorithm otherwise, and set the [=peer grant state=] according to the user's explicit selection.
Protocol concepts {#protocol-concepts}
======================================
When asked to <dfn>establish local peer connection</dfn>, the user agent ...
A <dfn for="protocol">Local Peer-to-Peer session</dfn> represents an authenticated [[!RFC9000|QUIC]] connection as defined in [[!openscreenprotocol|Open Screen Protocol]] or OSP.
A [=Local Peer-to-Peer session=] has the following capabilities:
<table class="data" dfn-for="session">
<thead>
<tr>
<th>capability
<th>definition
</tr>
</thead>
<tbody>
<tr>
<td><dfn>advertise agent</dfn>
<td>[[!openscreenprotocol]]
[discovery](https://www.w3.org/TR/openscreenprotocol/#discovery)
</tr>
<tr>
<td><dfn>discover agents</dfn>
<td>[[!openscreenprotocol]]
[discovery](https://www.w3.org/TR/openscreenprotocol/#discovery)
</tr>
<tr>
<td><dfn>discover metadata</dfn>
<td>[[!openscreenprotocol]]
[transport](https://www.w3.org/TR/openscreenprotocol/#transport)
</tr>
<tr>
<td><dfn>authenticate an agent</dfn>
<td>[[!openscreenprotocol]]
[authentication](https://www.w3.org/TR/openscreenprotocol/#authentication)
</tr>
<tr>
<td>[=open a data channel=]
<td>[[#data-channel-extension]]
</tr>
<tr>
<td>[=send data on a channel=]
<td>[[#data-channel-extension]]
</tr>
<tr>
<td>[=open a WebTransport session=]
<td>[[#webtransport-extension]]
</tr>
</tbody>
</table>
Part of these capabilities are defined below as [protocol extensions](https://www.w3.org/TR/openscreenprotocol/#protocol-extensions) to the [[!openscreenprotocol|Open Screen Protocol]].
Data channel extension {#data-channel-extension}
------------------------------------------------
In order to signal support for this protocol extension, the agent should include the [=data-channels=] [=agent-capability=] as part of the [agent-info-response](https://www.w3.org/TR/openscreenprotocol/#agent-info-response) message exchanged during [=discover metadata=].
To <dfn>open a data channel</dfn> an agent may send a [=data-channel-open-request=] message on a new [[!RFC9000|QUIC]] stream. The [=Local Peer-to-Peer session=] must be authenticated. The message must contain the following values:
: channel-id
:: An ID number (between 0 and 65,534) which uniquely identifies the data channel. Must not be empty.
: label
:: a string that contains a name describing the data channel. These labels are not required to be unique.
: protocol
:: a string containing the name of the subprotocol in use. If no protocol was specified when the data channel was created, then this property's value is the empty string ("").
When the receiver receives the [=data-channel-open-request=], it should send back a [=data-channel-open-response=] message. The response must include the following:
: result
:: a code indicating success or failure, and the reason for the failure.
If the [=data-channel-open-response=] message indicates success, the data channel is considered open. Agents can now <dfn>send data on a channel</dfn> by sending [=data-frame=] messages on the same [[!RFC9000|QUIC]] stream the data channel was opened. The message must include the following:
: encoding-id
:: Determines the encoding of the data being sent. The values are specified as [=data-channel-encoding-id=]:
0: [=encoding-id-blob|Blob=];
1: [=encoding-id-string|String=];
2: [=encoding-id-array-buffer|ArrayBuffer=].
: payload
:: The binary representation of the data being sent.
WebTransport extension {#webtransport-extension}
------------------------------------------------
The protocol extension to [=send data on a channel=] provides an ergonomic way to send simple messages. An agent can [=open a WebTransport session=] for communication that requires low overhead and more granular streams control.
In order to signal support for this protocol extension, the agent should include the [=quick-transport=] [=agent-capability=] as part of the [agent-info-response](https://www.w3.org/TR/openscreenprotocol/#agent-info-response) message exchanged during [=discover metadata=].
An agent can <dfn>open a WebTransport session</dfn> by dialing a new [[!RFC9000|QUIC]] connection using the agent certificates established during [=authenticate an agent=]. During connection establishment, the ALPN token "q2q" must be used in the TLS handshake.
The capabilities of the Local WebTransport session are defined in [[!webtransport]].
Note: The WebTransport-over-QUIC protocol is yet to be defined. Potentially considering earlier work such as [draft-vvv-webtransport-quic](https://datatracker.ietf.org/doc/html/draft-vvv-webtransport-quic-02).
<section algorithm="LP2PReceiver">
Local HTTPS {#local-https}
==========================
Authentication establishes a mutual trust anchor between peers on the [=local communication medium=]. This trust anchor can also be used to validate certificates used by HTTP servers on the [=local communication medium=]. An Open Screen Protocol agent certificate can be identified by the common name of its subject ending in "._openscreen._udp". When a user agent loads a webpage and finds an agent certificate in the certificate chain, it can use it as a trust anchor for authentication of the server. If the corresponding agent is not [=authenticated=], the user agent should prompt the user to authenticate the agent before proceeding with certificate validation.
Endpoint discovery {#local-https-discovery}
-------------------------------------------
If a peer is [=authenticated=], it may advertize one or more HTTPS endpoints it provides. A user agent may display these to the user to connect to servers on the [=local communication medium=] without knowledge of the corresponding hostname and/or IP address.
Issue: define endpoint-info messages
LP2PReceiver Interface {#lp2p-receiver}
================================================
The <dfn interface>LP2PReceiver</dfn> interface allows advertising on the [=local communication medium=], enabling other peers to discover and connect.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PReceiver : EventTarget {
constructor(optional LP2PReceiverOptions options = {});
attribute EventHandler onconnection;
Promise<undefined> start();
};
</pre>
LP2PReceiverOptions {#lp2p-receiver-options}
---------------------------------
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
dictionary LP2PReceiverOptions {
DOMString nickname;
};
</pre>
LP2PConnectionEvent {#lp2p-receiver-connection-event}
----------------------------------------------------
Issue: In general, when defining a new interface that inherits from Event please always ask feedback from the WHATWG or the W3C WebApps WG community. See [defining event interfaces](https://dom.spec.whatwg.org/#defining-event-interfaces).
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PConnectionEvent : Event {
constructor(DOMString type, LP2PConnectionEventInit connectionEventInitDict);
readonly attribute LP2PConnection connection;
};
dictionary LP2PConnectionEventInit : EventInit {
required LP2PConnection connection;
};
</pre>
Events {#lp2p-receiver-events}
------------------------------
The following event is [=fire an event|fired=] at the {{LP2PReceiver}} object:
<table class="data">
<thead>
<tr>
<th>Event name</th>
<th>Interface</th>
<th>Fired when…</th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn event for="LP2PReceiver"><code>connection</code></dfn></td>
<td>{{LP2PConnectionEvent}}</td>
<td>An incoming connection is received.</td>
</tr>
</tbody>
</table>
Event handlers {#lp2p-receiver-event-handlers}
----------------------------------------------
The following are the <a>event handlers</a> (and their corresponding <a>event handler event types</a>) that must be supported, as <a>event handler IDL attributes</a>, by all objects implementing the [[#lp2p-receiver|LP2PReceiver]] interface:
<table class="data">
<thead>
<tr>
<th><a>event handler</a></th>
<th><a>event handler event type</a></th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn attribute for="LP2PReceiver"><code>onconnection</code></dfn></td>
<td>{{LP2PReceiver/connection}}</td>
</tr>
</tbody>
</table>
Examples {#lp2p-receiver-examples}
---------------------------------
Example: Setting up a receiver to listen for connections:
<pre class='example' highlight='js'>
const receiver = new LP2PReceiver({
nickname: "example-receiver",
});
receiver.onconnection = e => {
console.log("Connection established!");
const conn = e.connection;
};
// Blocks until permission is received.
await receiver.start();
</pre>
</section>
<section algorithm="LP2PRequest">
The LP2PRequest Interface {#lp2p-request}
================================================
The <dfn interface>LP2PRequest</dfn> interface represents a request for a connection to another local peer.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PRequest {
constructor(optional LP2PRequestOptions options = {});
Promise<LP2PConnection> start();
};
</pre>
LP2PRequestOptions {#lp2p-request-options}
---------------------------------
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
dictionary LP2PRequestOptions {
DOMString nickname;
};
</pre>
Examples {#lp2p-request-examples}
---------------------------------
Example: Setting up a request for a connection:
<pre class='example' highlight='js'>
const request = new LP2PRequest({
nickname: "example-request",
});
// Blocks until connection is received.
const conn = await request.start();
console.log("Connection established!");
</pre>
</section>
<section algorithm="LP2PConnection">
The LP2PConnection Interface {#lp2p-connection}
===============================================
The <dfn interface>LP2PConnection</dfn> interface represents a connection with another local peer.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PConnection : EventTarget {
};
</pre>
LP2PQuicTransport Interface Extensions {#lp2p-connection-quic-transport-extensions}
-------------------------------------------------------------------
This {{LP2PQuicTransport}} extension allows opening a QuicTransport using an existing connection. In this case, the already established permission and grants should be used.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
partial interface LP2PQuicTransport {
constructor(LP2PConnection connection,
optional LP2PQuicTransportInit quicTransportDict = {});
};
</pre>
Examples {#lp2p-connection-examples}
----------------------------------------
Example: Open a {{LP2PQuicTransport}} using an existing connection as receiver:
<pre class='example' highlight='js'>
const receiver = new LP2PReceiver({
nickname: "example-receiver",
});
receiver.onconnection = async e => {
const conn = e.connection;
const transport = new LP2PQuicTransport(conn);
// Blocks until transport is ready.
await transport.ready;
};
// Blocks until permission is received.
await receiver.start();
</pre>
Example: Open a {{LP2PQuicTransport}} using an existing connection as requester:
<pre class='example' highlight='js'>
const request = new LP2PRequest({
nickname: "example-request",
});
// Blocks until connection is received.
const conn = await request.start();
const transport = new LP2PQuicTransport(conn);
// Blocks until transport is ready.
await transport.ready;
</pre>
</section>
<section algorithm="LP2PDataChannel">
The LP2PDataChannel Interface {#lp2p-data-channel}
==========================================
The LP2PDataChannel interface represents a bi-directional data channel between two peers. An LP2PDataChannel is created via a [factory method](#lp2p-connection-data-channel-extensions) on a LP2PConnection object.
Note: The LP2PDataChannel interface is purposefully kept as close as possible to the [RTCDataChannel](https://www.w3.org/TR/webrtc/#rtcdatachannel) interface defined in [[!webrtc]]. The aim is to allow seamless transition of developers that are familiar with WebRTC as well as allowing libraries to easily work with both the [[!webrtc]] and LP2P API.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PDataChannel : EventTarget {
constructor(USVString label,
optional LP2PDataChannelInit dataChannelDict = {});
readonly attribute USVString label;
readonly attribute USVString protocol;
readonly attribute unsigned short? id;
attribute EventHandler onopen;
attribute EventHandler onerror;
attribute EventHandler onclosing;
attribute EventHandler onclose;
undefined close();
attribute EventHandler onmessage;
attribute BinaryType binaryType;
undefined send((USVString or Blob or ArrayBuffer or ArrayBufferView) data);
};
</pre>
LP2PDataChannelInit {#lp2p-data-channel-init}
----------------------------------------------
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
dictionary LP2PDataChannelInit {
USVString protocol = "";
[EnforceRange] unsigned short id;
};
</pre>
Events {#lp2p-data-channel-events}
---------------------------------
The following event is [=fire an event|fired=] at the {{LP2PDataChannel}} object:
<table class="data">
<thead>
<tr>
<th>Event name</th>
<th>Interface</th>
<th>Fired when…</th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn event for="LP2PDataChannel"><code>open</code></dfn></td>
<td>{{Event}}</td>
<td>The data channel is opened.</td>
</tr>
<tr>
<td><dfn event for="LP2PDataChannel"><code>message</code></dfn></td>
<td>{{MessageEvent}}[[html]]</td>
<td>An incoming message is received.</td>
</tr>
<tr>
<td><dfn event for="LP2PDataChannel"><code>error</code></dfn></td>
<td>{{Event}}</td>
<td>An error occurred.</td>
</tr>
<tr>
<td><dfn event for="LP2PDataChannel"><code>closing</code></dfn></td>
<td>{{Event}}</td>
<td>The data channel is closing.</td>
</tr>
<tr>
<td><dfn event for="LP2PDataChannel"><code>close</code></dfn></td>
<td>{{Event}}</td>
<td>The data channel is closed.</td>
</tr>
</tbody>
</table>
Event handlers {#lp2p-data-channel-event-handlers}
---------------------------------------------------------------
The following are the <a>event handlers</a> (and their corresponding <a>event handler event types</a>) that must be supported, as <a>event handler IDL attributes</a>, by all objects implementing the [[#lp2p-data-channel|LP2PDataChannel]] interface:
<table class="data">
<thead>
<tr>
<th><a>event handler</a></th>
<th><a>event handler event type</a></th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn attribute for="LP2PDataChannel"><code>onopen</code></dfn></td>
<td>{{LP2PDataChannel/open}}</td>
</tr>
<tr>
<td><dfn attribute for="LP2PDataChannel"><code>onmessage</code></dfn></td>
<td>{{LP2PDataChannel/message}}</td>
</tr>
<tr>
<td><dfn attribute for="LP2PDataChannel"><code>onerror</code></dfn></td>
<td>{{LP2PDataChannel/error}}</td>
</tr>
<tr>
<td><dfn attribute for="LP2PDataChannel"><code>onclosing</code></dfn></td>
<td>{{LP2PDataChannel/closing}}</td>
</tr>
<tr>
<td><dfn attribute for="LP2PDataChannel"><code>onclose</code></dfn></td>
<td>{{LP2PDataChannel/close}}</td>
</tr>
</table>
LP2PConnection Interface Extensions {#lp2p-connection-data-channel-extensions}
-------------------------------------------------------------------
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
partial interface LP2PConnection {
LP2PDataChannel createDataChannel(USVString label,
optional LP2PDataChannelInit dataChannelDict = {});
attribute EventHandler ondatachannel;
};
</pre>
LP2PDataChannelEvent {#lp2p-data-channel-event}
------------------------------------------------
Issue: In general, when defining a new interface that inherits from Event please always ask feedback from the WHATWG or the W3C WebApps WG community. See [defining event interfaces](https://dom.spec.whatwg.org/#defining-event-interfaces).
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PDataChannelEvent : Event {
constructor(DOMString type, LP2PDataChannelEventInit DataChannelEventInitDict);
readonly attribute LP2PDataChannel channel;
};
dictionary LP2PDataChannelEventInit : EventInit {
required LP2PDataChannel channel;
};
</pre>
Extensions Events {#lp2p-connection-data-channel-extensions-events}
------------------------------
The following event is [=fire an event|fired=] at the {{LP2PConnection}} object:
<table class="data">
<thead>
<tr>
<th>Event name</th>
<th>Interface</th>
<th>Fired when…</th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn event for="LP2PConnection"><code>datachannel</code></dfn></td>
<td>{{LP2PDataChannelEvent}}</td>
<td>An incoming data channel is received.</td>
</tr>
</tbody>
</table>
Extensions Event handlers {#lp2p-connection-data-channel-extensions-event-handlers}
------------------------------------------------------------------------
The following are the <a>event handlers</a> (and their corresponding <a>event handler event types</a>) that must be supported, as <a>event handler IDL attributes</a>, by all objects implementing the {{LP2PConnection}} interface:
<table class="data">
<thead>
<tr>
<th><a>event handler</a></th>
<th><a>event handler event type</a></th>
</tr>
</thead>
<tbody>
<tr>
<td><dfn attribute for="LP2PConnection"><code>ondatachannel</code></dfn></td>
<td>{{LP2PConnection/datachannel}}</td>
</tr>
</tbody>
</table>
Examples {#data-channel-communication-examples}
---------------------------------------------------
Example: Receive a {{LP2PDataChannel}} on an existing connection as receiver:
<pre class='example' highlight='js'>
const receiver = new LP2PReceiver({
nickname: "example-receiver",
});
receiver.onconnection = e => {
const conn = e.connection;
console.log("Receiver: Got a connection!");
conn.ondatachannel = e => {
const channel = e.channel;
channel.onmessage = e => {
const message = e.data;
console.log(\`Receiver: Received message: ${message}\`);
};
channel.send("Good day to you, requester!");
};
};
await receiver.start();
</pre>
Example: Create a {{LP2PDataChannel}} on an existing connection as requester:
<pre class='example' highlight='js'>
const request = new LP2PRequest({
nickname: "example-request",
});
const conn = await request.start();
console.log("Requester: Got a connection!");
const channel = conn.createDataChannel("My Channel");
channel.onopen = e => {
channel.onmessage = e => {
const message = e.data;
console.log(\`Requester: Received message: ${message}\`);
};
channel.send("Good day to you, receiver!");
};
</pre>
</section>
<section algorithm="LP2PQuicTransport">
The LP2PQuicTransport Interface {#lp2p-quic-transport}
======================================================
The <dfn interface>LP2PQuicTransport</dfn> Interface allows opening a [[!webtransport]] between peers. If the LP2PRequest or LP2PReceiver is not yet started, it must be started when the LP2PQuicTransport is constructed.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
interface LP2PQuicTransport : WebTransport {
constructor((LP2PRequest or LP2PReceiver) source,
optional LP2PQuicTransportInit quicTransportDict = {});
};
[Exposed=(Window,Worker), SecureContext]
dictionary LP2PQuicTransportInit {
};
</pre>
Issue: Define LP2PQuicTransportInit as needed using WebTransportOptions as reference.
LP2PQuicTransportListener Interface {#lp2p-quic-transport-listener}
-------------------------------------------------------------------
The <dfn interface>LP2PQuicTransportListener</dfn> Interface allows listening for incoming [[!webtransport]] transports. If the LP2PRequest or LP2PReceiver is not yet started, it must be started when the LP2PQuicTransport is constructed.
<pre class="idl">
[Exposed=(Window,Worker), SecureContext]
partial interface LP2PQuicTransportListener {
constructor((LP2PRequest or LP2PReceiver) source,
optional LP2PQuicTransportListenerInit quicTransportListenerDict = {});
readonly attribute Promise<undefined> ready;
/* a ReadableStream of LP2PQuicTransport objects */
readonly attribute ReadableStream incomingTransports;
};
[Exposed=(Window,Worker), SecureContext]
dictionary LP2PQuicTransportListenerInit {
};
</pre>
Issue: Define LP2PQuicTransportListenerInit as needed using WebTransportOptions as reference.
Examples {#lp2p-quic-transport-examples}
----------------------------------------
Example: Setting up a request for a LP2PQuicTransport:
<pre class='example' highlight='js'>
const request = new LP2PRequest({
nickname: "example-request",
});
const transport = new LP2PQuicTransport(request);
// Blocks until transport is ready.
await transport.ready;
</pre>
Example: Receiving a LP2PQuicTransport:
<pre class='example' highlight='js'>
const receiver = new LP2PReceiver({
nickname: "example-receiver",
});
const listener = new LP2PQuicTransportListener(receiver);
for await (const transport of listener.incomingTransports) {
// Blocks until transport is ready.
await transport.ready;
}
</pre>
Refer to the [WebTransport examples](https://www.w3.org/TR/webtransport/#examples) for usage of a [[!webtransport]] object.
</section>
Security and privacy considerations {#security-and-privacy-considerations}
=========================================================================
Open Screen Protocol {#security-osp}
------------------------------------
The Local Peer-to-Peer API is meant to be implementable on the [[!openscreenprotocol|Open Screen Protocol]]. The Security and Privacy considerations of the Open Screen Protocol must therefore be considered when implementing this API.
Personally identifiable information {#security-pii}
---------------------------------------------------
The peer attributes, such as the nickname and device model, are provided to give minimal context to a connected peer. This information could be used in conjunction with other information for fingerprinting the user. However, this information is only available to an origin after it has been authenticated and a user has given explicit consent to make the connection to the remote peer.
No information is exposed to the origin during service discovery. No IP information is exposed to an origin. This is fully managed by the user agent.
Issue(WICG/local-peer-to-peer#15): Refine peer attributes, related:
User interface guidelines {#security-ui}
----------------------------------------
When the user is asked to grant permission to connect to a peer, the user agent should make it clear what origin the request is coming from.
Issue(WICG/local-peer-to-peer#15): Define filtering to provide additional context, related:
Impact on same-origin policy {#security-same-origin}
----------------------------------------
This document extends the Web platform with the ability to set up real-time, direct communication between browsers and other devices, including other browsers, within a [=local communication medium=].
This means that data and media can be shared between applications running in different browsers, or between an application running in the browser and another user agent that is not a browser such as a headless service provided by a smart TV or smart fridge. This extends the usual barriers in the Web's security model that prevents sending data between entities with different origins.
Device Access {#security-device-access}
---------------------------------------
The Local Peer-to-Peer API requires user permission for a page to access any peers. The API uses purpose-fit protocols for data communication. It cannot be used to connect to raw sockets or unknowing HTTP servers. In addition, a user must [=acquire a local peer grant=] by explicitly providing consenting for an origin to connect to a peer. In addition, a user must [=authenticate a local peer=] before use.
Persistent State {#security-persistent-state}
---------------------------------------------
The persisted state considerations of the [[!openscreenprotocol|Open Screen Protocol]] must be followed when implementing this API.
Secure Contexts {#security-secure-context}
------------------------------------------
The Local Peer-to-Peer API must only be provided in a secure context.
Appendix A: OSP Extension Messages {#appendix-a}
================================================
The following messages are defined according to and as an extension to the [[!openscreenprotocol|Open Screen Protocol]] [Messages](https://www.w3.org/TR/openscreenprotocol/#appendix-a).
Note: The type keys and capability IDs for these extensions are not officially registered yet. They will be registered as this specification matures.
<pre class="data" highlight='cddl'>
<dfn>agent-capability</dfn> = &(
<dfn>data-channels</dfn>: 11OO
<dfn>quick-transport</dfn>: 12OO
)
<dfn>data-channel-encoding-id</dfn> = &(
<dfn>encoding-id-blob</dfn>: 0
<dfn>encoding-id-string</dfn>: 1
<dfn>encoding-id-array-buffer</dfn>: 2
)
; type key 24
<dfn>data-frame</dfn> = {
0: data-channel-encoding-id ; encoding-id
4: bytes ; payload
}
; type key 1101
<dfn>data-channel-open-request</dfn> = {
request
1: uint ; channel-id
2: text ; label
3: text ; protocol
}
; type key 1102
<dfn>data-channel-open-response</dfn> = {
response
1: &result ; result
}
</pre>