├── .editorconfig ├── .github ├── dependabot.yaml └── workflows │ └── ci.yaml ├── .gitignore ├── .rustfmt.toml ├── Cargo.lock ├── Cargo.toml ├── Dockerfile ├── LICENSE ├── README.md ├── flake.lock ├── flake.nix ├── module.nix ├── package.nix └── src ├── cfg.rs ├── error.rs ├── main.rs └── routes.rs /.editorconfig: -------------------------------------------------------------------------------- 1 | [*] 2 | indent_size = 2 3 | indent_style = space 4 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | 8 | updates: 9 | - package-ecosystem: "cargo" 10 | directory: "/" 11 | schedule: 12 | interval: "daily" 13 | 14 | - package-ecosystem: "github-actions" 15 | directory: "/" 16 | schedule: 17 | interval: "daily" 18 | 19 | - package-ecosystem: "docker" 20 | directory: "/" 21 | schedule: 22 | interval: "daily" 23 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | tags: [ '*' ] 7 | pull_request: 8 | 9 | concurrency: 10 | group: ${{ github.workflow }}-${{ github.ref }} 11 | cancel-in-progress: true 12 | 13 | jobs: 14 | build: 15 | runs-on: ubuntu-latest 16 | 17 | strategy: 18 | matrix: 19 | target: 20 | - x86_64-unknown-linux-gnu 21 | #- aarch64-unknown-linux-gnu 22 | #- armv7-unknown-linux-gnueabihf 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | 27 | - uses: actions/cache@v4 28 | with: 29 | path: | 30 | ~/.cargo/bin/ 31 | ~/.cargo/registry/index/ 32 | ~/.cargo/registry/cache/ 33 | ~/.cargo/git/db/ 34 | target/ 35 | key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }} 36 | restore-keys: | 37 | ${{ runner.os }}-cargo-${{ matrix.target }}- 38 | 39 | - uses: dtolnay/rust-toolchain@stable 40 | 41 | #- name: Install cross 42 | #run: wget -cO - https://github.com/cross-rs/cross/releases/latest/download/cross-x86_64-unknown-linux-gnu.tar.gz | tar -xz 43 | 44 | - name: Build 45 | run: cargo build --release --target ${{ matrix.target }} 46 | #run: ./cross build --release --target ${{ matrix.target }} 47 | 48 | - name: Rename binary 49 | run: | 50 | mv target/${{ matrix.target }}/release/jitsi-openid jitsi-openid_${{ matrix.target }} 51 | 52 | - uses: actions/upload-artifact@v4 53 | with: 54 | name: jitsi-openid_${{ matrix.target }} 55 | path: jitsi-openid_${{ matrix.target }} 56 | 57 | - uses: crazy-max/ghaction-github-release@v2 58 | if: startsWith(github.ref, 'refs/tags/') 59 | with: 60 | files: jitsi-openid_${{ matrix.target }} 61 | 62 | docker: 63 | needs: build 64 | runs-on: ubuntu-latest 65 | 66 | permissions: 67 | packages: write 68 | 69 | steps: 70 | - uses: actions/checkout@v4 71 | 72 | - name: Docker meta 73 | id: meta 74 | uses: docker/metadata-action@v5 75 | with: 76 | images: | 77 | ghcr.io/${{ github.repository }} 78 | marcelcoding/jitsi-openid 79 | tags: | 80 | type=edge 81 | type=ref,event=pr 82 | type=semver,pattern={{version}} 83 | type=semver,pattern={{major}}.{{minor}} 84 | type=semver,pattern={{major}} 85 | 86 | - uses: docker/setup-qemu-action@v3 87 | - uses: docker/setup-buildx-action@v3 88 | 89 | - name: Cache Docker layers 90 | uses: actions/cache@v4 91 | with: 92 | path: /tmp/.buildx-cache 93 | key: ${{ runner.os }}-buildx-${{ github.sha }} 94 | restore-keys: | 95 | ${{ runner.os }}-buildx- 96 | 97 | - name: Login to GitHub Container Registry 98 | uses: docker/login-action@v3 99 | if: github.event_name != 'pull_request' 100 | with: 101 | registry: ghcr.io 102 | username: ${{ github.actor }} 103 | password: ${{ github.token }} 104 | 105 | - name: Login to Docker Hub 106 | uses: docker/login-action@v3 107 | if: github.event_name != 'pull_request' 108 | with: 109 | username: ${{ secrets.DOCKER_USERNAME }} 110 | password: ${{ secrets.DOCKER_TOKEN }} 111 | 112 | - name: Build 113 | uses: docker/build-push-action@v6 114 | with: 115 | platforms: linux/amd64,linux/arm64/v8 #,linux/arm/v7 116 | push: ${{ github.event_name != 'pull_request' }} 117 | tags: ${{ steps.meta.outputs.tags }} 118 | labels: ${{ steps.meta.outputs.labels }} 119 | cache-from: type=local,src=/tmp/.buildx-cache 120 | cache-to: type=local,dest=/tmp/.buildx-cache-new 121 | 122 | - name: Move cache 123 | run: | 124 | rm -rf /tmp/.buildx-cache 125 | mv /tmp/.buildx-cache-new /tmp/.buildx-cache 126 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | .idea 3 | *.iml 4 | -------------------------------------------------------------------------------- /.rustfmt.toml: -------------------------------------------------------------------------------- 1 | tab_spaces = 2 2 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "addr2line" 7 | version = "0.24.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" 10 | dependencies = [ 11 | "gimli", 12 | ] 13 | 14 | [[package]] 15 | name = "adler2" 16 | version = "2.0.0" 17 | source = "registry+https://github.com/rust-lang/crates.io-index" 18 | checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" 19 | 20 | [[package]] 21 | name = "android-tzdata" 22 | version = "0.1.1" 23 | source = "registry+https://github.com/rust-lang/crates.io-index" 24 | checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" 25 | 26 | [[package]] 27 | name = "android_system_properties" 28 | version = "0.1.5" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" 31 | dependencies = [ 32 | "libc", 33 | ] 34 | 35 | [[package]] 36 | name = "anyhow" 37 | version = "1.0.97" 38 | source = "registry+https://github.com/rust-lang/crates.io-index" 39 | checksum = "dcfed56ad506cb2c684a14971b8861fdc3baaaae314b9e5f9bb532cbe3ba7a4f" 40 | 41 | [[package]] 42 | name = "autocfg" 43 | version = "1.4.0" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" 46 | 47 | [[package]] 48 | name = "axum" 49 | version = "0.8.3" 50 | source = "registry+https://github.com/rust-lang/crates.io-index" 51 | checksum = "de45108900e1f9b9242f7f2e254aa3e2c029c921c258fe9e6b4217eeebd54288" 52 | dependencies = [ 53 | "axum-core", 54 | "bytes", 55 | "form_urlencoded", 56 | "futures-util", 57 | "http", 58 | "http-body", 59 | "http-body-util", 60 | "hyper", 61 | "hyper-util", 62 | "itoa", 63 | "matchit", 64 | "memchr", 65 | "mime", 66 | "percent-encoding", 67 | "pin-project-lite", 68 | "rustversion", 69 | "serde", 70 | "serde_path_to_error", 71 | "serde_urlencoded", 72 | "sync_wrapper", 73 | "tokio", 74 | "tower", 75 | "tower-layer", 76 | "tower-service", 77 | ] 78 | 79 | [[package]] 80 | name = "axum-core" 81 | version = "0.5.2" 82 | source = "registry+https://github.com/rust-lang/crates.io-index" 83 | checksum = "68464cd0412f486726fb3373129ef5d2993f90c34bc2bc1c1e9943b2f4fc7ca6" 84 | dependencies = [ 85 | "bytes", 86 | "futures-core", 87 | "http", 88 | "http-body", 89 | "http-body-util", 90 | "mime", 91 | "pin-project-lite", 92 | "rustversion", 93 | "sync_wrapper", 94 | "tower-layer", 95 | "tower-service", 96 | ] 97 | 98 | [[package]] 99 | name = "axum-extra" 100 | version = "0.10.1" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "45bf463831f5131b7d3c756525b305d40f1185b688565648a92e1392ca35713d" 103 | dependencies = [ 104 | "axum", 105 | "axum-core", 106 | "bytes", 107 | "cookie", 108 | "futures-util", 109 | "http", 110 | "http-body", 111 | "http-body-util", 112 | "mime", 113 | "pin-project-lite", 114 | "rustversion", 115 | "serde", 116 | "tower", 117 | "tower-layer", 118 | "tower-service", 119 | ] 120 | 121 | [[package]] 122 | name = "backtrace" 123 | version = "0.3.74" 124 | source = "registry+https://github.com/rust-lang/crates.io-index" 125 | checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a" 126 | dependencies = [ 127 | "addr2line", 128 | "cfg-if", 129 | "libc", 130 | "miniz_oxide", 131 | "object", 132 | "rustc-demangle", 133 | "windows-targets 0.52.6", 134 | ] 135 | 136 | [[package]] 137 | name = "base16ct" 138 | version = "0.2.0" 139 | source = "registry+https://github.com/rust-lang/crates.io-index" 140 | checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 141 | 142 | [[package]] 143 | name = "base64" 144 | version = "0.21.7" 145 | source = "registry+https://github.com/rust-lang/crates.io-index" 146 | checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" 147 | 148 | [[package]] 149 | name = "base64" 150 | version = "0.22.1" 151 | source = "registry+https://github.com/rust-lang/crates.io-index" 152 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 153 | 154 | [[package]] 155 | name = "base64ct" 156 | version = "1.7.3" 157 | source = "registry+https://github.com/rust-lang/crates.io-index" 158 | checksum = "89e25b6adfb930f02d1981565a6e5d9c547ac15a96606256d3b59040e5cd4ca3" 159 | 160 | [[package]] 161 | name = "bitflags" 162 | version = "2.9.0" 163 | source = "registry+https://github.com/rust-lang/crates.io-index" 164 | checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" 165 | 166 | [[package]] 167 | name = "block-buffer" 168 | version = "0.10.4" 169 | source = "registry+https://github.com/rust-lang/crates.io-index" 170 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 171 | dependencies = [ 172 | "generic-array", 173 | ] 174 | 175 | [[package]] 176 | name = "bumpalo" 177 | version = "3.17.0" 178 | source = "registry+https://github.com/rust-lang/crates.io-index" 179 | checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" 180 | 181 | [[package]] 182 | name = "byteorder" 183 | version = "1.5.0" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 186 | 187 | [[package]] 188 | name = "bytes" 189 | version = "1.10.1" 190 | source = "registry+https://github.com/rust-lang/crates.io-index" 191 | checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" 192 | 193 | [[package]] 194 | name = "cc" 195 | version = "1.2.18" 196 | source = "registry+https://github.com/rust-lang/crates.io-index" 197 | checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c" 198 | dependencies = [ 199 | "shlex", 200 | ] 201 | 202 | [[package]] 203 | name = "cfg-if" 204 | version = "1.0.0" 205 | source = "registry+https://github.com/rust-lang/crates.io-index" 206 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" 207 | 208 | [[package]] 209 | name = "cfg_aliases" 210 | version = "0.2.1" 211 | source = "registry+https://github.com/rust-lang/crates.io-index" 212 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 213 | 214 | [[package]] 215 | name = "chrono" 216 | version = "0.4.40" 217 | source = "registry+https://github.com/rust-lang/crates.io-index" 218 | checksum = "1a7964611d71df112cb1730f2ee67324fcf4d0fc6606acbbe9bfe06df124637c" 219 | dependencies = [ 220 | "android-tzdata", 221 | "iana-time-zone", 222 | "js-sys", 223 | "num-traits", 224 | "serde", 225 | "wasm-bindgen", 226 | "windows-link", 227 | ] 228 | 229 | [[package]] 230 | name = "config" 231 | version = "0.15.11" 232 | source = "registry+https://github.com/rust-lang/crates.io-index" 233 | checksum = "595aae20e65c3be792d05818e8c63025294ac3cb7e200f11459063a352a6ef80" 234 | dependencies = [ 235 | "pathdiff", 236 | "serde", 237 | "winnow", 238 | ] 239 | 240 | [[package]] 241 | name = "const-oid" 242 | version = "0.9.6" 243 | source = "registry+https://github.com/rust-lang/crates.io-index" 244 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 245 | 246 | [[package]] 247 | name = "cookie" 248 | version = "0.18.1" 249 | source = "registry+https://github.com/rust-lang/crates.io-index" 250 | checksum = "4ddef33a339a91ea89fb53151bd0a4689cfce27055c291dfa69945475d22c747" 251 | dependencies = [ 252 | "percent-encoding", 253 | "time", 254 | "version_check", 255 | ] 256 | 257 | [[package]] 258 | name = "core-foundation" 259 | version = "0.10.0" 260 | source = "registry+https://github.com/rust-lang/crates.io-index" 261 | checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" 262 | dependencies = [ 263 | "core-foundation-sys", 264 | "libc", 265 | ] 266 | 267 | [[package]] 268 | name = "core-foundation-sys" 269 | version = "0.8.7" 270 | source = "registry+https://github.com/rust-lang/crates.io-index" 271 | checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" 272 | 273 | [[package]] 274 | name = "cpufeatures" 275 | version = "0.2.17" 276 | source = "registry+https://github.com/rust-lang/crates.io-index" 277 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 278 | dependencies = [ 279 | "libc", 280 | ] 281 | 282 | [[package]] 283 | name = "crypto-bigint" 284 | version = "0.5.5" 285 | source = "registry+https://github.com/rust-lang/crates.io-index" 286 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 287 | dependencies = [ 288 | "generic-array", 289 | "rand_core 0.6.4", 290 | "subtle", 291 | "zeroize", 292 | ] 293 | 294 | [[package]] 295 | name = "crypto-common" 296 | version = "0.1.6" 297 | source = "registry+https://github.com/rust-lang/crates.io-index" 298 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 299 | dependencies = [ 300 | "generic-array", 301 | "typenum", 302 | ] 303 | 304 | [[package]] 305 | name = "curve25519-dalek" 306 | version = "4.1.3" 307 | source = "registry+https://github.com/rust-lang/crates.io-index" 308 | checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 309 | dependencies = [ 310 | "cfg-if", 311 | "cpufeatures", 312 | "curve25519-dalek-derive", 313 | "digest", 314 | "fiat-crypto", 315 | "rustc_version", 316 | "subtle", 317 | "zeroize", 318 | ] 319 | 320 | [[package]] 321 | name = "curve25519-dalek-derive" 322 | version = "0.1.1" 323 | source = "registry+https://github.com/rust-lang/crates.io-index" 324 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 325 | dependencies = [ 326 | "proc-macro2", 327 | "quote", 328 | "syn", 329 | ] 330 | 331 | [[package]] 332 | name = "darling" 333 | version = "0.20.11" 334 | source = "registry+https://github.com/rust-lang/crates.io-index" 335 | checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" 336 | dependencies = [ 337 | "darling_core", 338 | "darling_macro", 339 | ] 340 | 341 | [[package]] 342 | name = "darling_core" 343 | version = "0.20.11" 344 | source = "registry+https://github.com/rust-lang/crates.io-index" 345 | checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" 346 | dependencies = [ 347 | "fnv", 348 | "ident_case", 349 | "proc-macro2", 350 | "quote", 351 | "strsim", 352 | "syn", 353 | ] 354 | 355 | [[package]] 356 | name = "darling_macro" 357 | version = "0.20.11" 358 | source = "registry+https://github.com/rust-lang/crates.io-index" 359 | checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" 360 | dependencies = [ 361 | "darling_core", 362 | "quote", 363 | "syn", 364 | ] 365 | 366 | [[package]] 367 | name = "der" 368 | version = "0.7.9" 369 | source = "registry+https://github.com/rust-lang/crates.io-index" 370 | checksum = "f55bf8e7b65898637379c1b74eb1551107c8294ed26d855ceb9fd1a09cfc9bc0" 371 | dependencies = [ 372 | "const-oid", 373 | "pem-rfc7468", 374 | "zeroize", 375 | ] 376 | 377 | [[package]] 378 | name = "deranged" 379 | version = "0.4.0" 380 | source = "registry+https://github.com/rust-lang/crates.io-index" 381 | checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" 382 | dependencies = [ 383 | "powerfmt", 384 | "serde", 385 | ] 386 | 387 | [[package]] 388 | name = "digest" 389 | version = "0.10.7" 390 | source = "registry+https://github.com/rust-lang/crates.io-index" 391 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 392 | dependencies = [ 393 | "block-buffer", 394 | "const-oid", 395 | "crypto-common", 396 | "subtle", 397 | ] 398 | 399 | [[package]] 400 | name = "displaydoc" 401 | version = "0.2.5" 402 | source = "registry+https://github.com/rust-lang/crates.io-index" 403 | checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" 404 | dependencies = [ 405 | "proc-macro2", 406 | "quote", 407 | "syn", 408 | ] 409 | 410 | [[package]] 411 | name = "dyn-clone" 412 | version = "1.0.19" 413 | source = "registry+https://github.com/rust-lang/crates.io-index" 414 | checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005" 415 | 416 | [[package]] 417 | name = "ecdsa" 418 | version = "0.16.9" 419 | source = "registry+https://github.com/rust-lang/crates.io-index" 420 | checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 421 | dependencies = [ 422 | "der", 423 | "digest", 424 | "elliptic-curve", 425 | "rfc6979", 426 | "signature", 427 | "spki", 428 | ] 429 | 430 | [[package]] 431 | name = "ed25519" 432 | version = "2.2.3" 433 | source = "registry+https://github.com/rust-lang/crates.io-index" 434 | checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" 435 | dependencies = [ 436 | "pkcs8", 437 | "signature", 438 | ] 439 | 440 | [[package]] 441 | name = "ed25519-dalek" 442 | version = "2.1.1" 443 | source = "registry+https://github.com/rust-lang/crates.io-index" 444 | checksum = "4a3daa8e81a3963a60642bcc1f90a670680bd4a77535faa384e9d1c79d620871" 445 | dependencies = [ 446 | "curve25519-dalek", 447 | "ed25519", 448 | "serde", 449 | "sha2", 450 | "subtle", 451 | "zeroize", 452 | ] 453 | 454 | [[package]] 455 | name = "either" 456 | version = "1.15.0" 457 | source = "registry+https://github.com/rust-lang/crates.io-index" 458 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 459 | 460 | [[package]] 461 | name = "elliptic-curve" 462 | version = "0.13.8" 463 | source = "registry+https://github.com/rust-lang/crates.io-index" 464 | checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 465 | dependencies = [ 466 | "base16ct", 467 | "crypto-bigint", 468 | "digest", 469 | "ff", 470 | "generic-array", 471 | "group", 472 | "hkdf", 473 | "pem-rfc7468", 474 | "pkcs8", 475 | "rand_core 0.6.4", 476 | "sec1", 477 | "subtle", 478 | "zeroize", 479 | ] 480 | 481 | [[package]] 482 | name = "equivalent" 483 | version = "1.0.2" 484 | source = "registry+https://github.com/rust-lang/crates.io-index" 485 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 486 | 487 | [[package]] 488 | name = "ff" 489 | version = "0.13.1" 490 | source = "registry+https://github.com/rust-lang/crates.io-index" 491 | checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" 492 | dependencies = [ 493 | "rand_core 0.6.4", 494 | "subtle", 495 | ] 496 | 497 | [[package]] 498 | name = "fiat-crypto" 499 | version = "0.2.9" 500 | source = "registry+https://github.com/rust-lang/crates.io-index" 501 | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 502 | 503 | [[package]] 504 | name = "fnv" 505 | version = "1.0.7" 506 | source = "registry+https://github.com/rust-lang/crates.io-index" 507 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 508 | 509 | [[package]] 510 | name = "form_urlencoded" 511 | version = "1.2.1" 512 | source = "registry+https://github.com/rust-lang/crates.io-index" 513 | checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" 514 | dependencies = [ 515 | "percent-encoding", 516 | ] 517 | 518 | [[package]] 519 | name = "futures-channel" 520 | version = "0.3.31" 521 | source = "registry+https://github.com/rust-lang/crates.io-index" 522 | checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" 523 | dependencies = [ 524 | "futures-core", 525 | ] 526 | 527 | [[package]] 528 | name = "futures-core" 529 | version = "0.3.31" 530 | source = "registry+https://github.com/rust-lang/crates.io-index" 531 | checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" 532 | 533 | [[package]] 534 | name = "futures-task" 535 | version = "0.3.31" 536 | source = "registry+https://github.com/rust-lang/crates.io-index" 537 | checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" 538 | 539 | [[package]] 540 | name = "futures-util" 541 | version = "0.3.31" 542 | source = "registry+https://github.com/rust-lang/crates.io-index" 543 | checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" 544 | dependencies = [ 545 | "futures-core", 546 | "futures-task", 547 | "pin-project-lite", 548 | "pin-utils", 549 | ] 550 | 551 | [[package]] 552 | name = "generic-array" 553 | version = "0.14.7" 554 | source = "registry+https://github.com/rust-lang/crates.io-index" 555 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 556 | dependencies = [ 557 | "typenum", 558 | "version_check", 559 | "zeroize", 560 | ] 561 | 562 | [[package]] 563 | name = "getrandom" 564 | version = "0.2.15" 565 | source = "registry+https://github.com/rust-lang/crates.io-index" 566 | checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" 567 | dependencies = [ 568 | "cfg-if", 569 | "js-sys", 570 | "libc", 571 | "wasi 0.11.0+wasi-snapshot-preview1", 572 | "wasm-bindgen", 573 | ] 574 | 575 | [[package]] 576 | name = "getrandom" 577 | version = "0.3.2" 578 | source = "registry+https://github.com/rust-lang/crates.io-index" 579 | checksum = "73fea8450eea4bac3940448fb7ae50d91f034f941199fcd9d909a5a07aa455f0" 580 | dependencies = [ 581 | "cfg-if", 582 | "js-sys", 583 | "libc", 584 | "r-efi", 585 | "wasi 0.14.2+wasi-0.2.4", 586 | "wasm-bindgen", 587 | ] 588 | 589 | [[package]] 590 | name = "gimli" 591 | version = "0.31.1" 592 | source = "registry+https://github.com/rust-lang/crates.io-index" 593 | checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" 594 | 595 | [[package]] 596 | name = "group" 597 | version = "0.13.0" 598 | source = "registry+https://github.com/rust-lang/crates.io-index" 599 | checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 600 | dependencies = [ 601 | "ff", 602 | "rand_core 0.6.4", 603 | "subtle", 604 | ] 605 | 606 | [[package]] 607 | name = "hashbrown" 608 | version = "0.12.3" 609 | source = "registry+https://github.com/rust-lang/crates.io-index" 610 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" 611 | 612 | [[package]] 613 | name = "hashbrown" 614 | version = "0.15.2" 615 | source = "registry+https://github.com/rust-lang/crates.io-index" 616 | checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" 617 | 618 | [[package]] 619 | name = "hex" 620 | version = "0.4.3" 621 | source = "registry+https://github.com/rust-lang/crates.io-index" 622 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" 623 | 624 | [[package]] 625 | name = "hkdf" 626 | version = "0.12.4" 627 | source = "registry+https://github.com/rust-lang/crates.io-index" 628 | checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" 629 | dependencies = [ 630 | "hmac", 631 | ] 632 | 633 | [[package]] 634 | name = "hmac" 635 | version = "0.12.1" 636 | source = "registry+https://github.com/rust-lang/crates.io-index" 637 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 638 | dependencies = [ 639 | "digest", 640 | ] 641 | 642 | [[package]] 643 | name = "http" 644 | version = "1.3.1" 645 | source = "registry+https://github.com/rust-lang/crates.io-index" 646 | checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" 647 | dependencies = [ 648 | "bytes", 649 | "fnv", 650 | "itoa", 651 | ] 652 | 653 | [[package]] 654 | name = "http-body" 655 | version = "1.0.1" 656 | source = "registry+https://github.com/rust-lang/crates.io-index" 657 | checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" 658 | dependencies = [ 659 | "bytes", 660 | "http", 661 | ] 662 | 663 | [[package]] 664 | name = "http-body-util" 665 | version = "0.1.3" 666 | source = "registry+https://github.com/rust-lang/crates.io-index" 667 | checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" 668 | dependencies = [ 669 | "bytes", 670 | "futures-core", 671 | "http", 672 | "http-body", 673 | "pin-project-lite", 674 | ] 675 | 676 | [[package]] 677 | name = "httparse" 678 | version = "1.10.1" 679 | source = "registry+https://github.com/rust-lang/crates.io-index" 680 | checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" 681 | 682 | [[package]] 683 | name = "httpdate" 684 | version = "1.0.3" 685 | source = "registry+https://github.com/rust-lang/crates.io-index" 686 | checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" 687 | 688 | [[package]] 689 | name = "hyper" 690 | version = "1.6.0" 691 | source = "registry+https://github.com/rust-lang/crates.io-index" 692 | checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" 693 | dependencies = [ 694 | "bytes", 695 | "futures-channel", 696 | "futures-util", 697 | "http", 698 | "http-body", 699 | "httparse", 700 | "httpdate", 701 | "itoa", 702 | "pin-project-lite", 703 | "smallvec", 704 | "tokio", 705 | "want", 706 | ] 707 | 708 | [[package]] 709 | name = "hyper-rustls" 710 | version = "0.27.5" 711 | source = "registry+https://github.com/rust-lang/crates.io-index" 712 | checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" 713 | dependencies = [ 714 | "futures-util", 715 | "http", 716 | "hyper", 717 | "hyper-util", 718 | "rustls", 719 | "rustls-native-certs", 720 | "rustls-pki-types", 721 | "tokio", 722 | "tokio-rustls", 723 | "tower-service", 724 | "webpki-roots", 725 | ] 726 | 727 | [[package]] 728 | name = "hyper-util" 729 | version = "0.1.11" 730 | source = "registry+https://github.com/rust-lang/crates.io-index" 731 | checksum = "497bbc33a26fdd4af9ed9c70d63f61cf56a938375fbb32df34db9b1cd6d643f2" 732 | dependencies = [ 733 | "bytes", 734 | "futures-channel", 735 | "futures-util", 736 | "http", 737 | "http-body", 738 | "hyper", 739 | "libc", 740 | "pin-project-lite", 741 | "socket2", 742 | "tokio", 743 | "tower-service", 744 | "tracing", 745 | ] 746 | 747 | [[package]] 748 | name = "iana-time-zone" 749 | version = "0.1.63" 750 | source = "registry+https://github.com/rust-lang/crates.io-index" 751 | checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" 752 | dependencies = [ 753 | "android_system_properties", 754 | "core-foundation-sys", 755 | "iana-time-zone-haiku", 756 | "js-sys", 757 | "log", 758 | "wasm-bindgen", 759 | "windows-core", 760 | ] 761 | 762 | [[package]] 763 | name = "iana-time-zone-haiku" 764 | version = "0.1.2" 765 | source = "registry+https://github.com/rust-lang/crates.io-index" 766 | checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" 767 | dependencies = [ 768 | "cc", 769 | ] 770 | 771 | [[package]] 772 | name = "icu_collections" 773 | version = "1.5.0" 774 | source = "registry+https://github.com/rust-lang/crates.io-index" 775 | checksum = "db2fa452206ebee18c4b5c2274dbf1de17008e874b4dc4f0aea9d01ca79e4526" 776 | dependencies = [ 777 | "displaydoc", 778 | "yoke", 779 | "zerofrom", 780 | "zerovec", 781 | ] 782 | 783 | [[package]] 784 | name = "icu_locid" 785 | version = "1.5.0" 786 | source = "registry+https://github.com/rust-lang/crates.io-index" 787 | checksum = "13acbb8371917fc971be86fc8057c41a64b521c184808a698c02acc242dbf637" 788 | dependencies = [ 789 | "displaydoc", 790 | "litemap", 791 | "tinystr", 792 | "writeable", 793 | "zerovec", 794 | ] 795 | 796 | [[package]] 797 | name = "icu_locid_transform" 798 | version = "1.5.0" 799 | source = "registry+https://github.com/rust-lang/crates.io-index" 800 | checksum = "01d11ac35de8e40fdeda00d9e1e9d92525f3f9d887cdd7aa81d727596788b54e" 801 | dependencies = [ 802 | "displaydoc", 803 | "icu_locid", 804 | "icu_locid_transform_data", 805 | "icu_provider", 806 | "tinystr", 807 | "zerovec", 808 | ] 809 | 810 | [[package]] 811 | name = "icu_locid_transform_data" 812 | version = "1.5.1" 813 | source = "registry+https://github.com/rust-lang/crates.io-index" 814 | checksum = "7515e6d781098bf9f7205ab3fc7e9709d34554ae0b21ddbcb5febfa4bc7df11d" 815 | 816 | [[package]] 817 | name = "icu_normalizer" 818 | version = "1.5.0" 819 | source = "registry+https://github.com/rust-lang/crates.io-index" 820 | checksum = "19ce3e0da2ec68599d193c93d088142efd7f9c5d6fc9b803774855747dc6a84f" 821 | dependencies = [ 822 | "displaydoc", 823 | "icu_collections", 824 | "icu_normalizer_data", 825 | "icu_properties", 826 | "icu_provider", 827 | "smallvec", 828 | "utf16_iter", 829 | "utf8_iter", 830 | "write16", 831 | "zerovec", 832 | ] 833 | 834 | [[package]] 835 | name = "icu_normalizer_data" 836 | version = "1.5.1" 837 | source = "registry+https://github.com/rust-lang/crates.io-index" 838 | checksum = "c5e8338228bdc8ab83303f16b797e177953730f601a96c25d10cb3ab0daa0cb7" 839 | 840 | [[package]] 841 | name = "icu_properties" 842 | version = "1.5.1" 843 | source = "registry+https://github.com/rust-lang/crates.io-index" 844 | checksum = "93d6020766cfc6302c15dbbc9c8778c37e62c14427cb7f6e601d849e092aeef5" 845 | dependencies = [ 846 | "displaydoc", 847 | "icu_collections", 848 | "icu_locid_transform", 849 | "icu_properties_data", 850 | "icu_provider", 851 | "tinystr", 852 | "zerovec", 853 | ] 854 | 855 | [[package]] 856 | name = "icu_properties_data" 857 | version = "1.5.1" 858 | source = "registry+https://github.com/rust-lang/crates.io-index" 859 | checksum = "85fb8799753b75aee8d2a21d7c14d9f38921b54b3dbda10f5a3c7a7b82dba5e2" 860 | 861 | [[package]] 862 | name = "icu_provider" 863 | version = "1.5.0" 864 | source = "registry+https://github.com/rust-lang/crates.io-index" 865 | checksum = "6ed421c8a8ef78d3e2dbc98a973be2f3770cb42b606e3ab18d6237c4dfde68d9" 866 | dependencies = [ 867 | "displaydoc", 868 | "icu_locid", 869 | "icu_provider_macros", 870 | "stable_deref_trait", 871 | "tinystr", 872 | "writeable", 873 | "yoke", 874 | "zerofrom", 875 | "zerovec", 876 | ] 877 | 878 | [[package]] 879 | name = "icu_provider_macros" 880 | version = "1.5.0" 881 | source = "registry+https://github.com/rust-lang/crates.io-index" 882 | checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" 883 | dependencies = [ 884 | "proc-macro2", 885 | "quote", 886 | "syn", 887 | ] 888 | 889 | [[package]] 890 | name = "ident_case" 891 | version = "1.0.1" 892 | source = "registry+https://github.com/rust-lang/crates.io-index" 893 | checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" 894 | 895 | [[package]] 896 | name = "idna" 897 | version = "1.0.3" 898 | source = "registry+https://github.com/rust-lang/crates.io-index" 899 | checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" 900 | dependencies = [ 901 | "idna_adapter", 902 | "smallvec", 903 | "utf8_iter", 904 | ] 905 | 906 | [[package]] 907 | name = "idna_adapter" 908 | version = "1.2.0" 909 | source = "registry+https://github.com/rust-lang/crates.io-index" 910 | checksum = "daca1df1c957320b2cf139ac61e7bd64fed304c5040df000a745aa1de3b4ef71" 911 | dependencies = [ 912 | "icu_normalizer", 913 | "icu_properties", 914 | ] 915 | 916 | [[package]] 917 | name = "indexmap" 918 | version = "1.9.3" 919 | source = "registry+https://github.com/rust-lang/crates.io-index" 920 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" 921 | dependencies = [ 922 | "autocfg", 923 | "hashbrown 0.12.3", 924 | "serde", 925 | ] 926 | 927 | [[package]] 928 | name = "indexmap" 929 | version = "2.9.0" 930 | source = "registry+https://github.com/rust-lang/crates.io-index" 931 | checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e" 932 | dependencies = [ 933 | "equivalent", 934 | "hashbrown 0.15.2", 935 | "serde", 936 | ] 937 | 938 | [[package]] 939 | name = "ipnet" 940 | version = "2.11.0" 941 | source = "registry+https://github.com/rust-lang/crates.io-index" 942 | checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" 943 | 944 | [[package]] 945 | name = "itertools" 946 | version = "0.10.5" 947 | source = "registry+https://github.com/rust-lang/crates.io-index" 948 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 949 | dependencies = [ 950 | "either", 951 | ] 952 | 953 | [[package]] 954 | name = "itoa" 955 | version = "1.0.15" 956 | source = "registry+https://github.com/rust-lang/crates.io-index" 957 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 958 | 959 | [[package]] 960 | name = "jitsi-openid" 961 | version = "2.0.18" 962 | dependencies = [ 963 | "anyhow", 964 | "axum", 965 | "axum-extra", 966 | "config", 967 | "jsonwebtoken", 968 | "openidconnect", 969 | "reqwest", 970 | "serde", 971 | "time", 972 | "tokio", 973 | "tracing", 974 | "tracing-subscriber", 975 | "url", 976 | "uuid", 977 | ] 978 | 979 | [[package]] 980 | name = "js-sys" 981 | version = "0.3.77" 982 | source = "registry+https://github.com/rust-lang/crates.io-index" 983 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 984 | dependencies = [ 985 | "once_cell", 986 | "wasm-bindgen", 987 | ] 988 | 989 | [[package]] 990 | name = "jsonwebtoken" 991 | version = "9.3.1" 992 | source = "registry+https://github.com/rust-lang/crates.io-index" 993 | checksum = "5a87cc7a48537badeae96744432de36f4be2b4a34a05a5ef32e9dd8a1c169dde" 994 | dependencies = [ 995 | "base64 0.22.1", 996 | "js-sys", 997 | "ring", 998 | "serde", 999 | "serde_json", 1000 | ] 1001 | 1002 | [[package]] 1003 | name = "lazy_static" 1004 | version = "1.5.0" 1005 | source = "registry+https://github.com/rust-lang/crates.io-index" 1006 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1007 | dependencies = [ 1008 | "spin", 1009 | ] 1010 | 1011 | [[package]] 1012 | name = "libc" 1013 | version = "0.2.171" 1014 | source = "registry+https://github.com/rust-lang/crates.io-index" 1015 | checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6" 1016 | 1017 | [[package]] 1018 | name = "libm" 1019 | version = "0.2.11" 1020 | source = "registry+https://github.com/rust-lang/crates.io-index" 1021 | checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" 1022 | 1023 | [[package]] 1024 | name = "litemap" 1025 | version = "0.7.5" 1026 | source = "registry+https://github.com/rust-lang/crates.io-index" 1027 | checksum = "23fb14cb19457329c82206317a5663005a4d404783dc74f4252769b0d5f42856" 1028 | 1029 | [[package]] 1030 | name = "log" 1031 | version = "0.4.27" 1032 | source = "registry+https://github.com/rust-lang/crates.io-index" 1033 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 1034 | 1035 | [[package]] 1036 | name = "matchit" 1037 | version = "0.8.4" 1038 | source = "registry+https://github.com/rust-lang/crates.io-index" 1039 | checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" 1040 | 1041 | [[package]] 1042 | name = "memchr" 1043 | version = "2.7.4" 1044 | source = "registry+https://github.com/rust-lang/crates.io-index" 1045 | checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" 1046 | 1047 | [[package]] 1048 | name = "mime" 1049 | version = "0.3.17" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" 1052 | 1053 | [[package]] 1054 | name = "miniz_oxide" 1055 | version = "0.8.7" 1056 | source = "registry+https://github.com/rust-lang/crates.io-index" 1057 | checksum = "ff70ce3e48ae43fa075863cef62e8b43b71a4f2382229920e0df362592919430" 1058 | dependencies = [ 1059 | "adler2", 1060 | ] 1061 | 1062 | [[package]] 1063 | name = "mio" 1064 | version = "1.0.3" 1065 | source = "registry+https://github.com/rust-lang/crates.io-index" 1066 | checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" 1067 | dependencies = [ 1068 | "libc", 1069 | "wasi 0.11.0+wasi-snapshot-preview1", 1070 | "windows-sys 0.52.0", 1071 | ] 1072 | 1073 | [[package]] 1074 | name = "nu-ansi-term" 1075 | version = "0.46.0" 1076 | source = "registry+https://github.com/rust-lang/crates.io-index" 1077 | checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84" 1078 | dependencies = [ 1079 | "overload", 1080 | "winapi", 1081 | ] 1082 | 1083 | [[package]] 1084 | name = "num-bigint-dig" 1085 | version = "0.8.4" 1086 | source = "registry+https://github.com/rust-lang/crates.io-index" 1087 | checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" 1088 | dependencies = [ 1089 | "byteorder", 1090 | "lazy_static", 1091 | "libm", 1092 | "num-integer", 1093 | "num-iter", 1094 | "num-traits", 1095 | "rand 0.8.5", 1096 | "smallvec", 1097 | "zeroize", 1098 | ] 1099 | 1100 | [[package]] 1101 | name = "num-conv" 1102 | version = "0.1.0" 1103 | source = "registry+https://github.com/rust-lang/crates.io-index" 1104 | checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" 1105 | 1106 | [[package]] 1107 | name = "num-integer" 1108 | version = "0.1.46" 1109 | source = "registry+https://github.com/rust-lang/crates.io-index" 1110 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1111 | dependencies = [ 1112 | "num-traits", 1113 | ] 1114 | 1115 | [[package]] 1116 | name = "num-iter" 1117 | version = "0.1.45" 1118 | source = "registry+https://github.com/rust-lang/crates.io-index" 1119 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1120 | dependencies = [ 1121 | "autocfg", 1122 | "num-integer", 1123 | "num-traits", 1124 | ] 1125 | 1126 | [[package]] 1127 | name = "num-traits" 1128 | version = "0.2.19" 1129 | source = "registry+https://github.com/rust-lang/crates.io-index" 1130 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1131 | dependencies = [ 1132 | "autocfg", 1133 | "libm", 1134 | ] 1135 | 1136 | [[package]] 1137 | name = "oauth2" 1138 | version = "5.0.0" 1139 | source = "registry+https://github.com/rust-lang/crates.io-index" 1140 | checksum = "51e219e79014df21a225b1860a479e2dcd7cbd9130f4defd4bd0e191ea31d67d" 1141 | dependencies = [ 1142 | "base64 0.22.1", 1143 | "chrono", 1144 | "getrandom 0.2.15", 1145 | "http", 1146 | "rand 0.8.5", 1147 | "reqwest", 1148 | "serde", 1149 | "serde_json", 1150 | "serde_path_to_error", 1151 | "sha2", 1152 | "thiserror 1.0.69", 1153 | "url", 1154 | ] 1155 | 1156 | [[package]] 1157 | name = "object" 1158 | version = "0.36.7" 1159 | source = "registry+https://github.com/rust-lang/crates.io-index" 1160 | checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" 1161 | dependencies = [ 1162 | "memchr", 1163 | ] 1164 | 1165 | [[package]] 1166 | name = "once_cell" 1167 | version = "1.21.3" 1168 | source = "registry+https://github.com/rust-lang/crates.io-index" 1169 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1170 | 1171 | [[package]] 1172 | name = "openidconnect" 1173 | version = "4.0.0" 1174 | source = "registry+https://github.com/rust-lang/crates.io-index" 1175 | checksum = "6dd50d4a5e7730e754f94d977efe61f611aadd3131f6a2b464f6e3a4167e8ef7" 1176 | dependencies = [ 1177 | "base64 0.21.7", 1178 | "chrono", 1179 | "dyn-clone", 1180 | "ed25519-dalek", 1181 | "hmac", 1182 | "http", 1183 | "itertools", 1184 | "log", 1185 | "oauth2", 1186 | "p256", 1187 | "p384", 1188 | "rand 0.8.5", 1189 | "rsa", 1190 | "serde", 1191 | "serde-value", 1192 | "serde_json", 1193 | "serde_path_to_error", 1194 | "serde_plain", 1195 | "serde_with", 1196 | "sha2", 1197 | "subtle", 1198 | "thiserror 1.0.69", 1199 | "url", 1200 | ] 1201 | 1202 | [[package]] 1203 | name = "openssl-probe" 1204 | version = "0.1.6" 1205 | source = "registry+https://github.com/rust-lang/crates.io-index" 1206 | checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" 1207 | 1208 | [[package]] 1209 | name = "ordered-float" 1210 | version = "2.10.1" 1211 | source = "registry+https://github.com/rust-lang/crates.io-index" 1212 | checksum = "68f19d67e5a2795c94e73e0bb1cc1a7edeb2e28efd39e2e1c9b7a40c1108b11c" 1213 | dependencies = [ 1214 | "num-traits", 1215 | ] 1216 | 1217 | [[package]] 1218 | name = "overload" 1219 | version = "0.1.1" 1220 | source = "registry+https://github.com/rust-lang/crates.io-index" 1221 | checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" 1222 | 1223 | [[package]] 1224 | name = "p256" 1225 | version = "0.13.2" 1226 | source = "registry+https://github.com/rust-lang/crates.io-index" 1227 | checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" 1228 | dependencies = [ 1229 | "ecdsa", 1230 | "elliptic-curve", 1231 | "primeorder", 1232 | "sha2", 1233 | ] 1234 | 1235 | [[package]] 1236 | name = "p384" 1237 | version = "0.13.1" 1238 | source = "registry+https://github.com/rust-lang/crates.io-index" 1239 | checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" 1240 | dependencies = [ 1241 | "ecdsa", 1242 | "elliptic-curve", 1243 | "primeorder", 1244 | "sha2", 1245 | ] 1246 | 1247 | [[package]] 1248 | name = "pathdiff" 1249 | version = "0.2.3" 1250 | source = "registry+https://github.com/rust-lang/crates.io-index" 1251 | checksum = "df94ce210e5bc13cb6651479fa48d14f601d9858cfe0467f43ae157023b938d3" 1252 | 1253 | [[package]] 1254 | name = "pem-rfc7468" 1255 | version = "0.7.0" 1256 | source = "registry+https://github.com/rust-lang/crates.io-index" 1257 | checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" 1258 | dependencies = [ 1259 | "base64ct", 1260 | ] 1261 | 1262 | [[package]] 1263 | name = "percent-encoding" 1264 | version = "2.3.1" 1265 | source = "registry+https://github.com/rust-lang/crates.io-index" 1266 | checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" 1267 | 1268 | [[package]] 1269 | name = "pin-project-lite" 1270 | version = "0.2.16" 1271 | source = "registry+https://github.com/rust-lang/crates.io-index" 1272 | checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" 1273 | 1274 | [[package]] 1275 | name = "pin-utils" 1276 | version = "0.1.0" 1277 | source = "registry+https://github.com/rust-lang/crates.io-index" 1278 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" 1279 | 1280 | [[package]] 1281 | name = "pkcs1" 1282 | version = "0.7.5" 1283 | source = "registry+https://github.com/rust-lang/crates.io-index" 1284 | checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" 1285 | dependencies = [ 1286 | "der", 1287 | "pkcs8", 1288 | "spki", 1289 | ] 1290 | 1291 | [[package]] 1292 | name = "pkcs8" 1293 | version = "0.10.2" 1294 | source = "registry+https://github.com/rust-lang/crates.io-index" 1295 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1296 | dependencies = [ 1297 | "der", 1298 | "spki", 1299 | ] 1300 | 1301 | [[package]] 1302 | name = "powerfmt" 1303 | version = "0.2.0" 1304 | source = "registry+https://github.com/rust-lang/crates.io-index" 1305 | checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" 1306 | 1307 | [[package]] 1308 | name = "ppv-lite86" 1309 | version = "0.2.21" 1310 | source = "registry+https://github.com/rust-lang/crates.io-index" 1311 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1312 | dependencies = [ 1313 | "zerocopy", 1314 | ] 1315 | 1316 | [[package]] 1317 | name = "primeorder" 1318 | version = "0.13.6" 1319 | source = "registry+https://github.com/rust-lang/crates.io-index" 1320 | checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" 1321 | dependencies = [ 1322 | "elliptic-curve", 1323 | ] 1324 | 1325 | [[package]] 1326 | name = "proc-macro2" 1327 | version = "1.0.94" 1328 | source = "registry+https://github.com/rust-lang/crates.io-index" 1329 | checksum = "a31971752e70b8b2686d7e46ec17fb38dad4051d94024c88df49b667caea9c84" 1330 | dependencies = [ 1331 | "unicode-ident", 1332 | ] 1333 | 1334 | [[package]] 1335 | name = "quinn" 1336 | version = "0.11.7" 1337 | source = "registry+https://github.com/rust-lang/crates.io-index" 1338 | checksum = "c3bd15a6f2967aef83887dcb9fec0014580467e33720d073560cf015a5683012" 1339 | dependencies = [ 1340 | "bytes", 1341 | "cfg_aliases", 1342 | "pin-project-lite", 1343 | "quinn-proto", 1344 | "quinn-udp", 1345 | "rustc-hash", 1346 | "rustls", 1347 | "socket2", 1348 | "thiserror 2.0.12", 1349 | "tokio", 1350 | "tracing", 1351 | "web-time", 1352 | ] 1353 | 1354 | [[package]] 1355 | name = "quinn-proto" 1356 | version = "0.11.10" 1357 | source = "registry+https://github.com/rust-lang/crates.io-index" 1358 | checksum = "b820744eb4dc9b57a3398183639c511b5a26d2ed702cedd3febaa1393caa22cc" 1359 | dependencies = [ 1360 | "bytes", 1361 | "getrandom 0.3.2", 1362 | "rand 0.9.0", 1363 | "ring", 1364 | "rustc-hash", 1365 | "rustls", 1366 | "rustls-pki-types", 1367 | "slab", 1368 | "thiserror 2.0.12", 1369 | "tinyvec", 1370 | "tracing", 1371 | "web-time", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "quinn-udp" 1376 | version = "0.5.11" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "541d0f57c6ec747a90738a52741d3221f7960e8ac2f0ff4b1a63680e033b4ab5" 1379 | dependencies = [ 1380 | "cfg_aliases", 1381 | "libc", 1382 | "once_cell", 1383 | "socket2", 1384 | "tracing", 1385 | "windows-sys 0.59.0", 1386 | ] 1387 | 1388 | [[package]] 1389 | name = "quote" 1390 | version = "1.0.40" 1391 | source = "registry+https://github.com/rust-lang/crates.io-index" 1392 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1393 | dependencies = [ 1394 | "proc-macro2", 1395 | ] 1396 | 1397 | [[package]] 1398 | name = "r-efi" 1399 | version = "5.2.0" 1400 | source = "registry+https://github.com/rust-lang/crates.io-index" 1401 | checksum = "74765f6d916ee2faa39bc8e68e4f3ed8949b48cccdac59983d287a7cb71ce9c5" 1402 | 1403 | [[package]] 1404 | name = "rand" 1405 | version = "0.8.5" 1406 | source = "registry+https://github.com/rust-lang/crates.io-index" 1407 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1408 | dependencies = [ 1409 | "libc", 1410 | "rand_chacha 0.3.1", 1411 | "rand_core 0.6.4", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "rand" 1416 | version = "0.9.0" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "3779b94aeb87e8bd4e834cee3650289ee9e0d5677f976ecdb6d219e5f4f6cd94" 1419 | dependencies = [ 1420 | "rand_chacha 0.9.0", 1421 | "rand_core 0.9.3", 1422 | "zerocopy", 1423 | ] 1424 | 1425 | [[package]] 1426 | name = "rand_chacha" 1427 | version = "0.3.1" 1428 | source = "registry+https://github.com/rust-lang/crates.io-index" 1429 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1430 | dependencies = [ 1431 | "ppv-lite86", 1432 | "rand_core 0.6.4", 1433 | ] 1434 | 1435 | [[package]] 1436 | name = "rand_chacha" 1437 | version = "0.9.0" 1438 | source = "registry+https://github.com/rust-lang/crates.io-index" 1439 | checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" 1440 | dependencies = [ 1441 | "ppv-lite86", 1442 | "rand_core 0.9.3", 1443 | ] 1444 | 1445 | [[package]] 1446 | name = "rand_core" 1447 | version = "0.6.4" 1448 | source = "registry+https://github.com/rust-lang/crates.io-index" 1449 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1450 | dependencies = [ 1451 | "getrandom 0.2.15", 1452 | ] 1453 | 1454 | [[package]] 1455 | name = "rand_core" 1456 | version = "0.9.3" 1457 | source = "registry+https://github.com/rust-lang/crates.io-index" 1458 | checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" 1459 | dependencies = [ 1460 | "getrandom 0.3.2", 1461 | ] 1462 | 1463 | [[package]] 1464 | name = "reqwest" 1465 | version = "0.12.15" 1466 | source = "registry+https://github.com/rust-lang/crates.io-index" 1467 | checksum = "d19c46a6fdd48bc4dab94b6103fccc55d34c67cc0ad04653aad4ea2a07cd7bbb" 1468 | dependencies = [ 1469 | "base64 0.22.1", 1470 | "bytes", 1471 | "futures-core", 1472 | "futures-util", 1473 | "http", 1474 | "http-body", 1475 | "http-body-util", 1476 | "hyper", 1477 | "hyper-rustls", 1478 | "hyper-util", 1479 | "ipnet", 1480 | "js-sys", 1481 | "log", 1482 | "mime", 1483 | "once_cell", 1484 | "percent-encoding", 1485 | "pin-project-lite", 1486 | "quinn", 1487 | "rustls", 1488 | "rustls-native-certs", 1489 | "rustls-pemfile", 1490 | "rustls-pki-types", 1491 | "serde", 1492 | "serde_json", 1493 | "serde_urlencoded", 1494 | "sync_wrapper", 1495 | "tokio", 1496 | "tokio-rustls", 1497 | "tower", 1498 | "tower-service", 1499 | "url", 1500 | "wasm-bindgen", 1501 | "wasm-bindgen-futures", 1502 | "web-sys", 1503 | "webpki-roots", 1504 | "windows-registry", 1505 | ] 1506 | 1507 | [[package]] 1508 | name = "rfc6979" 1509 | version = "0.4.0" 1510 | source = "registry+https://github.com/rust-lang/crates.io-index" 1511 | checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 1512 | dependencies = [ 1513 | "hmac", 1514 | "subtle", 1515 | ] 1516 | 1517 | [[package]] 1518 | name = "ring" 1519 | version = "0.17.14" 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" 1521 | checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" 1522 | dependencies = [ 1523 | "cc", 1524 | "cfg-if", 1525 | "getrandom 0.2.15", 1526 | "libc", 1527 | "untrusted", 1528 | "windows-sys 0.52.0", 1529 | ] 1530 | 1531 | [[package]] 1532 | name = "rsa" 1533 | version = "0.9.8" 1534 | source = "registry+https://github.com/rust-lang/crates.io-index" 1535 | checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" 1536 | dependencies = [ 1537 | "const-oid", 1538 | "digest", 1539 | "num-bigint-dig", 1540 | "num-integer", 1541 | "num-traits", 1542 | "pkcs1", 1543 | "pkcs8", 1544 | "rand_core 0.6.4", 1545 | "signature", 1546 | "spki", 1547 | "subtle", 1548 | "zeroize", 1549 | ] 1550 | 1551 | [[package]] 1552 | name = "rustc-demangle" 1553 | version = "0.1.24" 1554 | source = "registry+https://github.com/rust-lang/crates.io-index" 1555 | checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" 1556 | 1557 | [[package]] 1558 | name = "rustc-hash" 1559 | version = "2.1.1" 1560 | source = "registry+https://github.com/rust-lang/crates.io-index" 1561 | checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" 1562 | 1563 | [[package]] 1564 | name = "rustc_version" 1565 | version = "0.4.1" 1566 | source = "registry+https://github.com/rust-lang/crates.io-index" 1567 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1568 | dependencies = [ 1569 | "semver", 1570 | ] 1571 | 1572 | [[package]] 1573 | name = "rustls" 1574 | version = "0.23.25" 1575 | source = "registry+https://github.com/rust-lang/crates.io-index" 1576 | checksum = "822ee9188ac4ec04a2f0531e55d035fb2de73f18b41a63c70c2712503b6fb13c" 1577 | dependencies = [ 1578 | "once_cell", 1579 | "ring", 1580 | "rustls-pki-types", 1581 | "rustls-webpki", 1582 | "subtle", 1583 | "zeroize", 1584 | ] 1585 | 1586 | [[package]] 1587 | name = "rustls-native-certs" 1588 | version = "0.8.1" 1589 | source = "registry+https://github.com/rust-lang/crates.io-index" 1590 | checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" 1591 | dependencies = [ 1592 | "openssl-probe", 1593 | "rustls-pki-types", 1594 | "schannel", 1595 | "security-framework", 1596 | ] 1597 | 1598 | [[package]] 1599 | name = "rustls-pemfile" 1600 | version = "2.2.0" 1601 | source = "registry+https://github.com/rust-lang/crates.io-index" 1602 | checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" 1603 | dependencies = [ 1604 | "rustls-pki-types", 1605 | ] 1606 | 1607 | [[package]] 1608 | name = "rustls-pki-types" 1609 | version = "1.11.0" 1610 | source = "registry+https://github.com/rust-lang/crates.io-index" 1611 | checksum = "917ce264624a4b4db1c364dcc35bfca9ded014d0a958cd47ad3e960e988ea51c" 1612 | dependencies = [ 1613 | "web-time", 1614 | ] 1615 | 1616 | [[package]] 1617 | name = "rustls-webpki" 1618 | version = "0.103.1" 1619 | source = "registry+https://github.com/rust-lang/crates.io-index" 1620 | checksum = "fef8b8769aaccf73098557a87cd1816b4f9c7c16811c9c77142aa695c16f2c03" 1621 | dependencies = [ 1622 | "ring", 1623 | "rustls-pki-types", 1624 | "untrusted", 1625 | ] 1626 | 1627 | [[package]] 1628 | name = "rustversion" 1629 | version = "1.0.20" 1630 | source = "registry+https://github.com/rust-lang/crates.io-index" 1631 | checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2" 1632 | 1633 | [[package]] 1634 | name = "ryu" 1635 | version = "1.0.20" 1636 | source = "registry+https://github.com/rust-lang/crates.io-index" 1637 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1638 | 1639 | [[package]] 1640 | name = "schannel" 1641 | version = "0.1.27" 1642 | source = "registry+https://github.com/rust-lang/crates.io-index" 1643 | checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" 1644 | dependencies = [ 1645 | "windows-sys 0.59.0", 1646 | ] 1647 | 1648 | [[package]] 1649 | name = "sec1" 1650 | version = "0.7.3" 1651 | source = "registry+https://github.com/rust-lang/crates.io-index" 1652 | checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 1653 | dependencies = [ 1654 | "base16ct", 1655 | "der", 1656 | "generic-array", 1657 | "pkcs8", 1658 | "subtle", 1659 | "zeroize", 1660 | ] 1661 | 1662 | [[package]] 1663 | name = "security-framework" 1664 | version = "3.2.0" 1665 | source = "registry+https://github.com/rust-lang/crates.io-index" 1666 | checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" 1667 | dependencies = [ 1668 | "bitflags", 1669 | "core-foundation", 1670 | "core-foundation-sys", 1671 | "libc", 1672 | "security-framework-sys", 1673 | ] 1674 | 1675 | [[package]] 1676 | name = "security-framework-sys" 1677 | version = "2.14.0" 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" 1679 | checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" 1680 | dependencies = [ 1681 | "core-foundation-sys", 1682 | "libc", 1683 | ] 1684 | 1685 | [[package]] 1686 | name = "semver" 1687 | version = "1.0.26" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 1690 | 1691 | [[package]] 1692 | name = "serde" 1693 | version = "1.0.219" 1694 | source = "registry+https://github.com/rust-lang/crates.io-index" 1695 | checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" 1696 | dependencies = [ 1697 | "serde_derive", 1698 | ] 1699 | 1700 | [[package]] 1701 | name = "serde-value" 1702 | version = "0.7.0" 1703 | source = "registry+https://github.com/rust-lang/crates.io-index" 1704 | checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" 1705 | dependencies = [ 1706 | "ordered-float", 1707 | "serde", 1708 | ] 1709 | 1710 | [[package]] 1711 | name = "serde_derive" 1712 | version = "1.0.219" 1713 | source = "registry+https://github.com/rust-lang/crates.io-index" 1714 | checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" 1715 | dependencies = [ 1716 | "proc-macro2", 1717 | "quote", 1718 | "syn", 1719 | ] 1720 | 1721 | [[package]] 1722 | name = "serde_json" 1723 | version = "1.0.140" 1724 | source = "registry+https://github.com/rust-lang/crates.io-index" 1725 | checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" 1726 | dependencies = [ 1727 | "itoa", 1728 | "memchr", 1729 | "ryu", 1730 | "serde", 1731 | ] 1732 | 1733 | [[package]] 1734 | name = "serde_path_to_error" 1735 | version = "0.1.17" 1736 | source = "registry+https://github.com/rust-lang/crates.io-index" 1737 | checksum = "59fab13f937fa393d08645bf3a84bdfe86e296747b506ada67bb15f10f218b2a" 1738 | dependencies = [ 1739 | "itoa", 1740 | "serde", 1741 | ] 1742 | 1743 | [[package]] 1744 | name = "serde_plain" 1745 | version = "1.0.2" 1746 | source = "registry+https://github.com/rust-lang/crates.io-index" 1747 | checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" 1748 | dependencies = [ 1749 | "serde", 1750 | ] 1751 | 1752 | [[package]] 1753 | name = "serde_urlencoded" 1754 | version = "0.7.1" 1755 | source = "registry+https://github.com/rust-lang/crates.io-index" 1756 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" 1757 | dependencies = [ 1758 | "form_urlencoded", 1759 | "itoa", 1760 | "ryu", 1761 | "serde", 1762 | ] 1763 | 1764 | [[package]] 1765 | name = "serde_with" 1766 | version = "3.12.0" 1767 | source = "registry+https://github.com/rust-lang/crates.io-index" 1768 | checksum = "d6b6f7f2fcb69f747921f79f3926bd1e203fce4fef62c268dd3abfb6d86029aa" 1769 | dependencies = [ 1770 | "base64 0.22.1", 1771 | "chrono", 1772 | "hex", 1773 | "indexmap 1.9.3", 1774 | "indexmap 2.9.0", 1775 | "serde", 1776 | "serde_derive", 1777 | "serde_json", 1778 | "serde_with_macros", 1779 | "time", 1780 | ] 1781 | 1782 | [[package]] 1783 | name = "serde_with_macros" 1784 | version = "3.12.0" 1785 | source = "registry+https://github.com/rust-lang/crates.io-index" 1786 | checksum = "8d00caa5193a3c8362ac2b73be6b9e768aa5a4b2f721d8f4b339600c3cb51f8e" 1787 | dependencies = [ 1788 | "darling", 1789 | "proc-macro2", 1790 | "quote", 1791 | "syn", 1792 | ] 1793 | 1794 | [[package]] 1795 | name = "sha2" 1796 | version = "0.10.8" 1797 | source = "registry+https://github.com/rust-lang/crates.io-index" 1798 | checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" 1799 | dependencies = [ 1800 | "cfg-if", 1801 | "cpufeatures", 1802 | "digest", 1803 | ] 1804 | 1805 | [[package]] 1806 | name = "sharded-slab" 1807 | version = "0.1.7" 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" 1809 | checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" 1810 | dependencies = [ 1811 | "lazy_static", 1812 | ] 1813 | 1814 | [[package]] 1815 | name = "shlex" 1816 | version = "1.3.0" 1817 | source = "registry+https://github.com/rust-lang/crates.io-index" 1818 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1819 | 1820 | [[package]] 1821 | name = "signature" 1822 | version = "2.2.0" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1825 | dependencies = [ 1826 | "digest", 1827 | "rand_core 0.6.4", 1828 | ] 1829 | 1830 | [[package]] 1831 | name = "slab" 1832 | version = "0.4.9" 1833 | source = "registry+https://github.com/rust-lang/crates.io-index" 1834 | checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" 1835 | dependencies = [ 1836 | "autocfg", 1837 | ] 1838 | 1839 | [[package]] 1840 | name = "smallvec" 1841 | version = "1.15.0" 1842 | source = "registry+https://github.com/rust-lang/crates.io-index" 1843 | checksum = "8917285742e9f3e1683f0a9c4e6b57960b7314d0b08d30d1ecd426713ee2eee9" 1844 | 1845 | [[package]] 1846 | name = "socket2" 1847 | version = "0.5.9" 1848 | source = "registry+https://github.com/rust-lang/crates.io-index" 1849 | checksum = "4f5fd57c80058a56cf5c777ab8a126398ece8e442983605d280a44ce79d0edef" 1850 | dependencies = [ 1851 | "libc", 1852 | "windows-sys 0.52.0", 1853 | ] 1854 | 1855 | [[package]] 1856 | name = "spin" 1857 | version = "0.9.8" 1858 | source = "registry+https://github.com/rust-lang/crates.io-index" 1859 | checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" 1860 | 1861 | [[package]] 1862 | name = "spki" 1863 | version = "0.7.3" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 1866 | dependencies = [ 1867 | "base64ct", 1868 | "der", 1869 | ] 1870 | 1871 | [[package]] 1872 | name = "stable_deref_trait" 1873 | version = "1.2.0" 1874 | source = "registry+https://github.com/rust-lang/crates.io-index" 1875 | checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" 1876 | 1877 | [[package]] 1878 | name = "strsim" 1879 | version = "0.11.1" 1880 | source = "registry+https://github.com/rust-lang/crates.io-index" 1881 | checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" 1882 | 1883 | [[package]] 1884 | name = "subtle" 1885 | version = "2.6.1" 1886 | source = "registry+https://github.com/rust-lang/crates.io-index" 1887 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 1888 | 1889 | [[package]] 1890 | name = "syn" 1891 | version = "2.0.100" 1892 | source = "registry+https://github.com/rust-lang/crates.io-index" 1893 | checksum = "b09a44accad81e1ba1cd74a32461ba89dee89095ba17b32f5d03683b1b1fc2a0" 1894 | dependencies = [ 1895 | "proc-macro2", 1896 | "quote", 1897 | "unicode-ident", 1898 | ] 1899 | 1900 | [[package]] 1901 | name = "sync_wrapper" 1902 | version = "1.0.2" 1903 | source = "registry+https://github.com/rust-lang/crates.io-index" 1904 | checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" 1905 | dependencies = [ 1906 | "futures-core", 1907 | ] 1908 | 1909 | [[package]] 1910 | name = "synstructure" 1911 | version = "0.13.1" 1912 | source = "registry+https://github.com/rust-lang/crates.io-index" 1913 | checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" 1914 | dependencies = [ 1915 | "proc-macro2", 1916 | "quote", 1917 | "syn", 1918 | ] 1919 | 1920 | [[package]] 1921 | name = "thiserror" 1922 | version = "1.0.69" 1923 | source = "registry+https://github.com/rust-lang/crates.io-index" 1924 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 1925 | dependencies = [ 1926 | "thiserror-impl 1.0.69", 1927 | ] 1928 | 1929 | [[package]] 1930 | name = "thiserror" 1931 | version = "2.0.12" 1932 | source = "registry+https://github.com/rust-lang/crates.io-index" 1933 | checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" 1934 | dependencies = [ 1935 | "thiserror-impl 2.0.12", 1936 | ] 1937 | 1938 | [[package]] 1939 | name = "thiserror-impl" 1940 | version = "1.0.69" 1941 | source = "registry+https://github.com/rust-lang/crates.io-index" 1942 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 1943 | dependencies = [ 1944 | "proc-macro2", 1945 | "quote", 1946 | "syn", 1947 | ] 1948 | 1949 | [[package]] 1950 | name = "thiserror-impl" 1951 | version = "2.0.12" 1952 | source = "registry+https://github.com/rust-lang/crates.io-index" 1953 | checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" 1954 | dependencies = [ 1955 | "proc-macro2", 1956 | "quote", 1957 | "syn", 1958 | ] 1959 | 1960 | [[package]] 1961 | name = "thread_local" 1962 | version = "1.1.8" 1963 | source = "registry+https://github.com/rust-lang/crates.io-index" 1964 | checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" 1965 | dependencies = [ 1966 | "cfg-if", 1967 | "once_cell", 1968 | ] 1969 | 1970 | [[package]] 1971 | name = "time" 1972 | version = "0.3.41" 1973 | source = "registry+https://github.com/rust-lang/crates.io-index" 1974 | checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" 1975 | dependencies = [ 1976 | "deranged", 1977 | "itoa", 1978 | "num-conv", 1979 | "powerfmt", 1980 | "serde", 1981 | "time-core", 1982 | "time-macros", 1983 | ] 1984 | 1985 | [[package]] 1986 | name = "time-core" 1987 | version = "0.1.4" 1988 | source = "registry+https://github.com/rust-lang/crates.io-index" 1989 | checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" 1990 | 1991 | [[package]] 1992 | name = "time-macros" 1993 | version = "0.2.22" 1994 | source = "registry+https://github.com/rust-lang/crates.io-index" 1995 | checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" 1996 | dependencies = [ 1997 | "num-conv", 1998 | "time-core", 1999 | ] 2000 | 2001 | [[package]] 2002 | name = "tinystr" 2003 | version = "0.7.6" 2004 | source = "registry+https://github.com/rust-lang/crates.io-index" 2005 | checksum = "9117f5d4db391c1cf6927e7bea3db74b9a1c1add8f7eda9ffd5364f40f57b82f" 2006 | dependencies = [ 2007 | "displaydoc", 2008 | "zerovec", 2009 | ] 2010 | 2011 | [[package]] 2012 | name = "tinyvec" 2013 | version = "1.9.0" 2014 | source = "registry+https://github.com/rust-lang/crates.io-index" 2015 | checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" 2016 | dependencies = [ 2017 | "tinyvec_macros", 2018 | ] 2019 | 2020 | [[package]] 2021 | name = "tinyvec_macros" 2022 | version = "0.1.1" 2023 | source = "registry+https://github.com/rust-lang/crates.io-index" 2024 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 2025 | 2026 | [[package]] 2027 | name = "tokio" 2028 | version = "1.44.2" 2029 | source = "registry+https://github.com/rust-lang/crates.io-index" 2030 | checksum = "e6b88822cbe49de4185e3a4cbf8321dd487cf5fe0c5c65695fef6346371e9c48" 2031 | dependencies = [ 2032 | "backtrace", 2033 | "bytes", 2034 | "libc", 2035 | "mio", 2036 | "pin-project-lite", 2037 | "socket2", 2038 | "tokio-macros", 2039 | "windows-sys 0.52.0", 2040 | ] 2041 | 2042 | [[package]] 2043 | name = "tokio-macros" 2044 | version = "2.5.0" 2045 | source = "registry+https://github.com/rust-lang/crates.io-index" 2046 | checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" 2047 | dependencies = [ 2048 | "proc-macro2", 2049 | "quote", 2050 | "syn", 2051 | ] 2052 | 2053 | [[package]] 2054 | name = "tokio-rustls" 2055 | version = "0.26.2" 2056 | source = "registry+https://github.com/rust-lang/crates.io-index" 2057 | checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" 2058 | dependencies = [ 2059 | "rustls", 2060 | "tokio", 2061 | ] 2062 | 2063 | [[package]] 2064 | name = "tower" 2065 | version = "0.5.2" 2066 | source = "registry+https://github.com/rust-lang/crates.io-index" 2067 | checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" 2068 | dependencies = [ 2069 | "futures-core", 2070 | "futures-util", 2071 | "pin-project-lite", 2072 | "sync_wrapper", 2073 | "tokio", 2074 | "tower-layer", 2075 | "tower-service", 2076 | ] 2077 | 2078 | [[package]] 2079 | name = "tower-layer" 2080 | version = "0.3.3" 2081 | source = "registry+https://github.com/rust-lang/crates.io-index" 2082 | checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" 2083 | 2084 | [[package]] 2085 | name = "tower-service" 2086 | version = "0.3.3" 2087 | source = "registry+https://github.com/rust-lang/crates.io-index" 2088 | checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" 2089 | 2090 | [[package]] 2091 | name = "tracing" 2092 | version = "0.1.41" 2093 | source = "registry+https://github.com/rust-lang/crates.io-index" 2094 | checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" 2095 | dependencies = [ 2096 | "pin-project-lite", 2097 | "tracing-core", 2098 | ] 2099 | 2100 | [[package]] 2101 | name = "tracing-core" 2102 | version = "0.1.33" 2103 | source = "registry+https://github.com/rust-lang/crates.io-index" 2104 | checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" 2105 | dependencies = [ 2106 | "once_cell", 2107 | ] 2108 | 2109 | [[package]] 2110 | name = "tracing-subscriber" 2111 | version = "0.3.19" 2112 | source = "registry+https://github.com/rust-lang/crates.io-index" 2113 | checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" 2114 | dependencies = [ 2115 | "nu-ansi-term", 2116 | "sharded-slab", 2117 | "thread_local", 2118 | "tracing-core", 2119 | ] 2120 | 2121 | [[package]] 2122 | name = "try-lock" 2123 | version = "0.2.5" 2124 | source = "registry+https://github.com/rust-lang/crates.io-index" 2125 | checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" 2126 | 2127 | [[package]] 2128 | name = "typenum" 2129 | version = "1.18.0" 2130 | source = "registry+https://github.com/rust-lang/crates.io-index" 2131 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 2132 | 2133 | [[package]] 2134 | name = "unicode-ident" 2135 | version = "1.0.18" 2136 | source = "registry+https://github.com/rust-lang/crates.io-index" 2137 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 2138 | 2139 | [[package]] 2140 | name = "untrusted" 2141 | version = "0.9.0" 2142 | source = "registry+https://github.com/rust-lang/crates.io-index" 2143 | checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" 2144 | 2145 | [[package]] 2146 | name = "url" 2147 | version = "2.5.4" 2148 | source = "registry+https://github.com/rust-lang/crates.io-index" 2149 | checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" 2150 | dependencies = [ 2151 | "form_urlencoded", 2152 | "idna", 2153 | "percent-encoding", 2154 | "serde", 2155 | ] 2156 | 2157 | [[package]] 2158 | name = "utf16_iter" 2159 | version = "1.0.5" 2160 | source = "registry+https://github.com/rust-lang/crates.io-index" 2161 | checksum = "c8232dd3cdaed5356e0f716d285e4b40b932ac434100fe9b7e0e8e935b9e6246" 2162 | 2163 | [[package]] 2164 | name = "utf8_iter" 2165 | version = "1.0.4" 2166 | source = "registry+https://github.com/rust-lang/crates.io-index" 2167 | checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" 2168 | 2169 | [[package]] 2170 | name = "uuid" 2171 | version = "1.16.0" 2172 | source = "registry+https://github.com/rust-lang/crates.io-index" 2173 | checksum = "458f7a779bf54acc9f347480ac654f68407d3aab21269a6e3c9f922acd9e2da9" 2174 | dependencies = [ 2175 | "getrandom 0.3.2", 2176 | ] 2177 | 2178 | [[package]] 2179 | name = "version_check" 2180 | version = "0.9.5" 2181 | source = "registry+https://github.com/rust-lang/crates.io-index" 2182 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 2183 | 2184 | [[package]] 2185 | name = "want" 2186 | version = "0.3.1" 2187 | source = "registry+https://github.com/rust-lang/crates.io-index" 2188 | checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" 2189 | dependencies = [ 2190 | "try-lock", 2191 | ] 2192 | 2193 | [[package]] 2194 | name = "wasi" 2195 | version = "0.11.0+wasi-snapshot-preview1" 2196 | source = "registry+https://github.com/rust-lang/crates.io-index" 2197 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" 2198 | 2199 | [[package]] 2200 | name = "wasi" 2201 | version = "0.14.2+wasi-0.2.4" 2202 | source = "registry+https://github.com/rust-lang/crates.io-index" 2203 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 2204 | dependencies = [ 2205 | "wit-bindgen-rt", 2206 | ] 2207 | 2208 | [[package]] 2209 | name = "wasm-bindgen" 2210 | version = "0.2.100" 2211 | source = "registry+https://github.com/rust-lang/crates.io-index" 2212 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 2213 | dependencies = [ 2214 | "cfg-if", 2215 | "once_cell", 2216 | "rustversion", 2217 | "wasm-bindgen-macro", 2218 | ] 2219 | 2220 | [[package]] 2221 | name = "wasm-bindgen-backend" 2222 | version = "0.2.100" 2223 | source = "registry+https://github.com/rust-lang/crates.io-index" 2224 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 2225 | dependencies = [ 2226 | "bumpalo", 2227 | "log", 2228 | "proc-macro2", 2229 | "quote", 2230 | "syn", 2231 | "wasm-bindgen-shared", 2232 | ] 2233 | 2234 | [[package]] 2235 | name = "wasm-bindgen-futures" 2236 | version = "0.4.50" 2237 | source = "registry+https://github.com/rust-lang/crates.io-index" 2238 | checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" 2239 | dependencies = [ 2240 | "cfg-if", 2241 | "js-sys", 2242 | "once_cell", 2243 | "wasm-bindgen", 2244 | "web-sys", 2245 | ] 2246 | 2247 | [[package]] 2248 | name = "wasm-bindgen-macro" 2249 | version = "0.2.100" 2250 | source = "registry+https://github.com/rust-lang/crates.io-index" 2251 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 2252 | dependencies = [ 2253 | "quote", 2254 | "wasm-bindgen-macro-support", 2255 | ] 2256 | 2257 | [[package]] 2258 | name = "wasm-bindgen-macro-support" 2259 | version = "0.2.100" 2260 | source = "registry+https://github.com/rust-lang/crates.io-index" 2261 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 2262 | dependencies = [ 2263 | "proc-macro2", 2264 | "quote", 2265 | "syn", 2266 | "wasm-bindgen-backend", 2267 | "wasm-bindgen-shared", 2268 | ] 2269 | 2270 | [[package]] 2271 | name = "wasm-bindgen-shared" 2272 | version = "0.2.100" 2273 | source = "registry+https://github.com/rust-lang/crates.io-index" 2274 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 2275 | dependencies = [ 2276 | "unicode-ident", 2277 | ] 2278 | 2279 | [[package]] 2280 | name = "web-sys" 2281 | version = "0.3.77" 2282 | source = "registry+https://github.com/rust-lang/crates.io-index" 2283 | checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" 2284 | dependencies = [ 2285 | "js-sys", 2286 | "wasm-bindgen", 2287 | ] 2288 | 2289 | [[package]] 2290 | name = "web-time" 2291 | version = "1.1.0" 2292 | source = "registry+https://github.com/rust-lang/crates.io-index" 2293 | checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" 2294 | dependencies = [ 2295 | "js-sys", 2296 | "wasm-bindgen", 2297 | ] 2298 | 2299 | [[package]] 2300 | name = "webpki-roots" 2301 | version = "0.26.8" 2302 | source = "registry+https://github.com/rust-lang/crates.io-index" 2303 | checksum = "2210b291f7ea53617fbafcc4939f10914214ec15aace5ba62293a668f322c5c9" 2304 | dependencies = [ 2305 | "rustls-pki-types", 2306 | ] 2307 | 2308 | [[package]] 2309 | name = "winapi" 2310 | version = "0.3.9" 2311 | source = "registry+https://github.com/rust-lang/crates.io-index" 2312 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 2313 | dependencies = [ 2314 | "winapi-i686-pc-windows-gnu", 2315 | "winapi-x86_64-pc-windows-gnu", 2316 | ] 2317 | 2318 | [[package]] 2319 | name = "winapi-i686-pc-windows-gnu" 2320 | version = "0.4.0" 2321 | source = "registry+https://github.com/rust-lang/crates.io-index" 2322 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 2323 | 2324 | [[package]] 2325 | name = "winapi-x86_64-pc-windows-gnu" 2326 | version = "0.4.0" 2327 | source = "registry+https://github.com/rust-lang/crates.io-index" 2328 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 2329 | 2330 | [[package]] 2331 | name = "windows-core" 2332 | version = "0.61.0" 2333 | source = "registry+https://github.com/rust-lang/crates.io-index" 2334 | checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980" 2335 | dependencies = [ 2336 | "windows-implement", 2337 | "windows-interface", 2338 | "windows-link", 2339 | "windows-result", 2340 | "windows-strings 0.4.0", 2341 | ] 2342 | 2343 | [[package]] 2344 | name = "windows-implement" 2345 | version = "0.60.0" 2346 | source = "registry+https://github.com/rust-lang/crates.io-index" 2347 | checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" 2348 | dependencies = [ 2349 | "proc-macro2", 2350 | "quote", 2351 | "syn", 2352 | ] 2353 | 2354 | [[package]] 2355 | name = "windows-interface" 2356 | version = "0.59.1" 2357 | source = "registry+https://github.com/rust-lang/crates.io-index" 2358 | checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" 2359 | dependencies = [ 2360 | "proc-macro2", 2361 | "quote", 2362 | "syn", 2363 | ] 2364 | 2365 | [[package]] 2366 | name = "windows-link" 2367 | version = "0.1.1" 2368 | source = "registry+https://github.com/rust-lang/crates.io-index" 2369 | checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38" 2370 | 2371 | [[package]] 2372 | name = "windows-registry" 2373 | version = "0.4.0" 2374 | source = "registry+https://github.com/rust-lang/crates.io-index" 2375 | checksum = "4286ad90ddb45071efd1a66dfa43eb02dd0dfbae1545ad6cc3c51cf34d7e8ba3" 2376 | dependencies = [ 2377 | "windows-result", 2378 | "windows-strings 0.3.1", 2379 | "windows-targets 0.53.0", 2380 | ] 2381 | 2382 | [[package]] 2383 | name = "windows-result" 2384 | version = "0.3.2" 2385 | source = "registry+https://github.com/rust-lang/crates.io-index" 2386 | checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252" 2387 | dependencies = [ 2388 | "windows-link", 2389 | ] 2390 | 2391 | [[package]] 2392 | name = "windows-strings" 2393 | version = "0.3.1" 2394 | source = "registry+https://github.com/rust-lang/crates.io-index" 2395 | checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319" 2396 | dependencies = [ 2397 | "windows-link", 2398 | ] 2399 | 2400 | [[package]] 2401 | name = "windows-strings" 2402 | version = "0.4.0" 2403 | source = "registry+https://github.com/rust-lang/crates.io-index" 2404 | checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97" 2405 | dependencies = [ 2406 | "windows-link", 2407 | ] 2408 | 2409 | [[package]] 2410 | name = "windows-sys" 2411 | version = "0.52.0" 2412 | source = "registry+https://github.com/rust-lang/crates.io-index" 2413 | checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" 2414 | dependencies = [ 2415 | "windows-targets 0.52.6", 2416 | ] 2417 | 2418 | [[package]] 2419 | name = "windows-sys" 2420 | version = "0.59.0" 2421 | source = "registry+https://github.com/rust-lang/crates.io-index" 2422 | checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" 2423 | dependencies = [ 2424 | "windows-targets 0.52.6", 2425 | ] 2426 | 2427 | [[package]] 2428 | name = "windows-targets" 2429 | version = "0.52.6" 2430 | source = "registry+https://github.com/rust-lang/crates.io-index" 2431 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 2432 | dependencies = [ 2433 | "windows_aarch64_gnullvm 0.52.6", 2434 | "windows_aarch64_msvc 0.52.6", 2435 | "windows_i686_gnu 0.52.6", 2436 | "windows_i686_gnullvm 0.52.6", 2437 | "windows_i686_msvc 0.52.6", 2438 | "windows_x86_64_gnu 0.52.6", 2439 | "windows_x86_64_gnullvm 0.52.6", 2440 | "windows_x86_64_msvc 0.52.6", 2441 | ] 2442 | 2443 | [[package]] 2444 | name = "windows-targets" 2445 | version = "0.53.0" 2446 | source = "registry+https://github.com/rust-lang/crates.io-index" 2447 | checksum = "b1e4c7e8ceaaf9cb7d7507c974735728ab453b67ef8f18febdd7c11fe59dca8b" 2448 | dependencies = [ 2449 | "windows_aarch64_gnullvm 0.53.0", 2450 | "windows_aarch64_msvc 0.53.0", 2451 | "windows_i686_gnu 0.53.0", 2452 | "windows_i686_gnullvm 0.53.0", 2453 | "windows_i686_msvc 0.53.0", 2454 | "windows_x86_64_gnu 0.53.0", 2455 | "windows_x86_64_gnullvm 0.53.0", 2456 | "windows_x86_64_msvc 0.53.0", 2457 | ] 2458 | 2459 | [[package]] 2460 | name = "windows_aarch64_gnullvm" 2461 | version = "0.52.6" 2462 | source = "registry+https://github.com/rust-lang/crates.io-index" 2463 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 2464 | 2465 | [[package]] 2466 | name = "windows_aarch64_gnullvm" 2467 | version = "0.53.0" 2468 | source = "registry+https://github.com/rust-lang/crates.io-index" 2469 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 2470 | 2471 | [[package]] 2472 | name = "windows_aarch64_msvc" 2473 | version = "0.52.6" 2474 | source = "registry+https://github.com/rust-lang/crates.io-index" 2475 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 2476 | 2477 | [[package]] 2478 | name = "windows_aarch64_msvc" 2479 | version = "0.53.0" 2480 | source = "registry+https://github.com/rust-lang/crates.io-index" 2481 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 2482 | 2483 | [[package]] 2484 | name = "windows_i686_gnu" 2485 | version = "0.52.6" 2486 | source = "registry+https://github.com/rust-lang/crates.io-index" 2487 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 2488 | 2489 | [[package]] 2490 | name = "windows_i686_gnu" 2491 | version = "0.53.0" 2492 | source = "registry+https://github.com/rust-lang/crates.io-index" 2493 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 2494 | 2495 | [[package]] 2496 | name = "windows_i686_gnullvm" 2497 | version = "0.52.6" 2498 | source = "registry+https://github.com/rust-lang/crates.io-index" 2499 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 2500 | 2501 | [[package]] 2502 | name = "windows_i686_gnullvm" 2503 | version = "0.53.0" 2504 | source = "registry+https://github.com/rust-lang/crates.io-index" 2505 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 2506 | 2507 | [[package]] 2508 | name = "windows_i686_msvc" 2509 | version = "0.52.6" 2510 | source = "registry+https://github.com/rust-lang/crates.io-index" 2511 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 2512 | 2513 | [[package]] 2514 | name = "windows_i686_msvc" 2515 | version = "0.53.0" 2516 | source = "registry+https://github.com/rust-lang/crates.io-index" 2517 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 2518 | 2519 | [[package]] 2520 | name = "windows_x86_64_gnu" 2521 | version = "0.52.6" 2522 | source = "registry+https://github.com/rust-lang/crates.io-index" 2523 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 2524 | 2525 | [[package]] 2526 | name = "windows_x86_64_gnu" 2527 | version = "0.53.0" 2528 | source = "registry+https://github.com/rust-lang/crates.io-index" 2529 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 2530 | 2531 | [[package]] 2532 | name = "windows_x86_64_gnullvm" 2533 | version = "0.52.6" 2534 | source = "registry+https://github.com/rust-lang/crates.io-index" 2535 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 2536 | 2537 | [[package]] 2538 | name = "windows_x86_64_gnullvm" 2539 | version = "0.53.0" 2540 | source = "registry+https://github.com/rust-lang/crates.io-index" 2541 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 2542 | 2543 | [[package]] 2544 | name = "windows_x86_64_msvc" 2545 | version = "0.52.6" 2546 | source = "registry+https://github.com/rust-lang/crates.io-index" 2547 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 2548 | 2549 | [[package]] 2550 | name = "windows_x86_64_msvc" 2551 | version = "0.53.0" 2552 | source = "registry+https://github.com/rust-lang/crates.io-index" 2553 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 2554 | 2555 | [[package]] 2556 | name = "winnow" 2557 | version = "0.7.4" 2558 | source = "registry+https://github.com/rust-lang/crates.io-index" 2559 | checksum = "0e97b544156e9bebe1a0ffbc03484fc1ffe3100cbce3ffb17eac35f7cdd7ab36" 2560 | dependencies = [ 2561 | "memchr", 2562 | ] 2563 | 2564 | [[package]] 2565 | name = "wit-bindgen-rt" 2566 | version = "0.39.0" 2567 | source = "registry+https://github.com/rust-lang/crates.io-index" 2568 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 2569 | dependencies = [ 2570 | "bitflags", 2571 | ] 2572 | 2573 | [[package]] 2574 | name = "write16" 2575 | version = "1.0.0" 2576 | source = "registry+https://github.com/rust-lang/crates.io-index" 2577 | checksum = "d1890f4022759daae28ed4fe62859b1236caebfc61ede2f63ed4e695f3f6d936" 2578 | 2579 | [[package]] 2580 | name = "writeable" 2581 | version = "0.5.5" 2582 | source = "registry+https://github.com/rust-lang/crates.io-index" 2583 | checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" 2584 | 2585 | [[package]] 2586 | name = "yoke" 2587 | version = "0.7.5" 2588 | source = "registry+https://github.com/rust-lang/crates.io-index" 2589 | checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" 2590 | dependencies = [ 2591 | "serde", 2592 | "stable_deref_trait", 2593 | "yoke-derive", 2594 | "zerofrom", 2595 | ] 2596 | 2597 | [[package]] 2598 | name = "yoke-derive" 2599 | version = "0.7.5" 2600 | source = "registry+https://github.com/rust-lang/crates.io-index" 2601 | checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" 2602 | dependencies = [ 2603 | "proc-macro2", 2604 | "quote", 2605 | "syn", 2606 | "synstructure", 2607 | ] 2608 | 2609 | [[package]] 2610 | name = "zerocopy" 2611 | version = "0.8.24" 2612 | source = "registry+https://github.com/rust-lang/crates.io-index" 2613 | checksum = "2586fea28e186957ef732a5f8b3be2da217d65c5969d4b1e17f973ebbe876879" 2614 | dependencies = [ 2615 | "zerocopy-derive", 2616 | ] 2617 | 2618 | [[package]] 2619 | name = "zerocopy-derive" 2620 | version = "0.8.24" 2621 | source = "registry+https://github.com/rust-lang/crates.io-index" 2622 | checksum = "a996a8f63c5c4448cd959ac1bab0aaa3306ccfd060472f85943ee0750f0169be" 2623 | dependencies = [ 2624 | "proc-macro2", 2625 | "quote", 2626 | "syn", 2627 | ] 2628 | 2629 | [[package]] 2630 | name = "zerofrom" 2631 | version = "0.1.6" 2632 | source = "registry+https://github.com/rust-lang/crates.io-index" 2633 | checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" 2634 | dependencies = [ 2635 | "zerofrom-derive", 2636 | ] 2637 | 2638 | [[package]] 2639 | name = "zerofrom-derive" 2640 | version = "0.1.6" 2641 | source = "registry+https://github.com/rust-lang/crates.io-index" 2642 | checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" 2643 | dependencies = [ 2644 | "proc-macro2", 2645 | "quote", 2646 | "syn", 2647 | "synstructure", 2648 | ] 2649 | 2650 | [[package]] 2651 | name = "zeroize" 2652 | version = "1.8.1" 2653 | source = "registry+https://github.com/rust-lang/crates.io-index" 2654 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 2655 | 2656 | [[package]] 2657 | name = "zerovec" 2658 | version = "0.10.4" 2659 | source = "registry+https://github.com/rust-lang/crates.io-index" 2660 | checksum = "aa2b893d79df23bfb12d5461018d408ea19dfafe76c2c7ef6d4eba614f8ff079" 2661 | dependencies = [ 2662 | "yoke", 2663 | "zerofrom", 2664 | "zerovec-derive", 2665 | ] 2666 | 2667 | [[package]] 2668 | name = "zerovec-derive" 2669 | version = "0.10.3" 2670 | source = "registry+https://github.com/rust-lang/crates.io-index" 2671 | checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" 2672 | dependencies = [ 2673 | "proc-macro2", 2674 | "quote", 2675 | "syn", 2676 | ] 2677 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "jitsi-openid" 3 | version = "2.0.18" 4 | edition = "2021" 5 | 6 | [dependencies] 7 | reqwest = { version = "0.12", default-features = false, features = ["rustls-tls", "rustls-tls-native-roots"] } 8 | tokio = { version = "1.44", features = ["macros", "rt-multi-thread", "sync"], default-features = false } 9 | openidconnect = { version = "4.0", features = ["reqwest", "rustls-tls"], default-features = false } 10 | tracing-subscriber = { version = "0.3", features = ["fmt", "ansi"], default-features = false } 11 | axum = { version = "0.8", features = ["tokio", "http1", "query"], default-features = false } 12 | axum-extra = { version = "0.10", features = ["cookie"], default-features = false } 13 | anyhow = { version = "1.0", features = ["std"], default-features = false } 14 | uuid = { version = "1.16", features = ["v4"], default-features = false } 15 | jsonwebtoken = { version = "9.3", default-features = false } 16 | tracing = { version = "0.1", default-features = false } 17 | config = { version = "0.15", default-features = false } 18 | serde = { version = "1.0", default-features = false } 19 | time = { version = "0.3", default-features = false } 20 | url = { version = "2.5", default-features = false } 21 | 22 | 23 | [profile.release] 24 | lto = true 25 | codegen-units = 1 26 | panic = "abort" 27 | strip = true 28 | 29 | # by overriding our dependencies' compilation settings, we can further optimize for size 30 | # https://docs.rust-embedded.org/book/unsorted/speed-vs-size.html#optimizing-dependencies 31 | [profile.release.package."*"] 32 | codegen-units = 1 33 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM rust:slim-bookworm AS builder 2 | 3 | RUN update-ca-certificates 4 | 5 | ENV USER=jitsi-openid 6 | ENV UID=10001 7 | 8 | RUN adduser \ 9 | --disabled-password \ 10 | --gecos "" \ 11 | --home "/nonexistent" \ 12 | --shell "/sbin/nologin" \ 13 | --no-create-home \ 14 | --uid "${UID}" \ 15 | "${USER}" 16 | 17 | RUN apt-get update && apt-get install -y --no-install-recommends \ 18 | pkg-config \ 19 | libssl-dev \ 20 | && rm -rf /var/lib/apt/lists/* 21 | 22 | RUN cargo new --bin jitsi-openid 23 | 24 | WORKDIR /jitsi-openid 25 | 26 | COPY ./Cargo.lock ./Cargo.lock 27 | COPY ./Cargo.toml ./Cargo.toml 28 | 29 | RUN cargo build --release \ 30 | && rm src/*.rs target/release/deps/jitsi_openid* 31 | 32 | COPY ./src ./src 33 | RUN cargo build --release 34 | 35 | FROM debian:bookworm-slim 36 | 37 | ENV LISTEN_ADDR=0.0.0.0:3000 38 | EXPOSE 3000 39 | 40 | COPY --from=builder /etc/passwd /etc/passwd 41 | COPY --from=builder /etc/group /etc/group 42 | 43 | RUN apt-get update && apt-get install -y --no-install-recommends \ 44 | libssl3 \ 45 | ca-certificates \ 46 | && rm -rf /var/lib/apt/lists/* 47 | 48 | WORKDIR /jitsi-openid 49 | 50 | COPY --from=builder /jitsi-openid/target/release/jitsi-openid ./jitsi-openid 51 | 52 | USER jitsi-openid:jitsi-openid 53 | 54 | CMD ["/jitsi-openid/jitsi-openid"] 55 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU AFFERO GENERAL PUBLIC LICENSE 2 | Version 3, 19 November 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | Preamble 9 | 10 | The GNU Affero General Public License is a free, copyleft license for 11 | software and other kinds of works, specifically designed to ensure 12 | cooperation with the community in the case of network server software. 13 | 14 | The licenses for most software and other practical works are designed 15 | to take away your freedom to share and change the works. By contrast, 16 | our General Public Licenses are intended to guarantee your freedom to 17 | share and change all versions of a program--to make sure it remains free 18 | software for all its users. 19 | 20 | When we speak of free software, we are referring to freedom, not 21 | price. Our General Public Licenses are designed to make sure that you 22 | have the freedom to distribute copies of free software (and charge for 23 | them if you wish), that you receive source code or can get it if you 24 | want it, that you can change the software or use pieces of it in new 25 | free programs, and that you know you can do these things. 26 | 27 | Developers that use our General Public Licenses protect your rights 28 | with two steps: (1) assert copyright on the software, and (2) offer 29 | you this License which gives you legal permission to copy, distribute 30 | and/or modify the software. 31 | 32 | A secondary benefit of defending all users' freedom is that 33 | improvements made in alternate versions of the program, if they 34 | receive widespread use, become available for other developers to 35 | incorporate. Many developers of free software are heartened and 36 | encouraged by the resulting cooperation. However, in the case of 37 | software used on network servers, this result may fail to come about. 38 | The GNU General Public License permits making a modified version and 39 | letting the public access it on a server without ever releasing its 40 | source code to the public. 41 | 42 | The GNU Affero General Public License is designed specifically to 43 | ensure that, in such cases, the modified source code becomes available 44 | to the community. It requires the operator of a network server to 45 | provide the source code of the modified version running there to the 46 | users of that server. Therefore, public use of a modified version, on 47 | a publicly accessible server, gives the public access to the source 48 | code of the modified version. 49 | 50 | An older license, called the Affero General Public License and 51 | published by Affero, was designed to accomplish similar goals. This is 52 | a different license, not a version of the Affero GPL, but Affero has 53 | released a new version of the Affero GPL which permits relicensing under 54 | this license. 55 | 56 | The precise terms and conditions for copying, distribution and 57 | modification follow. 58 | 59 | TERMS AND CONDITIONS 60 | 61 | 0. Definitions. 62 | 63 | "This License" refers to version 3 of the GNU Affero General Public License. 64 | 65 | "Copyright" also means copyright-like laws that apply to other kinds of 66 | works, such as semiconductor masks. 67 | 68 | "The Program" refers to any copyrightable work licensed under this 69 | License. Each licensee is addressed as "you". "Licensees" and 70 | "recipients" may be individuals or organizations. 71 | 72 | To "modify" a work means to copy from or adapt all or part of the work 73 | in a fashion requiring copyright permission, other than the making of an 74 | exact copy. The resulting work is called a "modified version" of the 75 | earlier work or a work "based on" the earlier work. 76 | 77 | A "covered work" means either the unmodified Program or a work based 78 | on the Program. 79 | 80 | To "propagate" a work means to do anything with it that, without 81 | permission, would make you directly or secondarily liable for 82 | infringement under applicable copyright law, except executing it on a 83 | computer or modifying a private copy. Propagation includes copying, 84 | distribution (with or without modification), making available to the 85 | public, and in some countries other activities as well. 86 | 87 | To "convey" a work means any kind of propagation that enables other 88 | parties to make or receive copies. Mere interaction with a user through 89 | a computer network, with no transfer of a copy, is not conveying. 90 | 91 | An interactive user interface displays "Appropriate Legal Notices" 92 | to the extent that it includes a convenient and prominently visible 93 | feature that (1) displays an appropriate copyright notice, and (2) 94 | tells the user that there is no warranty for the work (except to the 95 | extent that warranties are provided), that licensees may convey the 96 | work under this License, and how to view a copy of this License. If 97 | the interface presents a list of user commands or options, such as a 98 | menu, a prominent item in the list meets this criterion. 99 | 100 | 1. Source Code. 101 | 102 | The "source code" for a work means the preferred form of the work 103 | for making modifications to it. "Object code" means any non-source 104 | form of a work. 105 | 106 | A "Standard Interface" means an interface that either is an official 107 | standard defined by a recognized standards body, or, in the case of 108 | interfaces specified for a particular programming language, one that 109 | is widely used among developers working in that language. 110 | 111 | The "System Libraries" of an executable work include anything, other 112 | than the work as a whole, that (a) is included in the normal form of 113 | packaging a Major Component, but which is not part of that Major 114 | Component, and (b) serves only to enable use of the work with that 115 | Major Component, or to implement a Standard Interface for which an 116 | implementation is available to the public in source code form. A 117 | "Major Component", in this context, means a major essential component 118 | (kernel, window system, and so on) of the specific operating system 119 | (if any) on which the executable work runs, or a compiler used to 120 | produce the work, or an object code interpreter used to run it. 121 | 122 | The "Corresponding Source" for a work in object code form means all 123 | the source code needed to generate, install, and (for an executable 124 | work) run the object code and to modify the work, including scripts to 125 | control those activities. However, it does not include the work's 126 | System Libraries, or general-purpose tools or generally available free 127 | programs which are used unmodified in performing those activities but 128 | which are not part of the work. For example, Corresponding Source 129 | includes interface definition files associated with source files for 130 | the work, and the source code for shared libraries and dynamically 131 | linked subprograms that the work is specifically designed to require, 132 | such as by intimate data communication or control flow between those 133 | subprograms and other parts of the work. 134 | 135 | The Corresponding Source need not include anything that users 136 | can regenerate automatically from other parts of the Corresponding 137 | Source. 138 | 139 | The Corresponding Source for a work in source code form is that 140 | same work. 141 | 142 | 2. Basic Permissions. 143 | 144 | All rights granted under this License are granted for the term of 145 | copyright on the Program, and are irrevocable provided the stated 146 | conditions are met. This License explicitly affirms your unlimited 147 | permission to run the unmodified Program. The output from running a 148 | covered work is covered by this License only if the output, given its 149 | content, constitutes a covered work. This License acknowledges your 150 | rights of fair use or other equivalent, as provided by copyright law. 151 | 152 | You may make, run and propagate covered works that you do not 153 | convey, without conditions so long as your license otherwise remains 154 | in force. You may convey covered works to others for the sole purpose 155 | of having them make modifications exclusively for you, or provide you 156 | with facilities for running those works, provided that you comply with 157 | the terms of this License in conveying all material for which you do 158 | not control copyright. Those thus making or running the covered works 159 | for you must do so exclusively on your behalf, under your direction 160 | and control, on terms that prohibit them from making any copies of 161 | your copyrighted material outside their relationship with you. 162 | 163 | Conveying under any other circumstances is permitted solely under 164 | the conditions stated below. Sublicensing is not allowed; section 10 165 | makes it unnecessary. 166 | 167 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law. 168 | 169 | No covered work shall be deemed part of an effective technological 170 | measure under any applicable law fulfilling obligations under article 171 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or 172 | similar laws prohibiting or restricting circumvention of such 173 | measures. 174 | 175 | When you convey a covered work, you waive any legal power to forbid 176 | circumvention of technological measures to the extent such circumvention 177 | is effected by exercising rights under this License with respect to 178 | the covered work, and you disclaim any intention to limit operation or 179 | modification of the work as a means of enforcing, against the work's 180 | users, your or third parties' legal rights to forbid circumvention of 181 | technological measures. 182 | 183 | 4. Conveying Verbatim Copies. 184 | 185 | You may convey verbatim copies of the Program's source code as you 186 | receive it, in any medium, provided that you conspicuously and 187 | appropriately publish on each copy an appropriate copyright notice; 188 | keep intact all notices stating that this License and any 189 | non-permissive terms added in accord with section 7 apply to the code; 190 | keep intact all notices of the absence of any warranty; and give all 191 | recipients a copy of this License along with the Program. 192 | 193 | You may charge any price or no price for each copy that you convey, 194 | and you may offer support or warranty protection for a fee. 195 | 196 | 5. Conveying Modified Source Versions. 197 | 198 | You may convey a work based on the Program, or the modifications to 199 | produce it from the Program, in the form of source code under the 200 | terms of section 4, provided that you also meet all of these conditions: 201 | 202 | a) The work must carry prominent notices stating that you modified 203 | it, and giving a relevant date. 204 | 205 | b) The work must carry prominent notices stating that it is 206 | released under this License and any conditions added under section 207 | 7. This requirement modifies the requirement in section 4 to 208 | "keep intact all notices". 209 | 210 | c) You must license the entire work, as a whole, under this 211 | License to anyone who comes into possession of a copy. This 212 | License will therefore apply, along with any applicable section 7 213 | additional terms, to the whole of the work, and all its parts, 214 | regardless of how they are packaged. This License gives no 215 | permission to license the work in any other way, but it does not 216 | invalidate such permission if you have separately received it. 217 | 218 | d) If the work has interactive user interfaces, each must display 219 | Appropriate Legal Notices; however, if the Program has interactive 220 | interfaces that do not display Appropriate Legal Notices, your 221 | work need not make them do so. 222 | 223 | A compilation of a covered work with other separate and independent 224 | works, which are not by their nature extensions of the covered work, 225 | and which are not combined with it such as to form a larger program, 226 | in or on a volume of a storage or distribution medium, is called an 227 | "aggregate" if the compilation and its resulting copyright are not 228 | used to limit the access or legal rights of the compilation's users 229 | beyond what the individual works permit. Inclusion of a covered work 230 | in an aggregate does not cause this License to apply to the other 231 | parts of the aggregate. 232 | 233 | 6. Conveying Non-Source Forms. 234 | 235 | You may convey a covered work in object code form under the terms 236 | of sections 4 and 5, provided that you also convey the 237 | machine-readable Corresponding Source under the terms of this License, 238 | in one of these ways: 239 | 240 | a) Convey the object code in, or embodied in, a physical product 241 | (including a physical distribution medium), accompanied by the 242 | Corresponding Source fixed on a durable physical medium 243 | customarily used for software interchange. 244 | 245 | b) Convey the object code in, or embodied in, a physical product 246 | (including a physical distribution medium), accompanied by a 247 | written offer, valid for at least three years and valid for as 248 | long as you offer spare parts or customer support for that product 249 | model, to give anyone who possesses the object code either (1) a 250 | copy of the Corresponding Source for all the software in the 251 | product that is covered by this License, on a durable physical 252 | medium customarily used for software interchange, for a price no 253 | more than your reasonable cost of physically performing this 254 | conveying of source, or (2) access to copy the 255 | Corresponding Source from a network server at no charge. 256 | 257 | c) Convey individual copies of the object code with a copy of the 258 | written offer to provide the Corresponding Source. This 259 | alternative is allowed only occasionally and noncommercially, and 260 | only if you received the object code with such an offer, in accord 261 | with subsection 6b. 262 | 263 | d) Convey the object code by offering access from a designated 264 | place (gratis or for a charge), and offer equivalent access to the 265 | Corresponding Source in the same way through the same place at no 266 | further charge. You need not require recipients to copy the 267 | Corresponding Source along with the object code. If the place to 268 | copy the object code is a network server, the Corresponding Source 269 | may be on a different server (operated by you or a third party) 270 | that supports equivalent copying facilities, provided you maintain 271 | clear directions next to the object code saying where to find the 272 | Corresponding Source. Regardless of what server hosts the 273 | Corresponding Source, you remain obligated to ensure that it is 274 | available for as long as needed to satisfy these requirements. 275 | 276 | e) Convey the object code using peer-to-peer transmission, provided 277 | you inform other peers where the object code and Corresponding 278 | Source of the work are being offered to the general public at no 279 | charge under subsection 6d. 280 | 281 | A separable portion of the object code, whose source code is excluded 282 | from the Corresponding Source as a System Library, need not be 283 | included in conveying the object code work. 284 | 285 | A "User Product" is either (1) a "consumer product", which means any 286 | tangible personal property which is normally used for personal, family, 287 | or household purposes, or (2) anything designed or sold for incorporation 288 | into a dwelling. In determining whether a product is a consumer product, 289 | doubtful cases shall be resolved in favor of coverage. For a particular 290 | product received by a particular user, "normally used" refers to a 291 | typical or common use of that class of product, regardless of the status 292 | of the particular user or of the way in which the particular user 293 | actually uses, or expects or is expected to use, the product. A product 294 | is a consumer product regardless of whether the product has substantial 295 | commercial, industrial or non-consumer uses, unless such uses represent 296 | the only significant mode of use of the product. 297 | 298 | "Installation Information" for a User Product means any methods, 299 | procedures, authorization keys, or other information required to install 300 | and execute modified versions of a covered work in that User Product from 301 | a modified version of its Corresponding Source. The information must 302 | suffice to ensure that the continued functioning of the modified object 303 | code is in no case prevented or interfered with solely because 304 | modification has been made. 305 | 306 | If you convey an object code work under this section in, or with, or 307 | specifically for use in, a User Product, and the conveying occurs as 308 | part of a transaction in which the right of possession and use of the 309 | User Product is transferred to the recipient in perpetuity or for a 310 | fixed term (regardless of how the transaction is characterized), the 311 | Corresponding Source conveyed under this section must be accompanied 312 | by the Installation Information. But this requirement does not apply 313 | if neither you nor any third party retains the ability to install 314 | modified object code on the User Product (for example, the work has 315 | been installed in ROM). 316 | 317 | The requirement to provide Installation Information does not include a 318 | requirement to continue to provide support service, warranty, or updates 319 | for a work that has been modified or installed by the recipient, or for 320 | the User Product in which it has been modified or installed. Access to a 321 | network may be denied when the modification itself materially and 322 | adversely affects the operation of the network or violates the rules and 323 | protocols for communication across the network. 324 | 325 | Corresponding Source conveyed, and Installation Information provided, 326 | in accord with this section must be in a format that is publicly 327 | documented (and with an implementation available to the public in 328 | source code form), and must require no special password or key for 329 | unpacking, reading or copying. 330 | 331 | 7. Additional Terms. 332 | 333 | "Additional permissions" are terms that supplement the terms of this 334 | License by making exceptions from one or more of its conditions. 335 | Additional permissions that are applicable to the entire Program shall 336 | be treated as though they were included in this License, to the extent 337 | that they are valid under applicable law. If additional permissions 338 | apply only to part of the Program, that part may be used separately 339 | under those permissions, but the entire Program remains governed by 340 | this License without regard to the additional permissions. 341 | 342 | When you convey a copy of a covered work, you may at your option 343 | remove any additional permissions from that copy, or from any part of 344 | it. (Additional permissions may be written to require their own 345 | removal in certain cases when you modify the work.) You may place 346 | additional permissions on material, added by you to a covered work, 347 | for which you have or can give appropriate copyright permission. 348 | 349 | Notwithstanding any other provision of this License, for material you 350 | add to a covered work, you may (if authorized by the copyright holders of 351 | that material) supplement the terms of this License with terms: 352 | 353 | a) Disclaiming warranty or limiting liability differently from the 354 | terms of sections 15 and 16 of this License; or 355 | 356 | b) Requiring preservation of specified reasonable legal notices or 357 | author attributions in that material or in the Appropriate Legal 358 | Notices displayed by works containing it; or 359 | 360 | c) Prohibiting misrepresentation of the origin of that material, or 361 | requiring that modified versions of such material be marked in 362 | reasonable ways as different from the original version; or 363 | 364 | d) Limiting the use for publicity purposes of names of licensors or 365 | authors of the material; or 366 | 367 | e) Declining to grant rights under trademark law for use of some 368 | trade names, trademarks, or service marks; or 369 | 370 | f) Requiring indemnification of licensors and authors of that 371 | material by anyone who conveys the material (or modified versions of 372 | it) with contractual assumptions of liability to the recipient, for 373 | any liability that these contractual assumptions directly impose on 374 | those licensors and authors. 375 | 376 | All other non-permissive additional terms are considered "further 377 | restrictions" within the meaning of section 10. If the Program as you 378 | received it, or any part of it, contains a notice stating that it is 379 | governed by this License along with a term that is a further 380 | restriction, you may remove that term. If a license document contains 381 | a further restriction but permits relicensing or conveying under this 382 | License, you may add to a covered work material governed by the terms 383 | of that license document, provided that the further restriction does 384 | not survive such relicensing or conveying. 385 | 386 | If you add terms to a covered work in accord with this section, you 387 | must place, in the relevant source files, a statement of the 388 | additional terms that apply to those files, or a notice indicating 389 | where to find the applicable terms. 390 | 391 | Additional terms, permissive or non-permissive, may be stated in the 392 | form of a separately written license, or stated as exceptions; 393 | the above requirements apply either way. 394 | 395 | 8. Termination. 396 | 397 | You may not propagate or modify a covered work except as expressly 398 | provided under this License. Any attempt otherwise to propagate or 399 | modify it is void, and will automatically terminate your rights under 400 | this License (including any patent licenses granted under the third 401 | paragraph of section 11). 402 | 403 | However, if you cease all violation of this License, then your 404 | license from a particular copyright holder is reinstated (a) 405 | provisionally, unless and until the copyright holder explicitly and 406 | finally terminates your license, and (b) permanently, if the copyright 407 | holder fails to notify you of the violation by some reasonable means 408 | prior to 60 days after the cessation. 409 | 410 | Moreover, your license from a particular copyright holder is 411 | reinstated permanently if the copyright holder notifies you of the 412 | violation by some reasonable means, this is the first time you have 413 | received notice of violation of this License (for any work) from that 414 | copyright holder, and you cure the violation prior to 30 days after 415 | your receipt of the notice. 416 | 417 | Termination of your rights under this section does not terminate the 418 | licenses of parties who have received copies or rights from you under 419 | this License. If your rights have been terminated and not permanently 420 | reinstated, you do not qualify to receive new licenses for the same 421 | material under section 10. 422 | 423 | 9. Acceptance Not Required for Having Copies. 424 | 425 | You are not required to accept this License in order to receive or 426 | run a copy of the Program. Ancillary propagation of a covered work 427 | occurring solely as a consequence of using peer-to-peer transmission 428 | to receive a copy likewise does not require acceptance. However, 429 | nothing other than this License grants you permission to propagate or 430 | modify any covered work. These actions infringe copyright if you do 431 | not accept this License. Therefore, by modifying or propagating a 432 | covered work, you indicate your acceptance of this License to do so. 433 | 434 | 10. Automatic Licensing of Downstream Recipients. 435 | 436 | Each time you convey a covered work, the recipient automatically 437 | receives a license from the original licensors, to run, modify and 438 | propagate that work, subject to this License. You are not responsible 439 | for enforcing compliance by third parties with this License. 440 | 441 | An "entity transaction" is a transaction transferring control of an 442 | organization, or substantially all assets of one, or subdividing an 443 | organization, or merging organizations. If propagation of a covered 444 | work results from an entity transaction, each party to that 445 | transaction who receives a copy of the work also receives whatever 446 | licenses to the work the party's predecessor in interest had or could 447 | give under the previous paragraph, plus a right to possession of the 448 | Corresponding Source of the work from the predecessor in interest, if 449 | the predecessor has it or can get it with reasonable efforts. 450 | 451 | You may not impose any further restrictions on the exercise of the 452 | rights granted or affirmed under this License. For example, you may 453 | not impose a license fee, royalty, or other charge for exercise of 454 | rights granted under this License, and you may not initiate litigation 455 | (including a cross-claim or counterclaim in a lawsuit) alleging that 456 | any patent claim is infringed by making, using, selling, offering for 457 | sale, or importing the Program or any portion of it. 458 | 459 | 11. Patents. 460 | 461 | A "contributor" is a copyright holder who authorizes use under this 462 | License of the Program or a work on which the Program is based. The 463 | work thus licensed is called the contributor's "contributor version". 464 | 465 | A contributor's "essential patent claims" are all patent claims 466 | owned or controlled by the contributor, whether already acquired or 467 | hereafter acquired, that would be infringed by some manner, permitted 468 | by this License, of making, using, or selling its contributor version, 469 | but do not include claims that would be infringed only as a 470 | consequence of further modification of the contributor version. For 471 | purposes of this definition, "control" includes the right to grant 472 | patent sublicenses in a manner consistent with the requirements of 473 | this License. 474 | 475 | Each contributor grants you a non-exclusive, worldwide, royalty-free 476 | patent license under the contributor's essential patent claims, to 477 | make, use, sell, offer for sale, import and otherwise run, modify and 478 | propagate the contents of its contributor version. 479 | 480 | In the following three paragraphs, a "patent license" is any express 481 | agreement or commitment, however denominated, not to enforce a patent 482 | (such as an express permission to practice a patent or covenant not to 483 | sue for patent infringement). To "grant" such a patent license to a 484 | party means to make such an agreement or commitment not to enforce a 485 | patent against the party. 486 | 487 | If you convey a covered work, knowingly relying on a patent license, 488 | and the Corresponding Source of the work is not available for anyone 489 | to copy, free of charge and under the terms of this License, through a 490 | publicly available network server or other readily accessible means, 491 | then you must either (1) cause the Corresponding Source to be so 492 | available, or (2) arrange to deprive yourself of the benefit of the 493 | patent license for this particular work, or (3) arrange, in a manner 494 | consistent with the requirements of this License, to extend the patent 495 | license to downstream recipients. "Knowingly relying" means you have 496 | actual knowledge that, but for the patent license, your conveying the 497 | covered work in a country, or your recipient's use of the covered work 498 | in a country, would infringe one or more identifiable patents in that 499 | country that you have reason to believe are valid. 500 | 501 | If, pursuant to or in connection with a single transaction or 502 | arrangement, you convey, or propagate by procuring conveyance of, a 503 | covered work, and grant a patent license to some of the parties 504 | receiving the covered work authorizing them to use, propagate, modify 505 | or convey a specific copy of the covered work, then the patent license 506 | you grant is automatically extended to all recipients of the covered 507 | work and works based on it. 508 | 509 | A patent license is "discriminatory" if it does not include within 510 | the scope of its coverage, prohibits the exercise of, or is 511 | conditioned on the non-exercise of one or more of the rights that are 512 | specifically granted under this License. You may not convey a covered 513 | work if you are a party to an arrangement with a third party that is 514 | in the business of distributing software, under which you make payment 515 | to the third party based on the extent of your activity of conveying 516 | the work, and under which the third party grants, to any of the 517 | parties who would receive the covered work from you, a discriminatory 518 | patent license (a) in connection with copies of the covered work 519 | conveyed by you (or copies made from those copies), or (b) primarily 520 | for and in connection with specific products or compilations that 521 | contain the covered work, unless you entered into that arrangement, 522 | or that patent license was granted, prior to 28 March 2007. 523 | 524 | Nothing in this License shall be construed as excluding or limiting 525 | any implied license or other defenses to infringement that may 526 | otherwise be available to you under applicable patent law. 527 | 528 | 12. No Surrender of Others' Freedom. 529 | 530 | If conditions are imposed on you (whether by court order, agreement or 531 | otherwise) that contradict the conditions of this License, they do not 532 | excuse you from the conditions of this License. If you cannot convey a 533 | covered work so as to satisfy simultaneously your obligations under this 534 | License and any other pertinent obligations, then as a consequence you may 535 | not convey it at all. For example, if you agree to terms that obligate you 536 | to collect a royalty for further conveying from those to whom you convey 537 | the Program, the only way you could satisfy both those terms and this 538 | License would be to refrain entirely from conveying the Program. 539 | 540 | 13. Remote Network Interaction; Use with the GNU General Public License. 541 | 542 | Notwithstanding any other provision of this License, if you modify the 543 | Program, your modified version must prominently offer all users 544 | interacting with it remotely through a computer network (if your version 545 | supports such interaction) an opportunity to receive the Corresponding 546 | Source of your version by providing access to the Corresponding Source 547 | from a network server at no charge, through some standard or customary 548 | means of facilitating copying of software. This Corresponding Source 549 | shall include the Corresponding Source for any work covered by version 3 550 | of the GNU General Public License that is incorporated pursuant to the 551 | following paragraph. 552 | 553 | Notwithstanding any other provision of this License, you have 554 | permission to link or combine any covered work with a work licensed 555 | under version 3 of the GNU General Public License into a single 556 | combined work, and to convey the resulting work. The terms of this 557 | License will continue to apply to the part which is the covered work, 558 | but the work with which it is combined will remain governed by version 559 | 3 of the GNU General Public License. 560 | 561 | 14. Revised Versions of this License. 562 | 563 | The Free Software Foundation may publish revised and/or new versions of 564 | the GNU Affero General Public License from time to time. Such new versions 565 | will be similar in spirit to the present version, but may differ in detail to 566 | address new problems or concerns. 567 | 568 | Each version is given a distinguishing version number. If the 569 | Program specifies that a certain numbered version of the GNU Affero General 570 | Public License "or any later version" applies to it, you have the 571 | option of following the terms and conditions either of that numbered 572 | version or of any later version published by the Free Software 573 | Foundation. If the Program does not specify a version number of the 574 | GNU Affero General Public License, you may choose any version ever published 575 | by the Free Software Foundation. 576 | 577 | If the Program specifies that a proxy can decide which future 578 | versions of the GNU Affero General Public License can be used, that proxy's 579 | public statement of acceptance of a version permanently authorizes you 580 | to choose that version for the Program. 581 | 582 | Later license versions may give you additional or different 583 | permissions. However, no additional obligations are imposed on any 584 | author or copyright holder as a result of your choosing to follow a 585 | later version. 586 | 587 | 15. Disclaimer of Warranty. 588 | 589 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY 590 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT 591 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY 592 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, 593 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 594 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM 595 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF 596 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 597 | 598 | 16. Limitation of Liability. 599 | 600 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING 601 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS 602 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY 603 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE 604 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF 605 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD 606 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), 607 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF 608 | SUCH DAMAGES. 609 | 610 | 17. Interpretation of Sections 15 and 16. 611 | 612 | If the disclaimer of warranty and limitation of liability provided 613 | above cannot be given local legal effect according to their terms, 614 | reviewing courts shall apply local law that most closely approximates 615 | an absolute waiver of all civil liability in connection with the 616 | Program, unless a warranty or assumption of liability accompanies a 617 | copy of the Program in return for a fee. 618 | 619 | END OF TERMS AND CONDITIONS 620 | 621 | How to Apply These Terms to Your New Programs 622 | 623 | If you develop a new program, and you want it to be of the greatest 624 | possible use to the public, the best way to achieve this is to make it 625 | free software which everyone can redistribute and change under these terms. 626 | 627 | To do so, attach the following notices to the program. It is safest 628 | to attach them to the start of each source file to most effectively 629 | state the exclusion of warranty; and each file should have at least 630 | the "copyright" line and a pointer to where the full notice is found. 631 | 632 | 633 | Copyright (C) 634 | 635 | This program is free software: you can redistribute it and/or modify 636 | it under the terms of the GNU Affero General Public License as published 637 | by the Free Software Foundation, either version 3 of the License, or 638 | (at your option) any later version. 639 | 640 | This program is distributed in the hope that it will be useful, 641 | but WITHOUT ANY WARRANTY; without even the implied warranty of 642 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 643 | GNU Affero General Public License for more details. 644 | 645 | You should have received a copy of the GNU Affero General Public License 646 | along with this program. If not, see . 647 | 648 | Also add information on how to contact you by electronic and paper mail. 649 | 650 | If your software can interact with users remotely through a computer 651 | network, you should also make sure that it provides a way for users to 652 | get its source. For example, if your program is a web application, its 653 | interface could display a "Source" link that leads users to an archive 654 | of the code. There are many ways you could offer source, and different 655 | solutions will be better for different programs; see section 13 for the 656 | specific requirements. 657 | 658 | You should also get your employer (if you work as a programmer) or school, 659 | if any, to sign a "copyright disclaimer" for the program, if necessary. 660 | For more information on this, and how to apply and follow the GNU AGPL, see 661 | . 662 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jitsi OpenID 2 | 3 | Jitsi OpenID is an authentication adapter to provide [jitsi](https://jitsi.org/) the ability to use single sign on 4 | via [OpenID Connect](https://openid.net/connect/). 5 | 6 | ## Deployment 7 | 8 | **This guide is based of the [docker setup from jitsi](https://github.com/jitsi/docker-jitsi-meet/).** 9 | 10 | This image is available in the 11 | [GitHub Container Registry](https://github.com/users/MarcelCoding/packages/container/package/jitsi-openid): 12 | 13 | ``` 14 | ghcr.io/marcelcoding/jitsi-openid:latest 15 | ``` 16 | 17 | ### Docker "run" Command 18 | 19 | ```bash 20 | docker run \ 21 | -p 3000:3000 \ 22 | -e JITSI_SECRET=SECURE_SECRET \ 23 | -e JITSI_URL=https://meet.example.com \ 24 | -e JITSI_SUB=meet.example.com \ 25 | -e ISSUER_URL=https://id.example.com \ 26 | -e BASE_URL=https://auth.meet.example.com \ 27 | -e CLIENT_ID=meet.example.com \ 28 | -e CLIENT_SECRET=SECURE_SECRET \ 29 | --rm \ 30 | ghcr.io/marcelcoding/jitsi-openid:latest 31 | ``` 32 | 33 | ### Docker Compose 34 | 35 | ```yaml 36 | # docker-compose.yaml 37 | 38 | # ... 39 | 40 | services: 41 | # ... 42 | 43 | jitsi-openid: 44 | image: ghcr.io/marcelcoding/jitsi-openid:latest 45 | restart: always 46 | environment: 47 | - "JITSI_SECRET=SECURE_SECRET" # <- shared with jitsi (JWT_APP_SECRET -> see .env from jitsi), 48 | # secret to sign jwt tokens 49 | - "JITSI_URL=https://meet.example.com" # <- external url of jitsi 50 | - "JITSI_SUB=meet.example.com" # <- shared with jitsi (JWT_APP_ID -> see .env from jitsi), 51 | # id of jitsi 52 | - "ISSUER_URL=https://id.example.com" # <- base URL of your OpenID Connect provider 53 | # Keycloak: https://id.example.com/auth/realms/ 54 | - "BASE_URL=https://auth.meet.example.com" # <- base URL of this application 55 | - "CLIENT_ID=meet.example.com" # <- OpenID Connect Client ID 56 | - "CLIENT_SECRET=SECURE_SECRET" # <- OpenID Connect Client secret 57 | # - 'ACR_VALUES=password email' # <- OpenID Context Authentication Context Requirements, 58 | # space separated list of allowed actions (OPTIONAL), see 59 | # https://github.com/MarcelCoding/jitsi-openid/issues/122 60 | # - 'SCOPES=openid email jitsi' # <- OpenID Scopes, space separated list of scopes (OPTIONAL), 61 | # default: openid email 62 | # - 'VERIFY_ACCESS_TOKEN_HASH=false # <- explicitly disable access token hash verification (OPTIONAL), 63 | # default: true See https://github.com/MarcelCoding/jitsi-openid/issues/372#issuecomment-2730510228 64 | # - 'SKIP_PREJOIN_SCREEN=false' # <- skips the jitsi prejoin screen after login (default: true) 65 | # - 'GROUP=example' # <- Value for the 'group' field in the token 66 | # default: '' 67 | ports: 68 | - "3000:3000" 69 | # ... 70 | ``` 71 | 72 | To generate the `JITSI_SECRET` you can use one of the following command: 73 | 74 | ```bash 75 | cat /dev/urandom | tr -dc a-zA-Z0-9 | head -c128; echo 76 | ``` 77 | 78 | ### NixOS 79 | 80 | ```nix 81 | { 82 | inputs = { 83 | nixpkgs.url = "github:nixos/nixpkgs/nixos-23.11"; 84 | jitsi-openid = { 85 | url = "github:MarcelCoding/jitsi-openid"; 86 | inputs.nixpkgs.follows = "nixpkgs"; 87 | }; 88 | }; 89 | 90 | outputs = { self, nixpkgs, jitsi-openid, ... }: { 91 | nixosConfigurations = { 92 | hostname = nixpkgs.lib.nixosSystem { 93 | modules = [ 94 | jitsi-openid.nixosModules.default 95 | { nixpkgs.overlays = [ jitsi-openid.overlays.default ]; } 96 | ]; 97 | }; 98 | }; 99 | }; 100 | } 101 | ``` 102 | 103 | ```nix 104 | # for an explanation see docker compose setup 105 | services.jitsi-openid = { 106 | enable = true; 107 | listen = { 108 | addr = "::1"; 109 | port = 6031; 110 | }; 111 | jitsiSecretFile = "/run/secrets/jitsi-secret-file"; 112 | jitsiUrl = "https://meet.domain.tld"; 113 | jitsiSub = "meet.domain.tld"; 114 | issuerUrl = "https://auth.domain.tld"; 115 | baseUrl = "https://auth.meet.domain.tld"; 116 | clientId = "auth.meet.domain.tld"; 117 | clientSecretFile = "/run/secrets/client-secret-file"; 118 | openFirewall = false; 119 | }; 120 | ``` 121 | 122 | ### Jitsi Configuration 123 | 124 | If you have problems understating this have a look here: https://github.com/MarcelCoding/jitsi-openid/issues/80 125 | 126 | ```bash 127 | # for more information see: 128 | # https://github.com/jitsi/docker-jitsi-meet/blob/master/env.example 129 | 130 | # weather to allow users to join a room without requiring to authenticate 131 | #ENABLE_GUESTS=1 132 | 133 | # fixed 134 | ENABLE_AUTH=1 135 | AUTH_TYPE=jwt 136 | 137 | # should be the same as JITSI_ID of jitsi-openid environment variables 138 | JWT_APP_ID=meet.example.com 139 | # should be the same as JITSI_SECRET of jitsi-openid environment variables 140 | JWT_APP_SECRET=SECRET 141 | 142 | # fixed values 143 | JWT_ACCEPTED_ISSUERS=jitsi 144 | JWT_ACCEPTED_AUDIENCES=jitsi 145 | 146 | # auth.meet.example.com should be the domain name of jitsi-openid, 147 | # `/room/{room}` is the endpoint that's jitsi redirecting the user to 148 | # `{room}` is is a placeholder, where jitsi inserts the room name 149 | # jitsi-openid should redirect the user after a successfully authentication 150 | # !! it is recommend to use ALWAYS https e.g. using a reverse proxy !! 151 | TOKEN_AUTH_URL=https://auth.meet.example.com/room/{room} 152 | ``` 153 | 154 | ### Jitsi Configuration NixOS 155 | 156 | The following NixOS config shows how to use JWT Auth with the jitsi NixOS module. 157 | The necessary steps where extracted form [docker-jitsi-meet](https://github.com/jitsi/docker-jitsi-meet): 158 | 159 | ```nix 160 | { 161 | pkgs, 162 | config, 163 | ... 164 | }: 165 | 166 | let 167 | hostName = "meet.example.com"; 168 | ssoHostName = "auth-meet.example.com"; 169 | ssoPort = 3000; 170 | ssoAddress = "127.0.0.1"; 171 | cfg = config.services.jitsi-meet; 172 | in 173 | { 174 | networking.firewall.allowedUDPPorts = [ 10000 ]; # required for more then 2 participants 175 | 176 | # this assumes jitsi openid is already running on the server on port 3000 177 | # you could run it with e.g. virtualisation.oci-containers.containers 178 | services.nginx.virtualHosts.${ssoHostName} = { 179 | forceSSL = true; 180 | enableACME = true; 181 | locations = { 182 | "/" = { 183 | proxyPass = "http://${ssoAddress}:${toString ssoPort}"; 184 | }; 185 | }; 186 | }; 187 | 188 | nixpkgs.config.permittedInsecurePackages = [ 189 | "jitsi-meet-1.0.8043" 190 | ]; 191 | 192 | services.jitsi-meet = { 193 | enable = true; 194 | 195 | inherit hostName; 196 | nginx.enable = true; 197 | secureDomain = { 198 | enable = true; 199 | authentication = "token"; 200 | }; 201 | 202 | config.tokenAuthUrl = "https://${ssoHostName}/room/{room}"; 203 | }; 204 | 205 | services.prosody = { 206 | extraModules = [ 207 | "token_verification" 208 | ]; 209 | 210 | extraConfig = '' 211 | asap_accepted_issuers = "jitsi" 212 | asap_accepted_audiences = "jitsi" 213 | ''; 214 | 215 | virtualHosts.${cfg.hostName} = { 216 | # a secure secret should be used for production 217 | extraConfig = '' 218 | app_secret = "insecure_secret" 219 | app_id = "jitsi" 220 | ''; 221 | }; 222 | }; 223 | 224 | systemd.services.prosody.environment = { 225 | # the token_verification module has some more lua dependencies 226 | LUA_PATH = "${pkgs.lua52Packages.basexx}/share/lua/5.2/?.lua;${pkgs.lua52Packages.cjson}/share/lua/5.2/?.lua;${pkgs.lua52Packages.luaossl}/share/lua/5.2/?.lua;${pkgs.lua52Packages.inspect}/share/lua/5.2/?.lua"; 227 | LUA_CPATH = "${pkgs.lua52Packages.cjson}/lib/lua/5.2/?.so;${pkgs.lua52Packages.luaossl}/lib/lua/5.2/?.so"; 228 | }; 229 | } 230 | ``` 231 | 232 | ### Jitsi JWTs 233 | 234 | The JWTs are populated using the data returned by your IDP. 235 | This includes the user id, email and name. 236 | 237 | The `sub` extracted from the `prefered_username` field, if that isn't preset the `sub` field is used. 238 | 239 | The `name` is extracted from the `name` field, if that isn't preset a concatenation of `given_name`, `middle_name` 240 | and `family_name` is used. If all tree of them are also not present the `prefered_username` is used. 241 | 242 | The `affiliation` is straight up passed, without any modifications or alternatives. It can be used to restrict the 243 | permissions a user has in a specific room in jitsi. 244 | See https://github.com/jitsi-contrib/prosody-plugins/tree/main/token_affiliation for more information. 245 | 246 | The picture (avatar) URL is delegated from the IDP to Jitsi. 247 | 248 | Translations aren't respected: https://github.com/MarcelCoding/jitsi-openid/issues/117#issuecomment-1172406703 249 | 250 | ## License 251 | 252 | [LICENSE](LICENSE) 253 | -------------------------------------------------------------------------------- /flake.lock: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": { 3 | "flake-utils": { 4 | "inputs": { 5 | "systems": "systems" 6 | }, 7 | "locked": { 8 | "lastModified": 1731533236, 9 | "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", 10 | "owner": "numtide", 11 | "repo": "flake-utils", 12 | "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", 13 | "type": "github" 14 | }, 15 | "original": { 16 | "owner": "numtide", 17 | "repo": "flake-utils", 18 | "type": "github" 19 | } 20 | }, 21 | "nixpkgs": { 22 | "locked": { 23 | "lastModified": 1743703532, 24 | "narHash": "sha256-s1KLDALEeqy+ttrvqV3jx9mBZEvmthQErTVOAzbjHZs=", 25 | "owner": "NixOS", 26 | "repo": "nixpkgs", 27 | "rev": "bdb91860de2f719b57eef819b5617762f7120c70", 28 | "type": "github" 29 | }, 30 | "original": { 31 | "owner": "NixOS", 32 | "ref": "nixos-24.11", 33 | "repo": "nixpkgs", 34 | "type": "github" 35 | } 36 | }, 37 | "root": { 38 | "inputs": { 39 | "flake-utils": "flake-utils", 40 | "nixpkgs": "nixpkgs" 41 | } 42 | }, 43 | "systems": { 44 | "locked": { 45 | "lastModified": 1681028828, 46 | "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", 47 | "owner": "nix-systems", 48 | "repo": "default", 49 | "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", 50 | "type": "github" 51 | }, 52 | "original": { 53 | "owner": "nix-systems", 54 | "repo": "default", 55 | "type": "github" 56 | } 57 | } 58 | }, 59 | "root": "root", 60 | "version": 7 61 | } 62 | -------------------------------------------------------------------------------- /flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | inputs = { 3 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; 4 | flake-utils.url = "github:numtide/flake-utils"; 5 | }; 6 | 7 | outputs = { self, nixpkgs, flake-utils }: 8 | flake-utils.lib.eachDefaultSystem 9 | (system: 10 | let 11 | pkgs = (import nixpkgs) { 12 | inherit system; 13 | }; 14 | in 15 | { 16 | packages = rec { 17 | jitsi-openid = pkgs.callPackage ./package.nix { 18 | cargoToml = ./Cargo.toml; 19 | }; 20 | default = jitsi-openid; 21 | }; 22 | 23 | 24 | devShells = { 25 | default = pkgs.mkShell { 26 | nativeBuildInputs = with pkgs; [ pkg-config ]; 27 | buildInputs = with pkgs; [ openssl ]; 28 | }; 29 | }; 30 | } 31 | ) // { 32 | overlays.default = _: prev: { 33 | jitsi-openid = self.packages."${prev.system}".default; 34 | }; 35 | 36 | nixosModules = rec { 37 | jitsi-openid = import ./module.nix; 38 | default = jitsi-openid; 39 | }; 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /module.nix: -------------------------------------------------------------------------------- 1 | { config, pkgs, lib, ... }: 2 | 3 | let 4 | cfg = config.services.jitsi-openid; 5 | in 6 | { 7 | options = { 8 | services.jitsi-openid = { 9 | package = lib.mkPackageOption pkgs "jitsi-openid" { }; 10 | enable = lib.mkEnableOption (lib.mdDoc "Jitsi OpenID"); 11 | listen = { 12 | addr = lib.mkOption { 13 | type = lib.types.str; 14 | description = lib.mdDoc "The ip address Jitsi OpenID should be listening on."; 15 | default = "0.0.0.0"; 16 | }; 17 | port = lib.mkOption { 18 | type = lib.types.port; 19 | description = lib.mdDoc "The port Jitsi OpenID shuld be listening on."; 20 | default = 6031; 21 | }; 22 | }; 23 | jitsiSecretFile = lib.mkOption { 24 | type = lib.types.str; 25 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 26 | default = null; 27 | }; 28 | jitsiUrl = lib.mkOption { 29 | type = lib.types.str; 30 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 31 | default = null; 32 | }; 33 | jitsiSub = lib.mkOption { 34 | type = lib.types.str; 35 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 36 | default = null; 37 | }; 38 | issuerUrl = lib.mkOption { 39 | type = lib.types.str; 40 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 41 | default = null; 42 | }; 43 | baseUrl = lib.mkOption { 44 | type = lib.types.str; 45 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 46 | default = null; 47 | }; 48 | clientId = lib.mkOption { 49 | type = lib.types.str; 50 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 51 | default = null; 52 | }; 53 | clientSecretFile = lib.mkOption { 54 | type = lib.types.str; 55 | description = lib.mdDoc "The socket address of the udp upstream zia should redirect all traffic to."; 56 | default = null; 57 | }; 58 | openFirewall = lib.mkOption { 59 | type = lib.types.bool; 60 | default = false; 61 | description = lib.mdDoc "Whether to open ports in the firewall for the server."; 62 | }; 63 | }; 64 | }; 65 | 66 | config = lib.mkIf cfg.enable { 67 | environment.systemPackages = [ cfg.package ]; 68 | networking.firewall.allowedTCPPorts = lib.mkIf cfg.openFirewall [ cfg.listen.port ]; 69 | 70 | systemd.services.jitsi-openid = { 71 | description = "Jitsi OpenID"; 72 | 73 | wantedBy = [ "multi-user.target" ]; 74 | after = [ "network.target" ]; 75 | 76 | environment = { 77 | LISTEN_ADDR = "${if (lib.hasInfix ":" cfg.listen.addr) then "[${cfg.listen.addr}]" else cfg.listen.addr}:${toString cfg.listen.port}"; 78 | JITSI_SECRET_FILE = "%d/jitsi_secret_file"; 79 | JITSI_URL = cfg.jitsiUrl; 80 | JITSI_SUB = cfg.jitsiSub; 81 | ISSUER_URL = cfg.issuerUrl; 82 | BASE_URL = cfg.baseUrl; 83 | CLIENT_ID = cfg.clientId; 84 | CLIENT_SECRET_FILE = "%d/client_secret_file"; 85 | }; 86 | 87 | serviceConfig = { 88 | ExecStart = "${cfg.package}/bin/jitsi-openid"; 89 | DynamicUser = true; 90 | User = "jitsi-openid"; 91 | 92 | LoadCredential = [ 93 | "jitsi_secret_file:${cfg.jitsiSecretFile}" 94 | "client_secret_file:${cfg.clientSecretFile}" 95 | ]; 96 | }; 97 | }; 98 | }; 99 | } 100 | -------------------------------------------------------------------------------- /package.nix: -------------------------------------------------------------------------------- 1 | { lib, rustPlatform, pkg-config, openssl, ... }: 2 | 3 | let 4 | manifest = (lib.importTOML ./Cargo.toml).package; 5 | in 6 | rustPlatform.buildRustPackage rec { 7 | pname = manifest.name; 8 | inherit (manifest) version; 9 | 10 | src = lib.cleanSource ./.; 11 | cargoLock.lockFile = ./Cargo.lock; 12 | 13 | cargoBuildFlags = "-p ${pname}"; 14 | cargoTestFlags = "-p ${pname}"; 15 | 16 | nativeBuildInputs = [ 17 | pkg-config 18 | ]; 19 | 20 | buildInputs = [ 21 | openssl 22 | ]; 23 | 24 | meta = { 25 | mainProgram = "jitsi-openid"; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /src/cfg.rs: -------------------------------------------------------------------------------- 1 | use std::net::SocketAddr; 2 | use std::path::PathBuf; 3 | 4 | use openidconnect::{AuthenticationContextClass, ClientId, IssuerUrl}; 5 | use serde::{Deserialize, Deserializer}; 6 | use url::Url; 7 | 8 | use crate::ClientSecret; 9 | 10 | #[derive(Deserialize, Clone)] 11 | pub(crate) struct Cfg { 12 | pub(crate) jitsi_secret: Option, 13 | pub(crate) jitsi_secret_file: Option, 14 | pub(crate) jitsi_url: Url, 15 | pub(crate) jitsi_sub: String, 16 | #[serde(alias = "issuer_base_url")] 17 | pub(crate) issuer_url: IssuerUrl, 18 | pub(crate) base_url: Url, 19 | pub(crate) client_id: ClientId, 20 | #[serde(alias = "secret")] 21 | pub(crate) client_secret: Option, 22 | pub(crate) client_secret_file: Option, 23 | #[serde(default = "default_listen_addr")] 24 | pub(crate) listen_addr: SocketAddr, 25 | #[serde(default)] 26 | #[serde(deserialize_with = "string_array")] 27 | pub(crate) acr_values: Option>, 28 | #[serde(default)] 29 | #[serde(deserialize_with = "string_array2")] 30 | pub(crate) scopes: Option>, 31 | #[serde(default)] 32 | pub(crate) verify_access_token_hash: Option, 33 | #[serde(default)] 34 | pub(crate) skip_prejoin_screen: Option, 35 | #[serde(default)] 36 | pub(crate) group: String, 37 | } 38 | 39 | fn default_listen_addr() -> SocketAddr { 40 | ([127, 0, 0, 1], 3000).into() 41 | } 42 | 43 | /// Serializes an OffsetDateTime to a Unix timestamp (milliseconds since 1970/1/1T00:00:00T) 44 | pub fn string_array2<'a, D: Deserializer<'a>>( 45 | deserializer: D, 46 | ) -> Result>, D::Error> { 47 | let input: String = Deserialize::deserialize(deserializer)?; 48 | 49 | let values = input.split(' ').map(|acr| acr.to_string()).collect(); 50 | 51 | Ok(Some(values)) 52 | } 53 | 54 | /// Serializes an OffsetDateTime to a Unix timestamp (milliseconds since 1970/1/1T00:00:00T) 55 | pub fn string_array<'a, D: Deserializer<'a>>( 56 | deserializer: D, 57 | ) -> Result>, D::Error> { 58 | let input: String = Deserialize::deserialize(deserializer)?; 59 | 60 | let values = input 61 | .split(' ') 62 | .map(|acr| AuthenticationContextClass::new(acr.to_string())) 63 | .collect(); 64 | 65 | Ok(Some(values)) 66 | } 67 | -------------------------------------------------------------------------------- /src/error.rs: -------------------------------------------------------------------------------- 1 | use axum::http::StatusCode; 2 | use axum::response::{IntoResponse, Response}; 3 | use openidconnect::ClaimsVerificationError; 4 | 5 | pub(crate) enum AppError { 6 | InvalidSession, 7 | InvalidCode, 8 | InvalidState, 9 | InvalidIdTokenNonce(ClaimsVerificationError), 10 | MissingIdTokenAndUserInfoEndpoint, 11 | IdTokenRequired, 12 | InvalidAccessToken, 13 | MissingAccessTokenHash, 14 | UnsupportedSigningAlgorithm, 15 | InternalServerError, 16 | UnableToQueryUserInfo, 17 | AuthenticationContextWasNotFulfilled, 18 | InvalidSigningKey, 19 | ConfigurationError, 20 | } 21 | 22 | impl IntoResponse for AppError { 23 | fn into_response(self) -> Response { 24 | match self { 25 | Self::InvalidSession => (StatusCode::BAD_REQUEST, "Invalid Session").into_response(), 26 | Self::InvalidCode => (StatusCode::BAD_REQUEST, "Invalid Code").into_response(), 27 | Self::InvalidState => (StatusCode::BAD_REQUEST, "Invalid State").into_response(), 28 | Self::InvalidIdTokenNonce(err) => (StatusCode::BAD_REQUEST, format!("Invalid Id Token Nonce: {}", err)).into_response(), 29 | Self::MissingIdTokenAndUserInfoEndpoint => (StatusCode::BAD_REQUEST, "Missing Id Token And User Info Endpoint - at least one is missing, you may create an issue to find an workaround if you can't configure your idp to provide either of them: https://github.com/MarcelCoding/jitsi-openid/issues/new").into_response(), 30 | Self::InvalidAccessToken => (StatusCode::BAD_REQUEST, "Invalid Access Token").into_response(), 31 | Self::MissingAccessTokenHash => (StatusCode::BAD_REQUEST, "Missing Access Token Hash - see https://github.com/MarcelCoding/jitsi-openid/issues/372#issuecomment-2730510228 for more information how to handle this").into_response(), 32 | Self::UnsupportedSigningAlgorithm => (StatusCode::BAD_REQUEST, "Unsupported Signing Algorithm").into_response(), 33 | Self::InternalServerError => (StatusCode::INTERNAL_SERVER_ERROR, "Internal Server Error").into_response(), 34 | Self::UnableToQueryUserInfo => (StatusCode::INTERNAL_SERVER_ERROR, "Unable to Query User Info").into_response(), 35 | Self::IdTokenRequired => (StatusCode::INTERNAL_SERVER_ERROR, "An authentication context requirement is configured. To validate this requirement an id token is required ... no id token was provided").into_response(), 36 | Self::AuthenticationContextWasNotFulfilled => (StatusCode::BAD_REQUEST, "An authentication context requirement is configured. No one or not the correct one was fulfilled.").into_response(), 37 | Self::InvalidSigningKey => (StatusCode::INTERNAL_SERVER_ERROR, "Invalid signing key").into_response(), 38 | Self::ConfigurationError => (StatusCode::INTERNAL_SERVER_ERROR, "ConfigurationError").into_response() , 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/main.rs: -------------------------------------------------------------------------------- 1 | use std::collections::HashMap; 2 | use std::sync::Arc; 3 | 4 | use config::{Config, Environment}; 5 | use openidconnect::core::{ 6 | CoreAuthDisplay, CoreAuthPrompt, CoreErrorResponseType, CoreGenderClaim, CoreJsonWebKey, 7 | CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, CoreProviderMetadata, 8 | CoreRevocableToken, CoreRevocationErrorResponse, CoreTokenIntrospectionResponse, CoreTokenType, 9 | }; 10 | use openidconnect::{ 11 | AdditionalClaims, Client, ClientSecret, CsrfToken, EmptyExtraTokenFields, EndpointMaybeSet, 12 | EndpointNotSet, EndpointSet, IdTokenFields, Nonce, PkceCodeVerifier, RedirectUrl, 13 | StandardErrorResponse, StandardTokenResponse, UserInfoClaims, 14 | }; 15 | use serde::{self}; 16 | use serde::{Deserialize, Serialize}; 17 | use tokio::net::TcpListener; 18 | use tokio::sync::RwLock; 19 | use tracing::{info, Level}; 20 | use tracing_subscriber::FmtSubscriber; 21 | use uuid::Uuid; 22 | 23 | use crate::cfg::Cfg; 24 | use crate::error::AppError; 25 | use crate::error::AppError::{InvalidCode, InvalidSession}; 26 | use crate::routes::build_routes; 27 | use crate::AppError::{ 28 | InternalServerError, InvalidAccessToken, InvalidIdTokenNonce, InvalidState, 29 | MissingAccessTokenHash, MissingIdTokenAndUserInfoEndpoint, UnableToQueryUserInfo, 30 | UnsupportedSigningAlgorithm, 31 | }; 32 | 33 | mod cfg; 34 | mod error; 35 | mod routes; 36 | 37 | type Store = Arc>>; 38 | #[derive(Clone)] 39 | pub(crate) struct JitsiSecret(pub(crate) String); 40 | 41 | struct Session { 42 | room: String, 43 | csrf_token: CsrfToken, 44 | nonce: Nonce, 45 | pkce_verifier: PkceCodeVerifier, 46 | } 47 | 48 | #[derive(Clone, Debug, Deserialize, PartialEq, Serialize)] 49 | struct MyClaims { 50 | affiliation: Option, 51 | moderator: Option, 52 | } 53 | 54 | impl AdditionalClaims for MyClaims {} 55 | 56 | type MyUserInfoClaims = UserInfoClaims; 57 | 58 | type MyIdTokenFields = IdTokenFields< 59 | MyClaims, 60 | EmptyExtraTokenFields, 61 | CoreGenderClaim, 62 | CoreJweContentEncryptionAlgorithm, 63 | CoreJwsSigningAlgorithm, 64 | >; 65 | 66 | type MyTokenResponse = StandardTokenResponse; 67 | 68 | type MyClient = Client< 69 | MyClaims, 70 | CoreAuthDisplay, 71 | CoreGenderClaim, 72 | CoreJweContentEncryptionAlgorithm, 73 | CoreJsonWebKey, 74 | CoreAuthPrompt, 75 | StandardErrorResponse, 76 | MyTokenResponse, 77 | CoreTokenIntrospectionResponse, 78 | CoreRevocableToken, 79 | CoreRevocationErrorResponse, 80 | EndpointSet, 81 | EndpointNotSet, 82 | EndpointNotSet, 83 | EndpointNotSet, 84 | EndpointMaybeSet, 85 | EndpointMaybeSet, 86 | >; 87 | 88 | #[derive(Clone)] 89 | pub(crate) struct JitsiState { 90 | store: Store, 91 | client: MyClient, 92 | config: Cfg, 93 | jitsi_secret: JitsiSecret, 94 | http_client: reqwest::Client, 95 | } 96 | 97 | #[tokio::main] 98 | async fn main() -> anyhow::Result<()> { 99 | let subscriber = FmtSubscriber::builder() 100 | .with_max_level(Level::INFO) 101 | .compact() 102 | .finish(); 103 | 104 | tracing::subscriber::set_global_default(subscriber)?; 105 | 106 | info!(concat!( 107 | "Booting ", 108 | env!("CARGO_PKG_NAME"), 109 | "/", 110 | env!("CARGO_PKG_VERSION"), 111 | "..." 112 | )); 113 | 114 | let config = Config::builder() 115 | .add_source(Environment::default().try_parsing(true)) 116 | .build()? 117 | .try_deserialize::()?; 118 | 119 | let store = Store::new(RwLock::new(HashMap::new())); 120 | 121 | info!( 122 | "Using identity provider: {} and client-id: {}", 123 | &config.issuer_url.url(), 124 | *config.client_id 125 | ); 126 | 127 | let http_client = reqwest::ClientBuilder::new() 128 | // Following redirects opens the client up to SSRF vulnerabilities. 129 | .redirect(reqwest::redirect::Policy::none()) 130 | .build() 131 | .expect("Client should build"); 132 | 133 | let provider_metadata: CoreProviderMetadata = 134 | CoreProviderMetadata::discover_async(config.issuer_url.clone(), &http_client).await?; 135 | 136 | let client_secret = config 137 | .client_secret 138 | .clone() 139 | .or( 140 | config 141 | .client_secret_file 142 | .clone() 143 | .map(|path| ClientSecret::new(std::fs::read_to_string(path).unwrap())), 144 | ) 145 | .expect("Client secret not specified."); 146 | 147 | let client = MyClient::from_provider_metadata( 148 | provider_metadata, 149 | config.client_id.clone(), 150 | Some(client_secret), 151 | ) 152 | .set_redirect_uri(RedirectUrl::from_url(config.base_url.join("callback")?)); 153 | // TODO: .set_revocation_uri ? 154 | 155 | info!("Successfully queried identity provider metadata"); 156 | 157 | let jitsi_secret = JitsiSecret( 158 | config 159 | .jitsi_secret 160 | .clone() 161 | .or( 162 | config 163 | .jitsi_secret_file 164 | .clone() 165 | .map(|path| std::fs::read_to_string(path).unwrap()), 166 | ) 167 | .expect("Jitsi secret not specified."), 168 | ); 169 | 170 | let app = build_routes().with_state(JitsiState { 171 | store, 172 | client, 173 | config: config.clone(), 174 | jitsi_secret: jitsi_secret.clone(), 175 | http_client, 176 | }); 177 | 178 | let listener = TcpListener::bind(config.listen_addr).await?; 179 | 180 | info!( 181 | "Listening on {}, have a try on: {}/{{name}}", 182 | config.listen_addr, 183 | config.base_url.join("room")? 184 | ); 185 | 186 | axum::serve(listener, app.into_make_service()).await?; 187 | 188 | Ok(()) 189 | } 190 | 191 | // async fn shutdown_signal() { 192 | // let ctrl_c = async { 193 | // signal::ctrl_c() 194 | // .await 195 | // .expect("failed to install Ctrl+C handler"); 196 | // }; 197 | // 198 | // #[cfg(unix)] 199 | // { 200 | // let terminate = async { 201 | // signal::unix::signal(signal::unix::SignalKind::terminate()) 202 | // .expect("failed to install signal handler") 203 | // .recv() 204 | // .await; 205 | // }; 206 | // 207 | // tokio::select! { 208 | // _ = ctrl_c => {}, 209 | // _ = terminate => {}, 210 | // } 211 | // } 212 | // 213 | // #[cfg(not(unix))] 214 | // ctrl_c.await; 215 | // 216 | // info!("signal received, starting graceful shutdown"); 217 | // } 218 | -------------------------------------------------------------------------------- /src/routes.rs: -------------------------------------------------------------------------------- 1 | use axum::extract::{Path, Query, State}; 2 | use axum::response::{IntoResponse, Redirect}; 3 | use axum::routing::get; 4 | use axum::Router; 5 | use axum_extra::extract::cookie::Cookie; 6 | use axum_extra::extract::CookieJar; 7 | use jsonwebtoken::{EncodingKey, Header}; 8 | use openidconnect::core::{CoreAuthenticationFlow, CoreGenderClaim}; 9 | use openidconnect::{ 10 | AccessTokenHash, AuthorizationCode, ConfigurationError, CsrfToken, IdTokenClaims, Nonce, 11 | OAuth2TokenResponse, PkceCodeChallenge, Scope, TokenResponse, 12 | }; 13 | use serde::{self, Serializer}; 14 | use serde::{Deserialize, Serialize}; 15 | use time::{Duration, OffsetDateTime}; 16 | use tracing::{error, warn}; 17 | use uuid::Uuid; 18 | 19 | use crate::AppError::{AuthenticationContextWasNotFulfilled, IdTokenRequired}; 20 | use crate::{ 21 | AppError, Cfg, InternalServerError, InvalidAccessToken, InvalidCode, InvalidIdTokenNonce, 22 | InvalidSession, InvalidState, JitsiState, MissingAccessTokenHash, 23 | MissingIdTokenAndUserInfoEndpoint, MyClaims, MyClient, MyTokenResponse, MyUserInfoClaims, 24 | Session, UnableToQueryUserInfo, UnsupportedSigningAlgorithm, 25 | }; 26 | 27 | const COOKIE_NAME: &str = "JITSI_OPENID_SESSION"; 28 | 29 | pub(crate) fn build_routes() -> Router { 30 | Router::new() 31 | .route("/room/{name}", get(room)) 32 | .route("/callback", get(callback)) 33 | } 34 | 35 | async fn room( 36 | Path(room): Path, 37 | State(state): State, 38 | jar: CookieJar, 39 | ) -> impl IntoResponse { 40 | let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); 41 | 42 | let mut request = state 43 | .client 44 | .authorize_url( 45 | CoreAuthenticationFlow::AuthorizationCode, 46 | CsrfToken::new_random, 47 | Nonce::new_random, 48 | ) 49 | .set_pkce_challenge(pkce_challenge); 50 | 51 | match state.config.scopes { 52 | None => { 53 | request = request 54 | .add_scope(Scope::new("profile".to_string())) 55 | .add_scope(Scope::new("email".to_string())) 56 | } 57 | Some(scopes) => { 58 | for scope in &scopes { 59 | request = request.add_scope(Scope::new(scope.to_string())); 60 | } 61 | } 62 | }; 63 | 64 | if let Some(acr_values) = state.config.acr_values { 65 | for class in acr_values { 66 | request = request.add_auth_context_value(class); 67 | } 68 | } 69 | 70 | let (auth_url, csrf_token, nonce) = request.url(); 71 | 72 | let session_id = Uuid::new_v4(); 73 | state.store.write().await.insert( 74 | session_id, 75 | Session { 76 | room, 77 | csrf_token, 78 | nonce, 79 | pkce_verifier, 80 | }, 81 | ); 82 | 83 | // Build the cookie 84 | let cookie = Cookie::build((COOKIE_NAME, session_id.to_string())) 85 | .domain( 86 | state 87 | .config 88 | .base_url 89 | .host() 90 | .expect("Missing host in base url") 91 | .to_string(), 92 | ) 93 | .path(state.config.base_url.path().to_string()) 94 | .secure(state.config.base_url.scheme() == "https") 95 | .http_only(true) 96 | .max_age(Duration::minutes(30)); 97 | 98 | (jar.add(cookie), Redirect::to(auth_url.as_str())) 99 | } 100 | 101 | #[derive(Deserialize)] 102 | struct Callback { 103 | state: String, 104 | // session_state: String, 105 | code: AuthorizationCode, 106 | } 107 | 108 | async fn callback( 109 | jar: CookieJar, 110 | Query(callback): Query, 111 | State(state): State, 112 | ) -> Result { 113 | let session_id = match jar 114 | .get(COOKIE_NAME) 115 | .map(|cookie| Uuid::parse_str(cookie.value())) 116 | { 117 | Some(Ok(session_id)) => session_id, 118 | Some(Err(_)) => return Err(InvalidSession), 119 | None => return Err(InvalidSession), 120 | }; 121 | 122 | let session = match state.store.write().await.remove(&session_id) { 123 | Some(session) => session, 124 | None => return Err(InvalidSession), 125 | }; 126 | 127 | if &callback.state != session.csrf_token.secret() { 128 | return Err(InvalidState); 129 | } 130 | 131 | let response = state 132 | .client 133 | .exchange_code(callback.code) 134 | .map_err(|err| { 135 | error!("Configuration error: {:?}", err); 136 | AppError::ConfigurationError 137 | })? 138 | .set_pkce_verifier(session.pkce_verifier) 139 | .request_async(&state.http_client) 140 | .await 141 | .map_err(|err| { 142 | warn!("Authentication failed, Invalid Code: {:?}", err); 143 | InvalidCode 144 | })?; 145 | 146 | let jitsi_user = match id_token_claims(&state.config, &state.client, &response, &session.nonce)? { 147 | None => match user_info_claims(&state.client, &state.http_client, &response).await? { 148 | None => return Err(MissingIdTokenAndUserInfoEndpoint), 149 | Some(user) => user, 150 | }, 151 | Some(user) => user, 152 | }; 153 | 154 | let jwt = create_jitsi_jwt( 155 | jitsi_user, 156 | "jitsi".to_string(), 157 | "jitsi".to_string(), 158 | state.config.jitsi_sub, 159 | "*".to_string(), 160 | state.jitsi_secret.0, 161 | state.config.group, 162 | ) 163 | .map_err(|err| { 164 | error!("Unable to create jwt: {}", err); 165 | InternalServerError 166 | })?; 167 | 168 | let mut url = state.config.jitsi_url.join(&session.room).unwrap(); 169 | url.query_pairs_mut().append_pair("jwt", &jwt); 170 | 171 | if state.config.skip_prejoin_screen.unwrap_or(true) { 172 | url.set_fragment(Some("config.prejoinConfig.enabled=false")); 173 | } 174 | 175 | Ok(Redirect::to(url.as_str())) 176 | } 177 | 178 | fn id_token_claims( 179 | config: &Cfg, 180 | client: &MyClient, 181 | response: &MyTokenResponse, 182 | nonce: &Nonce, 183 | ) -> Result, AppError> { 184 | let id_token = match response.id_token() { 185 | Some(id_token) => id_token, 186 | None => { 187 | return if config.acr_values.is_none() { 188 | Ok(None) 189 | } else { 190 | Err(IdTokenRequired) 191 | }; 192 | } 193 | }; 194 | 195 | let id_token_verifier = client 196 | .id_token_verifier() 197 | .set_other_audience_verifier_fn(|_aud| true); 198 | let claims = id_token 199 | .claims(&id_token_verifier, nonce) 200 | .map_err(InvalidIdTokenNonce)?; 201 | 202 | if let Some(acr_values) = &config.acr_values { 203 | if let Some(auth_context) = claims.auth_context_ref() { 204 | if !acr_values.contains(auth_context) { 205 | return Err(AuthenticationContextWasNotFulfilled); 206 | } 207 | } else { 208 | return Err(AuthenticationContextWasNotFulfilled); 209 | } 210 | } 211 | 212 | if config.verify_access_token_hash.unwrap_or(true) { 213 | match claims.access_token_hash() { 214 | Some(expected_access_token_hash) => { 215 | let algorithm = id_token.signing_alg().map_err(|err| { 216 | warn!( 217 | "Authentication failed, UnsupportedSigningAlgorithm: {:?}", 218 | err 219 | ); 220 | UnsupportedSigningAlgorithm 221 | })?; 222 | 223 | let actual_access_token_hash = AccessTokenHash::from_token( 224 | response.access_token(), 225 | algorithm, 226 | id_token 227 | .signing_key(&client.id_token_verifier()) 228 | .map_err(|err| { 229 | error!("Invalid Signing Key: {:?}", err); 230 | AppError::InvalidSigningKey 231 | })?, 232 | ) 233 | .map_err(|err| { 234 | warn!( 235 | "Authentication failed, UnsupportedSigningAlgorithm: {:?}", 236 | err 237 | ); 238 | UnsupportedSigningAlgorithm 239 | })?; 240 | 241 | if &actual_access_token_hash != expected_access_token_hash { 242 | return Err(InvalidAccessToken); 243 | } 244 | } 245 | None => return Err(MissingAccessTokenHash), 246 | }; 247 | } 248 | 249 | let uid = match claims.preferred_username() { 250 | Some(name) => name.to_string(), 251 | None => claims.subject().to_string(), 252 | }; 253 | 254 | Ok(Some(JitsiUser { 255 | id: uid, 256 | email: claims.email().map(|email| email.to_string()), 257 | affiliation: claims.additional_claims().affiliation.clone(), 258 | name: get_display_name_id_token(claims), 259 | avatar: claims 260 | .picture() 261 | .and_then(|x| x.get(None)) 262 | .map(|x| x.to_string()), 263 | moderator: claims.additional_claims().moderator, 264 | })) 265 | } 266 | 267 | async fn user_info_claims( 268 | client: &MyClient, 269 | http_client: &reqwest::Client, 270 | response: &MyTokenResponse, 271 | ) -> Result, AppError> { 272 | match client.user_info(response.access_token().clone(), None) { 273 | Ok(request) => { 274 | let claims: MyUserInfoClaims = request.request_async(http_client).await.map_err(|err| { 275 | warn!("Authentication failed, UnableToQueryUserInfo: {:?}", err); 276 | UnableToQueryUserInfo 277 | })?; 278 | 279 | Ok(Some(JitsiUser { 280 | id: match claims.preferred_username() { 281 | Some(name) => name.to_string(), 282 | None => claims.subject().to_string(), 283 | }, 284 | email: claims.email().map(|email| email.to_string()), 285 | affiliation: claims.additional_claims().affiliation.clone(), 286 | name: get_display_name(&claims), 287 | avatar: claims 288 | .picture() 289 | .and_then(|x| x.get(None)) 290 | .map(|x| x.to_string()), 291 | moderator: claims.additional_claims().moderator, 292 | })) 293 | } 294 | Err(ConfigurationError::MissingUrl(_)) => Ok(None), 295 | Err(err) => { 296 | error!("Unable to find user info url: {}", err); 297 | Err(InternalServerError) 298 | } 299 | } 300 | } 301 | 302 | #[derive(Serialize)] 303 | struct JitsiClaims { 304 | context: JitsiContext, 305 | aud: String, 306 | iss: String, 307 | sub: String, 308 | room: String, 309 | #[serde(serialize_with = "jwt_numeric_date")] 310 | nbf: OffsetDateTime, 311 | #[serde(serialize_with = "jwt_numeric_date")] 312 | iat: OffsetDateTime, 313 | #[serde(serialize_with = "jwt_numeric_date")] 314 | exp: OffsetDateTime, 315 | } 316 | 317 | #[derive(Serialize)] 318 | struct JitsiContext { 319 | user: JitsiUser, 320 | group: Option, 321 | } 322 | 323 | #[derive(Serialize)] 324 | struct JitsiUser { 325 | id: String, 326 | email: Option, 327 | affiliation: Option, 328 | name: Option, 329 | avatar: Option, 330 | moderator: Option, 331 | } 332 | 333 | fn create_jitsi_jwt( 334 | user: JitsiUser, 335 | aud: String, 336 | iss: String, 337 | sub: String, 338 | room: String, 339 | secret: String, 340 | group: String, 341 | ) -> anyhow::Result { 342 | let iat = OffsetDateTime::now_utc(); 343 | let exp = iat + Duration::days(1); 344 | 345 | let context = JitsiContext { 346 | user, 347 | group: Some(group), 348 | }; 349 | 350 | let claims = JitsiClaims { 351 | context, 352 | aud, 353 | iss, 354 | sub, 355 | room, 356 | // nbf = not-before 357 | nbf: iat, // idk whey some jitsi configurations what this, its basically the same as iat 358 | iat, 359 | exp, 360 | }; 361 | 362 | let token = jsonwebtoken::encode( 363 | &Header::default(), 364 | &claims, 365 | &EncodingKey::from_secret(secret.as_bytes()), 366 | )?; 367 | 368 | Ok(token) 369 | } 370 | 371 | /// Serializes an OffsetDateTime to a Unix timestamp (milliseconds since 1970/1/1T00:00:00T) 372 | pub fn jwt_numeric_date( 373 | date: &OffsetDateTime, 374 | serializer: S, 375 | ) -> Result { 376 | let timestamp = date.unix_timestamp(); 377 | serializer.serialize_i64(timestamp) 378 | } 379 | 380 | fn get_display_name_id_token(claims: &IdTokenClaims) -> Option { 381 | if let Some(name) = claims 382 | .name() 383 | .or_else(|| claims.name()) 384 | .and_then(|name| name.get(None)) 385 | .map(|name| name.to_string()) 386 | { 387 | return Some(name); 388 | } 389 | 390 | let name = [ 391 | claims 392 | .given_name() 393 | .and_then(|name| name.get(None)) 394 | .map(|name| name.to_string()), 395 | claims 396 | .middle_name() 397 | .and_then(|name| name.get(None)) 398 | .map(|name| name.to_string()), 399 | claims 400 | .family_name() 401 | .and_then(|name| name.get(None)) 402 | .map(|name| name.to_string()), 403 | ]; 404 | 405 | if !name.is_empty() { 406 | return Some( 407 | name 408 | .into_iter() 409 | .flatten() 410 | .collect::>() 411 | .join(" "), 412 | ); 413 | } 414 | 415 | claims.preferred_username().map(|name| name.to_string()) 416 | } 417 | 418 | fn get_display_name(claims: &MyUserInfoClaims) -> Option { 419 | if let Some(name) = claims 420 | .name() 421 | .or_else(|| claims.name()) 422 | .and_then(|name| name.get(None)) 423 | .map(|name| name.to_string()) 424 | { 425 | return Some(name); 426 | } 427 | 428 | let name = [ 429 | claims 430 | .given_name() 431 | .and_then(|name| name.get(None)) 432 | .map(|name| name.to_string()), 433 | claims 434 | .middle_name() 435 | .and_then(|name| name.get(None)) 436 | .map(|name| name.to_string()), 437 | claims 438 | .family_name() 439 | .and_then(|name| name.get(None)) 440 | .map(|name| name.to_string()), 441 | ]; 442 | 443 | if !name.is_empty() { 444 | return Some( 445 | name 446 | .into_iter() 447 | .flatten() 448 | .collect::>() 449 | .join(" "), 450 | ); 451 | } 452 | 453 | claims.preferred_username().map(|name| name.to_string()) 454 | } 455 | --------------------------------------------------------------------------------