@tribe-nest/media-protocol 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/_fixtures/joinTokenVectors.json +103 -0
- package/build/claims.d.ts +327 -0
- package/build/claims.d.ts.map +1 -0
- package/build/claims.js +91 -0
- package/build/claims.js.map +1 -0
- package/build/codecs.d.ts +102 -0
- package/build/codecs.d.ts.map +1 -0
- package/build/codecs.js +138 -0
- package/build/codecs.js.map +1 -0
- package/build/errorSchema.d.ts +8 -0
- package/build/errorSchema.d.ts.map +1 -0
- package/build/errorSchema.js +12 -0
- package/build/errorSchema.js.map +1 -0
- package/build/errors.d.ts +18 -0
- package/build/errors.d.ts.map +1 -0
- package/build/errors.js +47 -0
- package/build/errors.js.map +1 -0
- package/build/frames.d.ts +1291 -0
- package/build/frames.d.ts.map +1 -0
- package/build/frames.js +222 -0
- package/build/frames.js.map +1 -0
- package/build/grants.d.ts +307 -0
- package/build/grants.d.ts.map +1 -0
- package/build/grants.js +228 -0
- package/build/grants.js.map +1 -0
- package/build/index.d.ts +24 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +40 -0
- package/build/index.js.map +1 -0
- package/build/mp-build/_fixtures/joinTokenVectors.json +103 -0
- package/build/mp-build/claims.d.ts +299 -0
- package/build/mp-build/claims.d.ts.map +1 -0
- package/build/mp-build/claims.js +60 -0
- package/build/mp-build/claims.js.map +1 -0
- package/build/mp-build/errorSchema.d.ts +8 -0
- package/build/mp-build/errorSchema.d.ts.map +1 -0
- package/build/mp-build/errorSchema.js +12 -0
- package/build/mp-build/errorSchema.js.map +1 -0
- package/build/mp-build/errors.d.ts +18 -0
- package/build/mp-build/errors.d.ts.map +1 -0
- package/build/mp-build/errors.js +47 -0
- package/build/mp-build/errors.js.map +1 -0
- package/build/mp-build/frames.d.ts +786 -0
- package/build/mp-build/frames.d.ts.map +1 -0
- package/build/mp-build/frames.js +153 -0
- package/build/mp-build/frames.js.map +1 -0
- package/build/mp-build/grants.d.ts +245 -0
- package/build/mp-build/grants.d.ts.map +1 -0
- package/build/mp-build/grants.js +135 -0
- package/build/mp-build/grants.js.map +1 -0
- package/build/mp-build/index.d.ts +23 -0
- package/build/mp-build/index.d.ts.map +1 -0
- package/build/mp-build/index.js +39 -0
- package/build/mp-build/index.js.map +1 -0
- package/build/mp-build/token.d.ts +66 -0
- package/build/mp-build/token.d.ts.map +1 -0
- package/build/mp-build/token.js +208 -0
- package/build/mp-build/token.js.map +1 -0
- package/build/mp-build/version.d.ts +9 -0
- package/build/mp-build/version.d.ts.map +1 -0
- package/build/mp-build/version.js +12 -0
- package/build/mp-build/version.js.map +1 -0
- package/build/token.d.ts +66 -0
- package/build/token.d.ts.map +1 -0
- package/build/token.js +208 -0
- package/build/token.js.map +1 -0
- package/build/version.d.ts +9 -0
- package/build/version.d.ts.map +1 -0
- package/build/version.js +12 -0
- package/build/version.js.map +1 -0
- package/package.json +53 -0
- package/src/_fixtures/joinTokenVectors.json +103 -0
- package/src/_tests/codecs.spec.ts +66 -0
- package/src/_tests/publishGrants.spec.ts +109 -0
- package/src/_tests/token.spec.ts +272 -0
- package/src/claims.ts +116 -0
- package/src/codecs.ts +165 -0
- package/src/errorSchema.ts +9 -0
- package/src/errors.ts +44 -0
- package/src/frames.ts +234 -0
- package/src/grants.ts +248 -0
- package/src/index.ts +23 -0
- package/src/token.ts +237 -0
- package/src/version.ts +8 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
{
|
|
2
|
+
"_comment": "GENERATED by scripts/generateVectors.ts - do not hand-edit. One fixture read by BOTH the backend minter spec and the media-server verifier spec, so the two cannot drift. The keys are test keys and are committed on purpose.",
|
|
3
|
+
"nowSeconds": 1760000000,
|
|
4
|
+
"issuer": "legal-de",
|
|
5
|
+
"kid": "test-v1",
|
|
6
|
+
"keys": {
|
|
7
|
+
"test-v1": "-----BEGIN PUBLIC KEY-----\nMCowBQYDK2VwAyEADDA6KSONGhJqPWozH6py1Gu6M53ZpupI9cLMN/RZtws=\n-----END PUBLIC KEY-----\n"
|
|
8
|
+
},
|
|
9
|
+
"privateKeyForMinterTests": "-----BEGIN PRIVATE KEY-----\nMC4CAQAwBQYDK2VwBCIEIO8H96J+s7hghw0TR4cDCVjjaBwMciXpPte0hx7WSFf3\n-----END PRIVATE KEY-----\n",
|
|
10
|
+
"vectors": [
|
|
11
|
+
{
|
|
12
|
+
"name": "valid_human",
|
|
13
|
+
"why": "the ordinary case: a human joining over webrtc",
|
|
14
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.cHwZ_nFkDQoHVtB6-mA2Rg-KcuVTralgw1cS908OQh7_8JUOKAP9l6kFiKpmfHFMEz6aBt7yXeIRKnBvTfJlBw",
|
|
15
|
+
"expect": "ok"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"name": "valid_agent_exempt",
|
|
19
|
+
"why": "a non-human may be exempt from the active-set ceiling; a human may not",
|
|
20
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoidHJhbnNjcmliZXIiLCJraW5kIjoiYWdlbnQiLCJ0cmFuc3BvcnQiOiJwbGFpbiIsImdyYW50cyI6eyJjYW5QdWJsaXNoIjpmYWxzZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6ZmFsc2UsInN1YnNjcmliZUV4ZW1wdCI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.Mc3KKrczwe0j6YYpe-HXBiYn5C8CeOhYaE2HI64tANDzhucO0BxAgTg9fTdJAGKW8W9RymwV6j83HRWZr854AQ",
|
|
21
|
+
"expect": "ok"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
"name": "valid_barrier",
|
|
25
|
+
"why": "an information barrier: alice may receive only carol, and only carol may receive alice",
|
|
26
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlIjp7Im1vZGUiOiJhbGxvdyIsImlkZW50aXRpZXMiOlsiY2Fyb2wiXX0sInZpc2libGVUbyI6eyJtb2RlIjoiYWxsb3ciLCJpZGVudGl0aWVzIjpbImNhcm9sIl19fSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.1jx23AACBL-tvtUFSUGQAjjBCuEs6pv7MHSeqAfy7HY-ki65Rf-YadxsPk5Nzg-OrOopu08J6m_Wdm5YA3TMDw",
|
|
27
|
+
"expect": "ok"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "unknown_grant_key",
|
|
31
|
+
"why": "THE fail-open case. One phase minted `subscribeOnly` while another read `subscribe`; a lenient schema would have read 'no rule' as 'everyone' and put two Mandanten in one room.",
|
|
32
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlT25seSI6WyJjYXJvbCJdfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.uda5k_gP-zizkivazZkx1QoSj-54DgnTzCMoTBZ-Pzfyn1jZdw49IvPbAD-88yOfn7ukVYCOko0DRHkxmfu8Aw",
|
|
33
|
+
"expect": "bad_claims"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"name": "human_with_subscribe_exempt",
|
|
37
|
+
"why": "exemption bypasses the active-set ceiling; a human holding it can pull every track in a 1,000-person room",
|
|
38
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZSwic3Vic2NyaWJlRXhlbXB0Ijp0cnVlfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.o34OTK5D0qRD5enDABkljr_aFerqzoZYLR_uqgTKwO1DsszjDkIG8gUxvjucYZ9apvwWIq3tuwAPVRSAotqYCA",
|
|
39
|
+
"expect": "bad_claims"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"name": "expired",
|
|
43
|
+
"why": "a join ticket outlives its window",
|
|
44
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc1OTk5OTQwMCwiZXhwIjoxNzU5OTk5NzAwfQ.hTM23tP-4IP044XhjXNSmzpXMWzi1GC7LrV5vLN_H1SnnI0ZFgLmg8VTW34cPbZy6yIs8mXRZT8uNJ6xsCAQDQ",
|
|
45
|
+
"expect": "expired"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"name": "not_yet_valid",
|
|
49
|
+
"why": "nbf in the future",
|
|
50
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwibmJmIjoxNzYwMDAwNjAwLCJleHAiOjE3NjAwMDA5MDB9.xpFjHBt5XYyG6pP9_3j5C-h0FS5Y7byfo_M8qkkGn33iK9i4qO3L_SzFxYebTEoX-jmlTu8Y8MCPlhLzb3MFCw",
|
|
51
|
+
"expect": "not_yet_valid"
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
"name": "ttl_too_long",
|
|
55
|
+
"why": "enforced at VERIFY as well as mint, because a compromised minter would simply skip the mint check",
|
|
56
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDg2NDAwfQ.UCA0foITm9CL3z1ZslwGf4Dvmqe0xkOpYhN9l13-DKRPjje6pGez4jcvhKDGwPuy8f7lovvUfoRwCWG4UGYWCg",
|
|
57
|
+
"expect": "ttl_too_long"
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
"name": "wrong_issuer",
|
|
61
|
+
"why": "a token minted for the main instance must be worthless on the legal one",
|
|
62
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJtYWluIiwiYXVkIjoibWVkaWEiLCJyb29tIjoicm9vbS0xIiwiaWRlbnRpdHkiOiJhbGljZSIsImtpbmQiOiJodW1hbiIsInRyYW5zcG9ydCI6IndlYnJ0YyIsImdyYW50cyI6eyJjYW5QdWJsaXNoIjp0cnVlLCJjYW5TdWJzY3JpYmUiOnRydWUsImNhblB1Ymxpc2hEYXRhIjp0cnVlfSwianRpIjoianRpLTAwMDAwMDAxIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.Z33LRIVYrY7KlvUUsQCZ52x7HBxPKWBuJSKySb6d0Ncmenu8CpFSxC2JRm_s7NPbuMwBymgQjKUiFmTeUm_FCA",
|
|
63
|
+
"expect": "wrong_issuer"
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"name": "wrong_audience_control_as_join",
|
|
67
|
+
"why": "a control token replayed as a join",
|
|
68
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6ImNvbnRyb2wiLCJqdGkiOiJqdGktY29udHJvbC0xIiwiaWF0IjoxNzYwMDAwMDAwLCJleHAiOjE3NjAwMDAzMDB9.q9LAV0vxFy95CqICQ9jl5dm7ll_iD8HSDADK0cQu85wJxVx1roQL-RZggjcrxhShH2uzfKufTW9211pF56caDA",
|
|
69
|
+
"expect": "wrong_audience"
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
"name": "unknown_kid",
|
|
73
|
+
"why": "signed by a key this node does not carry",
|
|
74
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InJvdGF0ZWQtYXdheSJ9.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.W_BZBx_p9W245Xw89H3Dy_MEYf5JfNb8KpSeLok4ZjYUc_EWx8wxvghDrWjaidXp6yxOK3Su_r_b_QHOis7tCA",
|
|
75
|
+
"expect": "unknown_kid"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"name": "bad_signature",
|
|
79
|
+
"why": "correct kid, wrong key - a forgery attempt rather than a rotation",
|
|
80
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.Chdv_Jl7v6HTE5u1TpP6f7j2mqFPocPKfBSdwgbL_lNIN708mHHA5oGeR8AOjPakn16WLTW6jODEUnbj_KTLAA",
|
|
81
|
+
"expect": "bad_signature"
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
"name": "alg_none",
|
|
85
|
+
"why": "classic JWT algorithm confusion. Only EdDSA is ever accepted.",
|
|
86
|
+
"token": "eyJhbGciOiJub25lIiwidHlwIjoiSldUIiwia2lkIjoidGVzdC12MSJ9.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMSIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.",
|
|
87
|
+
"expect": "malformed"
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
"name": "wrong_room",
|
|
91
|
+
"why": "a valid token for a different room",
|
|
92
|
+
"token": "eyJhbGciOiJFZERTQSIsInR5cCI6IkpXVCIsImtpZCI6InRlc3QtdjEifQ.eyJ2IjoxLCJpc3MiOiJsZWdhbC1kZSIsImF1ZCI6Im1lZGlhIiwicm9vbSI6InJvb20tMiIsImlkZW50aXR5IjoiYWxpY2UiLCJraW5kIjoiaHVtYW4iLCJ0cmFuc3BvcnQiOiJ3ZWJydGMiLCJncmFudHMiOnsiY2FuUHVibGlzaCI6dHJ1ZSwiY2FuU3Vic2NyaWJlIjp0cnVlLCJjYW5QdWJsaXNoRGF0YSI6dHJ1ZX0sImp0aSI6Imp0aS0wMDAwMDAwMSIsImlhdCI6MTc2MDAwMDAwMCwiZXhwIjoxNzYwMDAwMzAwfQ.EWEv-Np5ECbj4TZXt3KTgcPUHEoDM2G4Wx-M0L25pTkE0onIRMm5vmbVBypULUtIWtKxOxsdDNBezcl8Nqy8Bg",
|
|
93
|
+
"expect": "wrong_room",
|
|
94
|
+
"room": "room-1"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"name": "malformed",
|
|
98
|
+
"why": "not three segments",
|
|
99
|
+
"token": "not.a.token.at.all",
|
|
100
|
+
"expect": "malformed"
|
|
101
|
+
}
|
|
102
|
+
]
|
|
103
|
+
}
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* The join token's claims: the whole authorization decision, made once by the
|
|
4
|
+
* backend and carried to a media plane that never asks it anything.
|
|
5
|
+
*
|
|
6
|
+
* Names here were contested by the parallel phase plans; each disagreement is
|
|
7
|
+
* resolved once, in this file, and everything else imports it.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* The longest display name a join token may carry.
|
|
11
|
+
*
|
|
12
|
+
* Exported because it is a MINT-TIME refusal, not a preference: `signJoinToken`
|
|
13
|
+
* hard-parses these claims, so a caller that builds a name out of stored text
|
|
14
|
+
* and does not clamp it throws instead of minting. Every such caller has to
|
|
15
|
+
* know the bound, and a caller that hard-codes 200 is a caller that will not
|
|
16
|
+
* follow this number if it ever moves.
|
|
17
|
+
*/
|
|
18
|
+
export declare const MEDIA_PARTICIPANT_NAME_MAX_LENGTH = 200;
|
|
19
|
+
/**
|
|
20
|
+
* A display name cut to what a token may carry.
|
|
21
|
+
*
|
|
22
|
+
* Lives HERE, beside the bound it enforces, rather than in each surface that
|
|
23
|
+
* mints. Two reasons, and the second is the one that matters.
|
|
24
|
+
*
|
|
25
|
+
* A minting surface builds the name out of stored text (a buyer's name off a
|
|
26
|
+
* booking, a seat's display name off a roster) and cannot promise a length, so
|
|
27
|
+
* every one of them needs this. And a surface that instead compared against the
|
|
28
|
+
* exported NUMBER would go silently unclamped the moment it read a stale build
|
|
29
|
+
* of this package: `value.length > undefined` is `false`, so the clamp
|
|
30
|
+
* evaporates and the failure only shows up as a 500 from `signJoinToken` in
|
|
31
|
+
* production. A missing FUNCTION throws on the first call instead.
|
|
32
|
+
*
|
|
33
|
+
* Truncation rather than refusal is deliberate. A name is a label on a tile,
|
|
34
|
+
* and no call should fail to open over one.
|
|
35
|
+
*/
|
|
36
|
+
export declare function clampParticipantName(value: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* `iss` IS the instance id (`legal-de`, `main`), not a service name.
|
|
39
|
+
*
|
|
40
|
+
* One plan proposed `iss: "tribenest-backend"` with the instance in a separate
|
|
41
|
+
* `inst` claim. That displaces the one value a verifier actually checks, and a
|
|
42
|
+
* legal-de token would then verify happily on the main instance - which is the
|
|
43
|
+
* whole reason instances are separate.
|
|
44
|
+
*/
|
|
45
|
+
export declare const mediaJoinClaimsSchema: z.ZodObject<{
|
|
46
|
+
v: z.ZodLiteral<1>;
|
|
47
|
+
iss: z.ZodString;
|
|
48
|
+
aud: z.ZodLiteral<"media">;
|
|
49
|
+
room: z.ZodString;
|
|
50
|
+
/** `identity`, not `sub`: it is a first-class concept the barrier rules name. */
|
|
51
|
+
identity: z.ZodString;
|
|
52
|
+
name: z.ZodOptional<z.ZodString>;
|
|
53
|
+
/** Top level, NOT inside grants - it decides what may be minted at all. */
|
|
54
|
+
kind: z.ZodEnum<["human", "agent", "egress", "sip", "ingress"]>;
|
|
55
|
+
/** Top level. Transport authority is not media authority. */
|
|
56
|
+
transport: z.ZodEnum<["webrtc", "plain", "pipe"]>;
|
|
57
|
+
grants: z.ZodObject<{
|
|
58
|
+
canPublish: z.ZodBoolean;
|
|
59
|
+
canSubscribe: z.ZodBoolean;
|
|
60
|
+
canPublishData: z.ZodBoolean;
|
|
61
|
+
subscribe: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
|
|
62
|
+
mode: z.ZodLiteral<"all">;
|
|
63
|
+
}, "strict", z.ZodTypeAny, {
|
|
64
|
+
mode: "all";
|
|
65
|
+
}, {
|
|
66
|
+
mode: "all";
|
|
67
|
+
}>, z.ZodObject<{
|
|
68
|
+
mode: z.ZodLiteral<"none">;
|
|
69
|
+
}, "strict", z.ZodTypeAny, {
|
|
70
|
+
mode: "none";
|
|
71
|
+
}, {
|
|
72
|
+
mode: "none";
|
|
73
|
+
}>, z.ZodObject<{
|
|
74
|
+
mode: z.ZodLiteral<"allow">;
|
|
75
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
76
|
+
}, "strict", z.ZodTypeAny, {
|
|
77
|
+
mode: "allow";
|
|
78
|
+
identities: string[];
|
|
79
|
+
}, {
|
|
80
|
+
mode: "allow";
|
|
81
|
+
identities: string[];
|
|
82
|
+
}>, z.ZodObject<{
|
|
83
|
+
mode: z.ZodLiteral<"deny">;
|
|
84
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
85
|
+
}, "strict", z.ZodTypeAny, {
|
|
86
|
+
mode: "deny";
|
|
87
|
+
identities: string[];
|
|
88
|
+
}, {
|
|
89
|
+
mode: "deny";
|
|
90
|
+
identities: string[];
|
|
91
|
+
}>]>>;
|
|
92
|
+
visibleTo: z.ZodOptional<z.ZodDiscriminatedUnion<"mode", [z.ZodObject<{
|
|
93
|
+
mode: z.ZodLiteral<"all">;
|
|
94
|
+
}, "strict", z.ZodTypeAny, {
|
|
95
|
+
mode: "all";
|
|
96
|
+
}, {
|
|
97
|
+
mode: "all";
|
|
98
|
+
}>, z.ZodObject<{
|
|
99
|
+
mode: z.ZodLiteral<"none">;
|
|
100
|
+
}, "strict", z.ZodTypeAny, {
|
|
101
|
+
mode: "none";
|
|
102
|
+
}, {
|
|
103
|
+
mode: "none";
|
|
104
|
+
}>, z.ZodObject<{
|
|
105
|
+
mode: z.ZodLiteral<"allow">;
|
|
106
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
107
|
+
}, "strict", z.ZodTypeAny, {
|
|
108
|
+
mode: "allow";
|
|
109
|
+
identities: string[];
|
|
110
|
+
}, {
|
|
111
|
+
mode: "allow";
|
|
112
|
+
identities: string[];
|
|
113
|
+
}>, z.ZodObject<{
|
|
114
|
+
mode: z.ZodLiteral<"deny">;
|
|
115
|
+
identities: z.ZodArray<z.ZodString, "many">;
|
|
116
|
+
}, "strict", z.ZodTypeAny, {
|
|
117
|
+
mode: "deny";
|
|
118
|
+
identities: string[];
|
|
119
|
+
}, {
|
|
120
|
+
mode: "deny";
|
|
121
|
+
identities: string[];
|
|
122
|
+
}>]>>;
|
|
123
|
+
publishKinds: z.ZodOptional<z.ZodArray<z.ZodEnum<["audio", "video", "screen"]>, "many">>;
|
|
124
|
+
subscribeExempt: z.ZodOptional<z.ZodBoolean>;
|
|
125
|
+
maxSubscriptions: z.ZodOptional<z.ZodNumber>;
|
|
126
|
+
}, "strict", z.ZodTypeAny, {
|
|
127
|
+
canPublish: boolean;
|
|
128
|
+
canSubscribe: boolean;
|
|
129
|
+
canPublishData: boolean;
|
|
130
|
+
subscribe?: {
|
|
131
|
+
mode: "all";
|
|
132
|
+
} | {
|
|
133
|
+
mode: "none";
|
|
134
|
+
} | {
|
|
135
|
+
mode: "allow";
|
|
136
|
+
identities: string[];
|
|
137
|
+
} | {
|
|
138
|
+
mode: "deny";
|
|
139
|
+
identities: string[];
|
|
140
|
+
} | undefined;
|
|
141
|
+
visibleTo?: {
|
|
142
|
+
mode: "all";
|
|
143
|
+
} | {
|
|
144
|
+
mode: "none";
|
|
145
|
+
} | {
|
|
146
|
+
mode: "allow";
|
|
147
|
+
identities: string[];
|
|
148
|
+
} | {
|
|
149
|
+
mode: "deny";
|
|
150
|
+
identities: string[];
|
|
151
|
+
} | undefined;
|
|
152
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
153
|
+
subscribeExempt?: boolean | undefined;
|
|
154
|
+
maxSubscriptions?: number | undefined;
|
|
155
|
+
}, {
|
|
156
|
+
canPublish: boolean;
|
|
157
|
+
canSubscribe: boolean;
|
|
158
|
+
canPublishData: boolean;
|
|
159
|
+
subscribe?: {
|
|
160
|
+
mode: "all";
|
|
161
|
+
} | {
|
|
162
|
+
mode: "none";
|
|
163
|
+
} | {
|
|
164
|
+
mode: "allow";
|
|
165
|
+
identities: string[];
|
|
166
|
+
} | {
|
|
167
|
+
mode: "deny";
|
|
168
|
+
identities: string[];
|
|
169
|
+
} | undefined;
|
|
170
|
+
visibleTo?: {
|
|
171
|
+
mode: "all";
|
|
172
|
+
} | {
|
|
173
|
+
mode: "none";
|
|
174
|
+
} | {
|
|
175
|
+
mode: "allow";
|
|
176
|
+
identities: string[];
|
|
177
|
+
} | {
|
|
178
|
+
mode: "deny";
|
|
179
|
+
identities: string[];
|
|
180
|
+
} | undefined;
|
|
181
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
182
|
+
subscribeExempt?: boolean | undefined;
|
|
183
|
+
maxSubscriptions?: number | undefined;
|
|
184
|
+
}>;
|
|
185
|
+
jti: z.ZodString;
|
|
186
|
+
iat: z.ZodNumber;
|
|
187
|
+
nbf: z.ZodOptional<z.ZodNumber>;
|
|
188
|
+
exp: z.ZodNumber;
|
|
189
|
+
}, "strict", z.ZodTypeAny, {
|
|
190
|
+
v: 1;
|
|
191
|
+
iss: string;
|
|
192
|
+
aud: "media";
|
|
193
|
+
room: string;
|
|
194
|
+
identity: string;
|
|
195
|
+
kind: "human" | "agent" | "egress" | "sip" | "ingress";
|
|
196
|
+
transport: "webrtc" | "plain" | "pipe";
|
|
197
|
+
grants: {
|
|
198
|
+
canPublish: boolean;
|
|
199
|
+
canSubscribe: boolean;
|
|
200
|
+
canPublishData: boolean;
|
|
201
|
+
subscribe?: {
|
|
202
|
+
mode: "all";
|
|
203
|
+
} | {
|
|
204
|
+
mode: "none";
|
|
205
|
+
} | {
|
|
206
|
+
mode: "allow";
|
|
207
|
+
identities: string[];
|
|
208
|
+
} | {
|
|
209
|
+
mode: "deny";
|
|
210
|
+
identities: string[];
|
|
211
|
+
} | undefined;
|
|
212
|
+
visibleTo?: {
|
|
213
|
+
mode: "all";
|
|
214
|
+
} | {
|
|
215
|
+
mode: "none";
|
|
216
|
+
} | {
|
|
217
|
+
mode: "allow";
|
|
218
|
+
identities: string[];
|
|
219
|
+
} | {
|
|
220
|
+
mode: "deny";
|
|
221
|
+
identities: string[];
|
|
222
|
+
} | undefined;
|
|
223
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
224
|
+
subscribeExempt?: boolean | undefined;
|
|
225
|
+
maxSubscriptions?: number | undefined;
|
|
226
|
+
};
|
|
227
|
+
jti: string;
|
|
228
|
+
iat: number;
|
|
229
|
+
exp: number;
|
|
230
|
+
name?: string | undefined;
|
|
231
|
+
nbf?: number | undefined;
|
|
232
|
+
}, {
|
|
233
|
+
v: 1;
|
|
234
|
+
iss: string;
|
|
235
|
+
aud: "media";
|
|
236
|
+
room: string;
|
|
237
|
+
identity: string;
|
|
238
|
+
kind: "human" | "agent" | "egress" | "sip" | "ingress";
|
|
239
|
+
transport: "webrtc" | "plain" | "pipe";
|
|
240
|
+
grants: {
|
|
241
|
+
canPublish: boolean;
|
|
242
|
+
canSubscribe: boolean;
|
|
243
|
+
canPublishData: boolean;
|
|
244
|
+
subscribe?: {
|
|
245
|
+
mode: "all";
|
|
246
|
+
} | {
|
|
247
|
+
mode: "none";
|
|
248
|
+
} | {
|
|
249
|
+
mode: "allow";
|
|
250
|
+
identities: string[];
|
|
251
|
+
} | {
|
|
252
|
+
mode: "deny";
|
|
253
|
+
identities: string[];
|
|
254
|
+
} | undefined;
|
|
255
|
+
visibleTo?: {
|
|
256
|
+
mode: "all";
|
|
257
|
+
} | {
|
|
258
|
+
mode: "none";
|
|
259
|
+
} | {
|
|
260
|
+
mode: "allow";
|
|
261
|
+
identities: string[];
|
|
262
|
+
} | {
|
|
263
|
+
mode: "deny";
|
|
264
|
+
identities: string[];
|
|
265
|
+
} | undefined;
|
|
266
|
+
publishKinds?: ("audio" | "video" | "screen")[] | undefined;
|
|
267
|
+
subscribeExempt?: boolean | undefined;
|
|
268
|
+
maxSubscriptions?: number | undefined;
|
|
269
|
+
};
|
|
270
|
+
jti: string;
|
|
271
|
+
iat: number;
|
|
272
|
+
exp: number;
|
|
273
|
+
name?: string | undefined;
|
|
274
|
+
nbf?: number | undefined;
|
|
275
|
+
}>;
|
|
276
|
+
export type MediaJoinClaims = z.infer<typeof mediaJoinClaimsSchema>;
|
|
277
|
+
/**
|
|
278
|
+
* Server-to-server control calls (create room, end room, attach an agent).
|
|
279
|
+
*
|
|
280
|
+
* A separate audience so a join token can never be replayed as a control call.
|
|
281
|
+
* It carries no room, identity, kind, transport or grants: a control caller is
|
|
282
|
+
* not a participant, and giving it participant-shaped claims invites code that
|
|
283
|
+
* treats it as one.
|
|
284
|
+
*/
|
|
285
|
+
export declare const mediaControlClaimsSchema: z.ZodObject<{
|
|
286
|
+
v: z.ZodLiteral<1>;
|
|
287
|
+
iss: z.ZodString;
|
|
288
|
+
aud: z.ZodLiteral<"control">;
|
|
289
|
+
jti: z.ZodString;
|
|
290
|
+
iat: z.ZodNumber;
|
|
291
|
+
nbf: z.ZodOptional<z.ZodNumber>;
|
|
292
|
+
exp: z.ZodNumber;
|
|
293
|
+
}, "strict", z.ZodTypeAny, {
|
|
294
|
+
v: 1;
|
|
295
|
+
iss: string;
|
|
296
|
+
aud: "control";
|
|
297
|
+
jti: string;
|
|
298
|
+
iat: number;
|
|
299
|
+
exp: number;
|
|
300
|
+
nbf?: number | undefined;
|
|
301
|
+
}, {
|
|
302
|
+
v: 1;
|
|
303
|
+
iss: string;
|
|
304
|
+
aud: "control";
|
|
305
|
+
jti: string;
|
|
306
|
+
iat: number;
|
|
307
|
+
exp: number;
|
|
308
|
+
nbf?: number | undefined;
|
|
309
|
+
}>;
|
|
310
|
+
export type MediaControlClaims = z.infer<typeof mediaControlClaimsSchema>;
|
|
311
|
+
/**
|
|
312
|
+
* Why a token was refused.
|
|
313
|
+
*
|
|
314
|
+
* Deliberately granular for the SERVER's logs and deliberately NOT returned to
|
|
315
|
+
* the client, which gets `unauthorized` and nothing else. Telling a caller
|
|
316
|
+
* whether the signature or the room was wrong is an oracle.
|
|
317
|
+
*/
|
|
318
|
+
export type JoinTokenRejection = "malformed" | "unknown_kid" | "bad_signature" | "expired" | "not_yet_valid" | "ttl_too_long" | "wrong_audience" | "wrong_issuer" | "wrong_room" | "bad_claims";
|
|
319
|
+
export type VerifyResult<T> = {
|
|
320
|
+
ok: true;
|
|
321
|
+
claims: T;
|
|
322
|
+
kid: string;
|
|
323
|
+
} | {
|
|
324
|
+
ok: false;
|
|
325
|
+
reason: JoinTokenRejection;
|
|
326
|
+
};
|
|
327
|
+
//# sourceMappingURL=claims.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claims.d.ts","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,iCAAiC,MAAM,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAE1D;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB;;;;;IAM9B,iFAAiF;;;IAGjF,2EAA2E;;IAE3E,6DAA6D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAQtD,CAAC;AAEZ,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAEpE;;;;;;;GAOG;AACH,eAAO,MAAM,wBAAwB;;;;;;;;;;;;;;;;;;;;;;;;EAU1B,CAAC;AAEZ,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE1E;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAC1B,WAAW,GACX,aAAa,GACb,eAAe,GACf,SAAS,GACT,eAAe,GACf,cAAc,GACd,gBAAgB,GAChB,cAAc,GACd,YAAY,GACZ,YAAY,CAAC;AAEjB,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC"}
|
package/build/claims.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.mediaControlClaimsSchema = exports.mediaJoinClaimsSchema = exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH = void 0;
|
|
4
|
+
exports.clampParticipantName = clampParticipantName;
|
|
5
|
+
const zod_1 = require("zod");
|
|
6
|
+
const grants_1 = require("./grants");
|
|
7
|
+
/**
|
|
8
|
+
* The join token's claims: the whole authorization decision, made once by the
|
|
9
|
+
* backend and carried to a media plane that never asks it anything.
|
|
10
|
+
*
|
|
11
|
+
* Names here were contested by the parallel phase plans; each disagreement is
|
|
12
|
+
* resolved once, in this file, and everything else imports it.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* The longest display name a join token may carry.
|
|
16
|
+
*
|
|
17
|
+
* Exported because it is a MINT-TIME refusal, not a preference: `signJoinToken`
|
|
18
|
+
* hard-parses these claims, so a caller that builds a name out of stored text
|
|
19
|
+
* and does not clamp it throws instead of minting. Every such caller has to
|
|
20
|
+
* know the bound, and a caller that hard-codes 200 is a caller that will not
|
|
21
|
+
* follow this number if it ever moves.
|
|
22
|
+
*/
|
|
23
|
+
exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH = 200;
|
|
24
|
+
/**
|
|
25
|
+
* A display name cut to what a token may carry.
|
|
26
|
+
*
|
|
27
|
+
* Lives HERE, beside the bound it enforces, rather than in each surface that
|
|
28
|
+
* mints. Two reasons, and the second is the one that matters.
|
|
29
|
+
*
|
|
30
|
+
* A minting surface builds the name out of stored text (a buyer's name off a
|
|
31
|
+
* booking, a seat's display name off a roster) and cannot promise a length, so
|
|
32
|
+
* every one of them needs this. And a surface that instead compared against the
|
|
33
|
+
* exported NUMBER would go silently unclamped the moment it read a stale build
|
|
34
|
+
* of this package: `value.length > undefined` is `false`, so the clamp
|
|
35
|
+
* evaporates and the failure only shows up as a 500 from `signJoinToken` in
|
|
36
|
+
* production. A missing FUNCTION throws on the first call instead.
|
|
37
|
+
*
|
|
38
|
+
* Truncation rather than refusal is deliberate. A name is a label on a tile,
|
|
39
|
+
* and no call should fail to open over one.
|
|
40
|
+
*/
|
|
41
|
+
function clampParticipantName(value) {
|
|
42
|
+
return value.length > exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH ? value.slice(0, exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH) : value;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* `iss` IS the instance id (`legal-de`, `main`), not a service name.
|
|
46
|
+
*
|
|
47
|
+
* One plan proposed `iss: "tribenest-backend"` with the instance in a separate
|
|
48
|
+
* `inst` claim. That displaces the one value a verifier actually checks, and a
|
|
49
|
+
* legal-de token would then verify happily on the main instance - which is the
|
|
50
|
+
* whole reason instances are separate.
|
|
51
|
+
*/
|
|
52
|
+
exports.mediaJoinClaimsSchema = zod_1.z
|
|
53
|
+
.object({
|
|
54
|
+
v: zod_1.z.literal(1),
|
|
55
|
+
iss: zod_1.z.string().min(1),
|
|
56
|
+
aud: zod_1.z.literal("media"),
|
|
57
|
+
room: zod_1.z.string().min(1).max(200),
|
|
58
|
+
/** `identity`, not `sub`: it is a first-class concept the barrier rules name. */
|
|
59
|
+
identity: zod_1.z.string().min(1).max(200),
|
|
60
|
+
name: zod_1.z.string().max(exports.MEDIA_PARTICIPANT_NAME_MAX_LENGTH).optional(),
|
|
61
|
+
/** Top level, NOT inside grants - it decides what may be minted at all. */
|
|
62
|
+
kind: grants_1.participantKindSchema,
|
|
63
|
+
/** Top level. Transport authority is not media authority. */
|
|
64
|
+
transport: grants_1.transportKindSchema,
|
|
65
|
+
grants: grants_1.mediaGrantsSchema,
|
|
66
|
+
jti: zod_1.z.string().min(8),
|
|
67
|
+
iat: zod_1.z.number().int().positive(),
|
|
68
|
+
nbf: zod_1.z.number().int().positive().optional(),
|
|
69
|
+
exp: zod_1.z.number().int().positive(),
|
|
70
|
+
})
|
|
71
|
+
.strict();
|
|
72
|
+
/**
|
|
73
|
+
* Server-to-server control calls (create room, end room, attach an agent).
|
|
74
|
+
*
|
|
75
|
+
* A separate audience so a join token can never be replayed as a control call.
|
|
76
|
+
* It carries no room, identity, kind, transport or grants: a control caller is
|
|
77
|
+
* not a participant, and giving it participant-shaped claims invites code that
|
|
78
|
+
* treats it as one.
|
|
79
|
+
*/
|
|
80
|
+
exports.mediaControlClaimsSchema = zod_1.z
|
|
81
|
+
.object({
|
|
82
|
+
v: zod_1.z.literal(1),
|
|
83
|
+
iss: zod_1.z.string().min(1),
|
|
84
|
+
aud: zod_1.z.literal("control"),
|
|
85
|
+
jti: zod_1.z.string().min(8),
|
|
86
|
+
iat: zod_1.z.number().int().positive(),
|
|
87
|
+
nbf: zod_1.z.number().int().positive().optional(),
|
|
88
|
+
exp: zod_1.z.number().int().positive(),
|
|
89
|
+
})
|
|
90
|
+
.strict();
|
|
91
|
+
//# sourceMappingURL=claims.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"claims.js","sourceRoot":"","sources":["../src/claims.ts"],"names":[],"mappings":";;;AAuCA,oDAEC;AAzCD,6BAAwB;AACxB,qCAAyF;AAEzF;;;;;;GAMG;AAEH;;;;;;;;GAQG;AACU,QAAA,iCAAiC,GAAG,GAAG,CAAC;AAErD;;;;;;;;;;;;;;;;GAgBG;AACH,SAAgB,oBAAoB,CAAC,KAAa;IAChD,OAAO,KAAK,CAAC,MAAM,GAAG,yCAAiC,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,yCAAiC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC;AACtH,CAAC;AAED;;;;;;;GAOG;AACU,QAAA,qBAAqB,GAAG,OAAC;KACnC,MAAM,CAAC;IACN,CAAC,EAAE,OAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,OAAO,CAAC,OAAO,CAAC;IACvB,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,iFAAiF;IACjF,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC;IACpC,IAAI,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,yCAAiC,CAAC,CAAC,QAAQ,EAAE;IAClE,2EAA2E;IAC3E,IAAI,EAAE,8BAAqB;IAC3B,6DAA6D;IAC7D,SAAS,EAAE,4BAAmB;IAC9B,MAAM,EAAE,0BAAiB;IACzB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,MAAM,EAAE,CAAC;AAIZ;;;;;;;GAOG;AACU,QAAA,wBAAwB,GAAG,OAAC;KACtC,MAAM,CAAC;IACN,CAAC,EAAE,OAAC,CAAC,OAAO,CAAC,CAAC,CAAC;IACf,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,OAAO,CAAC,SAAS,CAAC;IACzB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACtB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;IAChC,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,EAAE;IAC3C,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE;CACjC,CAAC;KACD,MAAM,EAAE,CAAC"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* THE codec list. Every Router in the fleet is created from this array and no
|
|
3
|
+
* other, and every server-side participant derives what it can receive FROM it.
|
|
4
|
+
*
|
|
5
|
+
* ## Why it is pinned rather than left to mediasoup's defaults
|
|
6
|
+
*
|
|
7
|
+
* Two Routers that disagree about codecs cannot be piped. `pipeToRouter` and
|
|
8
|
+
* the hand-rolled equivalent in the node's `pipe.ts` both require the receiving
|
|
9
|
+
* Router to be able to consume the producer, and "able" is decided by this
|
|
10
|
+
* list. A node booted from a different build with one extra codec still pipes
|
|
11
|
+
* fine until the day a client happens to negotiate that codec, and then exactly
|
|
12
|
+
* one leg of one room goes silent, which reads as a network fault.
|
|
13
|
+
*
|
|
14
|
+
* So the list lives in one place and every Router in the fleet is created from
|
|
15
|
+
* it. A change here is a fleet-wide change and a deploy that mixes versions is
|
|
16
|
+
* a deploy that mixes codec sets, which is why `DEPLOYMENT.md` says drain
|
|
17
|
+
* before upgrade rather than rolling.
|
|
18
|
+
*
|
|
19
|
+
* ## Why it lives in the PROTOCOL package
|
|
20
|
+
*
|
|
21
|
+
* The node is not the only party that has to agree. A room agent, the SIP
|
|
22
|
+
* gateway and the RTMP ingress are participants, not nodes: each one has to
|
|
23
|
+
* declare RTP capabilities on `consume`, each one runs in its own app, and none
|
|
24
|
+
* of them may import `apps/media-server`. Every phase that needed this list
|
|
25
|
+
* from outside the node had exactly one alternative, which is to write a second
|
|
26
|
+
* copy - and a second copy is the failure the pinning exists to prevent. The
|
|
27
|
+
* earlier agent plan proved it: its contract test compared two hand-written
|
|
28
|
+
* lists to EACH OTHER and never to this one, so both could drift together and
|
|
29
|
+
* stay green.
|
|
30
|
+
*
|
|
31
|
+
* Codec agreement is a wire contract between parties that cannot import each
|
|
32
|
+
* other, which is the same reason the frames and the claims are here.
|
|
33
|
+
*
|
|
34
|
+
* ## Zero mediasoup, deliberately
|
|
35
|
+
*
|
|
36
|
+
* The types below are declared structurally rather than imported from
|
|
37
|
+
* mediasoup, because this package is isomorphic and a browser must be able to
|
|
38
|
+
* import a frame type without pulling in a C++ addon. `apps/media-server`
|
|
39
|
+
* re-exports these values through explicitly mediasoup-typed bindings, so if
|
|
40
|
+
* the two shapes ever diverge the node fails to COMPILE rather than failing to
|
|
41
|
+
* pipe at three in the morning.
|
|
42
|
+
*
|
|
43
|
+
* ## What is in it, and what is deliberately not
|
|
44
|
+
*
|
|
45
|
+
* Opus for audio, because it is the only audio codec every browser publishes
|
|
46
|
+
* and the only one worth transcoding to for SIP and for agents.
|
|
47
|
+
*
|
|
48
|
+
* VP8 and H.264 for video. VP8 is universal and simple; H.264 is what Safari
|
|
49
|
+
* and every hardware encoder produce, and its absence is not a quality loss but
|
|
50
|
+
* a "video does not work on iPhone" bug. Both are listed with the RTCP feedback
|
|
51
|
+
* mediasoup needs for keyframes and bandwidth estimation: `nack`, `pli` and
|
|
52
|
+
* `transport-cc`. Drop `pli` and a keyframe request has no wire representation,
|
|
53
|
+
* so every active-speaker switch shows macroblocks until the encoder happens to
|
|
54
|
+
* send an IDR on its own schedule.
|
|
55
|
+
*
|
|
56
|
+
* VP9 and AV1 are deliberately absent. Both are real wins and both are a
|
|
57
|
+
* separate decision with a measurement behind it: SVC changes what
|
|
58
|
+
* `setPreferredLayers` means, and adding a codec that only some clients
|
|
59
|
+
* negotiate widens the "one leg is silent" surface above.
|
|
60
|
+
*/
|
|
61
|
+
export type MediaKind = "audio" | "video";
|
|
62
|
+
export type MediaRtcpFeedback = {
|
|
63
|
+
type: string;
|
|
64
|
+
parameter?: string;
|
|
65
|
+
};
|
|
66
|
+
/** Structurally identical to mediasoup's `RouterRtpCodecCapability`. */
|
|
67
|
+
export type MediaCodecCapability = {
|
|
68
|
+
kind: MediaKind;
|
|
69
|
+
mimeType: string;
|
|
70
|
+
clockRate: number;
|
|
71
|
+
channels?: number;
|
|
72
|
+
parameters?: Record<string, unknown>;
|
|
73
|
+
rtcpFeedback?: MediaRtcpFeedback[];
|
|
74
|
+
preferredPayloadType?: number;
|
|
75
|
+
};
|
|
76
|
+
/** Structurally identical to mediasoup's `RtpCapabilities`. */
|
|
77
|
+
export type MediaRtpCapabilities = {
|
|
78
|
+
codecs: Array<MediaCodecCapability & {
|
|
79
|
+
preferredPayloadType: number;
|
|
80
|
+
}>;
|
|
81
|
+
/**
|
|
82
|
+
* Always empty, and typed as the empty tuple rather than an array of some
|
|
83
|
+
* element type.
|
|
84
|
+
*
|
|
85
|
+
* A server-side participant declares no header extensions: it reads the RTP
|
|
86
|
+
* header itself and wants nothing negotiated on top of it. Typing it this way
|
|
87
|
+
* also means this package never has to describe mediasoup's header-extension
|
|
88
|
+
* union in order for the node's mediasoup-typed re-export to stay assignable.
|
|
89
|
+
*/
|
|
90
|
+
headerExtensions: [];
|
|
91
|
+
};
|
|
92
|
+
export declare const MEDIA_CODECS: MediaCodecCapability[];
|
|
93
|
+
/**
|
|
94
|
+
* The audio half, for a participant that has no video at all.
|
|
95
|
+
*
|
|
96
|
+
* DERIVED, never written beside the list above. A hand-written copy for agents
|
|
97
|
+
* and SIP was compared against another hand-written copy in an earlier plan and
|
|
98
|
+
* never against this list, which is precisely the drift the pinning exists to
|
|
99
|
+
* prevent: both copies agree with each other and neither agrees with the fleet.
|
|
100
|
+
*/
|
|
101
|
+
export declare function audioOnlyCapabilities(codecs?: MediaCodecCapability[]): MediaRtpCapabilities;
|
|
102
|
+
//# sourceMappingURL=codecs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codecs.d.ts","sourceRoot":"","sources":["../src/codecs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2DG;AAEH,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,OAAO,CAAC;AAE1C,MAAM,MAAM,iBAAiB,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAErE,wEAAwE;AACxE,MAAM,MAAM,oBAAoB,GAAG;IACjC,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,YAAY,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACnC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,oBAAoB,GAAG;IACjC,MAAM,EAAE,KAAK,CAAC,oBAAoB,GAAG;QAAE,oBAAoB,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE;;;;;;;;OAQG;IACH,gBAAgB,EAAE,EAAE,CAAC;CACtB,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,oBAAoB,EA8C9C,CAAC;AAEF;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,GAAE,oBAAoB,EAAiB,GAAG,oBAAoB,CAiBzG"}
|