podcast manager

some documentation

+147 -15
+2 -1
.gitignore
··· 9 9 lerna-debug.log* 10 10 11 11 node_modules 12 - docs 12 + docs/* 13 + !docs/readme 13 14 dist 14 15 *.local 15 16 .eslintcache
docs/readme/.gitkeep

This is a binary file and will not be displayed.

docs/readme/connection-flow.png

This is a binary file and will not be displayed.

+145 -14
readme-devlog.org
··· 1 1 #+PROPERTY: COOKIE_DATA recursive 2 2 #+STARTUP: overview 3 3 4 - * concepts [0/4] 4 + * concepts [0/5] 5 5 6 6 the skypod architecture is broken into pieces: 7 7 ··· 27 27 It acts mostly as a smart router; socket connection, authentication, and directed and 28 28 realm-wide broadcast. 29 29 30 - ***** TODO webrtc requirements 30 + **** realm client 31 31 32 - - [ ] what needs to happen for webrtc? I think SDP messages will just flow like normal 33 - - checkout whatever simplepeer does 32 + The realm client manages a full-mesh p2p network with other connected peers in the realm, 33 + and exposes the combined set of incoming messages as a stream that the client can do 34 + whatever with. 34 35 35 - **** realm client 36 + ***** realm encryption 36 37 37 38 In order to keep private data off of the server, the realm client takes on the additional 38 - task of maintaining a shared encyrption key for the realm, which can be used to encrypt 39 + task of maintaining a shared encryption key for the realm, which can be used to encrypt 39 40 data going over broadcasts. 40 41 41 - ***** TODO key exchange protocol 42 + ****** TODO key exchange protocol 42 43 43 44 *** identity 44 45 ··· 64 65 65 66 Could we use webauthn, or some way to use a yubikey to sign something? 66 67 67 - *** sync 68 + *** connection flow 69 + 70 + #+begin_src mermaid :file docs/readme/connection-flow.png 71 + sequenceDiagram 72 + participant Server as Server 73 + participant Client as Client 74 + participant PeerA as Existing Peer A 75 + participant PeerB as Existing Peer B 76 + 77 + Client<<->>Server: WebSocket Connection 78 + 79 + Note over Client, Server: Authentication Phase (3 second timeout) 80 + alt Registration (new realm) 81 + Client->>Server: JWT: preauth.register {pubkey} 82 + Server->>Server: validate JWT signature 83 + Server->>Server: ensureRegisteredRealm(realmid, identid, pubkey) 84 + else Authentication (existing realm) 85 + Client->>Server: JWT: preauth.authn {} 86 + Server->>Server: get publickey for issuer 87 + Server->>Server: validate JWT signature 88 + else Invitation Exchange 89 + Client->>Server: JWT: preauth.exchange {inviteJwt, pubkey} 90 + Server->>Server: get publickey for issuer 91 + Server->>Server: validate invitation JWT signature & nonce 92 + Server->>Server: admitToRealm(realmid, identid, pubkey) 93 + Server->>Server: identity admitted 94 + end 95 + 96 + Note over PeerB, Server: Authenticated! Exchange Peer Identities 97 + par do 98 + Server->>Client: preauth.authn response {peers[], identities{}} 99 + and 100 + Server--)PeerA: realm.rtc.peer-joined {identid, pubkey} 101 + and 102 + Server--)PeerB: realm.rtc.peer-joined {identid, pubkey} 103 + end 104 + 105 + Note over Client, PeerB: WebRTC Connections (initiated by Client) 106 + par do per connected peer 107 + Client->>+Server: realm.rtc.signal {signed_jwt, localid, remoteid} 108 + Server->>PeerA: realm.rtc.signal {signed_jwt, localid, remoteid} 109 + PeerA->>PeerA: verify JWT signature (pubkey from `peer-joined`) 110 + PeerA->>Server: realm.rtc.signal {signed_answer_jwt, localid, remoteid} 111 + Server->>-Client: realm.rtc.signal {signed_answer_jwt, localid, remoteid} 112 + Client->>Client: verify JWT signature (pubkey from `authn` response) 113 + 114 + Note over Client, PeerA: Direct P2P Connection Established 115 + Client->>PeerA: Direct WebRTC Connection 116 + loop every 30s 117 + PeerA<<->>Client: realm.rtc.ping/pong 118 + PeerA<<->>Client: application messages 119 + end 120 + end 121 + 122 + Note over PeerB, Server: Message Flow (Operational) 123 + Client->>PeerA: Application Data (p2p) 124 + Client->>PeerB: Application Data (p2p) 125 + Client->>Server: realm.broadcast {payload, recipients} 126 + Server->>PeerB: realm.broadcast {payload} 127 + 128 + Note over PeerB, Server: Connection Persistence & Error Handling 129 + alt Socket Error/Close 130 + Client->>Client: Connection destroyed 131 + Server->>PeerA: realm.rtc.peer-left {identid} 132 + Server->>PeerB: realm.rtc.peer-left {identid} 133 + PeerA->>PeerA: Disconnect peer 134 + PeerB->>PeerB: Disconnect peer 135 + else Peer Leaves 136 + PeerA->>Server: Connection closes 137 + Server->>Client: realm.rtc.peer-left {peerA_identid} 138 + Server->>PeerB: realm.rtc.peer-left {peerA_identid} 139 + Client->>Client: Disconnect from PeerA 140 + end 141 + #+end_src 142 + 143 + #+RESULTS: 144 + [[file:docs/readme/connection-flow.png]] 145 + 146 + *** message format 147 + 148 + A message consists of: 149 + 150 + - ~typ~ :: the message type, see below 151 + - ~msg~ :: a message key, used for discrimination on the payload 152 + - ~seq?~ :: an (optional) sequence number, which allows for request/reply semantics 153 + - ~dat?~ :: a payload, the schema for which depends on ~typ~ and ~msg~ (possibly omitted) 154 + 155 + See ~#common/protocol~ for the messages that have been defined. 156 + 157 + **** ~typ~ 158 + 159 + - ~evt~ :: events - one-way notifications 160 + - ~req~ :: requests - request-response pattern with sequence matching 161 + - ~res~ :: responses - correlated responses to requests by ~seq~ 162 + - ~err~ :: errors - structured errors with HTTP-style status codes 163 + 164 + **** examples 165 + 166 + #+begin_example 167 + { 168 + "typ": "req", 169 + "msg": "preauth.register", 170 + "seq": 1234, 171 + "dat": { 172 + "pubkey": { ... } 173 + } 174 + } 175 + #+end_example 176 + 177 + #+begin_example 178 + { 179 + "typ": "req", 180 + "msg": "preauth.authn", 181 + "seq": 1234 182 + } 183 + #+end_example 184 + 185 + #+begin_example 186 + { 187 + "typ": "res", 188 + "msg": "preauth.authn", 189 + "seq": 1234, 190 + "dat": { 191 + "identities": { ... }, 192 + "peers": { ... } 193 + } 194 + } 195 + #+end_example 196 + 197 + *** message authentication 198 + 199 + A client authenticates to the system and to peers by exchanging signed JWTs as the first 200 + messages in the messaging protocol; for authenticating to the realm, and for exchanging 201 + webrtc signaling messages. 68 202 69 - Once a device has authenticated to the realm server over a websocket connection, it can 70 - send and broadcast any message it likes to the other online of the realm, via the websocket 71 - announcement channel. 203 + **** TODO webrtc encryption? 72 204 73 - This sets it up to be used as a signaling server for WebRTC, allowing realm devices to 74 - communicate p2p without a dependency on the realm server outside of authentication and 75 - signaling. 205 + The websocket is encrypted by virtue of ~wss~ and the server's cert, but I'm not sure if 206 + the traffic over webrtc is encrypted; if it's not, we should figure that out. 76 207 77 208 ** feed proxy server 78 209