├── .gitignore
├── CODEOWNERS
├── images
├── image1.png
└── image2.png
├── ic_websocket_canisters
├── Cargo.toml
├── src
│ ├── ic_websocket_frontend
│ │ ├── assets
│ │ │ ├── favicon.ico
│ │ │ ├── main.css
│ │ │ └── logo2.svg
│ │ └── src
│ │ │ ├── utils
│ │ │ ├── parseHTMLString.js
│ │ │ ├── addNotification.js
│ │ │ └── validateBody.js
│ │ │ ├── index.js
│ │ │ ├── index.html
│ │ │ └── websocketConnection.js
│ └── ic_websocket_backend
│ │ ├── Cargo.toml
│ │ ├── ic_websocket_backend.did
│ │ └── src
│ │ ├── canister.rs
│ │ ├── lib.rs
│ │ └── sock.rs
├── dfx.json
├── package.json
├── webpack.config.js
└── Cargo.lock
├── ic_websocket_gateway
├── Cargo.toml
├── src
│ ├── canister_methods.rs
│ └── main.rs
└── Cargo.lock
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @dfinity/boundary-node
--------------------------------------------------------------------------------
/images/image1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfinity/ic-websocket-poc/HEAD/images/image1.png
--------------------------------------------------------------------------------
/images/image2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfinity/ic-websocket-poc/HEAD/images/image2.png
--------------------------------------------------------------------------------
/ic_websocket_canisters/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "src/ic_websocket_backend",
4 | ]
5 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/assets/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dfinity/ic-websocket-poc/HEAD/ic_websocket_canisters/src/ic_websocket_frontend/assets/favicon.ico
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/utils/parseHTMLString.js:
--------------------------------------------------------------------------------
1 | export default function (HTMLstring) {
2 | const node = new DOMParser().parseFromString(HTMLstring, "text/html").body
3 | .firstElementChild;
4 | return node;
5 | }
6 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/index.js:
--------------------------------------------------------------------------------
1 | import websocketConnection from "./websocketConnection";
2 |
3 | let backend_canister_id = "bw4dl-smaaa-aaaaa-qaacq-cai";
4 | let gateway_address = "ws://127.0.0.1:8080";
5 | let url = "http://127.0.0.1:4943";
6 | let local_test = true;
7 | //let url = "https://ic0.app";
8 | //let local_test = false;
9 |
10 | let ws = new websocketConnection(backend_canister_id, gateway_address, url, local_test);
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_backend/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ic_websocket_backend"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [lib]
7 | crate-type = ["cdylib"]
8 |
9 | [dependencies]
10 | candid = "0.8"
11 | ic-cdk = "0.6.6"
12 | ic-cdk-macros = "0.6.6"
13 | flate2 = "1.0"
14 | ic-certified-map = "0.3"
15 | base64 = "0.13.1"
16 | serde = "1.0.147"
17 | sha2 = "0.10.6"
18 | serde_cbor = "0.11.2"
19 | serde_bytes = "0.11"
20 | ed25519-compact = { version = "2", default-features = false }
--------------------------------------------------------------------------------
/ic_websocket_gateway/Cargo.toml:
--------------------------------------------------------------------------------
1 | [package]
2 | name = "ic_websocket_gateway"
3 | version = "0.1.0"
4 | edition = "2021"
5 |
6 | [dependencies]
7 | ezsockets = { version = "0.4", features = ["tungstenite"] }
8 | async-trait = "0.1.52"
9 | candid = "0.8.3"
10 | ic-agent = "0.23.2"
11 | ic-cdk = "0.7.4"
12 | ic-cdk-macros = "0.6.10"
13 | serde = "1.0.147"
14 | serde_cbor = "0.11.2"
15 | tokio = { version = "1.21.2", features = ["full"] }
16 | ring = "0.16"
17 | serde_bytes = "0.11"
18 | tungstenite = "0.16.0"
19 | ed25519-compact = "2"
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_backend/ic_websocket_backend.did:
--------------------------------------------------------------------------------
1 | type Message = record {
2 | client_id: nat64;
3 | key: text;
4 | val: blob;
5 | };
6 |
7 | type CertMessages = record {
8 | messages: vec Message;
9 | cert: blob;
10 | tree: blob;
11 | };
12 |
13 | service : {
14 | "ws_register": (blob) -> (nat64);
15 | "ws_get_client_key": (nat64) -> (blob);
16 | "ws_open": (blob, blob) -> (bool);
17 | "ws_close": (nat64) -> ();
18 | "ws_message": (blob) -> (bool);
19 | "ws_get_messages": (nat64) -> (CertMessages) query;
20 |
21 | "ws_wipe": () -> ();
22 | }
23 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/dfx.json:
--------------------------------------------------------------------------------
1 | {
2 | "canisters": {
3 | "ic_websocket_backend": {
4 | "candid": "src/ic_websocket_backend/ic_websocket_backend.did",
5 | "package": "ic_websocket_backend",
6 | "type": "rust"
7 | },
8 | "ic_websocket_frontend": {
9 | "dependencies": [
10 | "ic_websocket_backend"
11 | ],
12 | "frontend": {
13 | "entrypoint": "src/ic_websocket_frontend/src/index.html"
14 | },
15 | "source": [
16 | "src/ic_websocket_frontend/assets",
17 | "dist/ic_websocket_frontend/"
18 | ],
19 | "type": "assets"
20 | }
21 | },
22 | "defaults": {
23 | "build": {
24 | "args": "",
25 | "packtool": ""
26 | }
27 | },
28 | "output_env_file": ".env",
29 | "version": 1
30 | }
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_backend/src/canister.rs:
--------------------------------------------------------------------------------
1 | use ic_cdk::export::candid::CandidType;
2 | use serde::{Deserialize, Serialize};
3 | use serde_cbor::{from_slice, Serializer};
4 |
5 | use crate::{sock::send_message_from_canister, WebsocketMessage};
6 |
7 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
8 | #[candid_path("ic_cdk::export::candid")]
9 | pub struct AppMessage {
10 | pub text: String,
11 | }
12 |
13 | pub fn ws_on_open(client_id: u64) {
14 | let msg = AppMessage {
15 | text: String::from("ping"),
16 | };
17 | ws_send_app_message(client_id, msg);
18 | }
19 |
20 | pub fn ws_on_message(content: WebsocketMessage) {
21 | let app_msg: AppMessage = from_slice(&content.message).unwrap();
22 | let new_msg = AppMessage {
23 | text: app_msg.text + " ping",
24 | };
25 | ws_send_app_message(content.client_id, new_msg)
26 | }
27 |
28 | pub fn ws_send_app_message(client_id: u64, msg: AppMessage) {
29 | let mut msg_cbor = vec![];
30 | let mut serializer = Serializer::new(&mut msg_cbor);
31 | serializer.self_describe().unwrap();
32 | msg.serialize(&mut serializer).unwrap();
33 |
34 | send_message_from_canister(client_id, msg_cbor);
35 | }
36 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | WebSocket Demo!
7 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 | WebSocket LiveFeed
22 | const connection
24 | = new
25 | WebSocket(gateway_address);
29 |
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ic_websocket_frontend",
3 | "version": "0.1.0",
4 | "description": "Internet Computer starter application",
5 | "keywords": [
6 | "Internet Computer",
7 | "Motoko",
8 | "JavaScript",
9 | "Canister"
10 | ],
11 | "scripts": {
12 | "build": "webpack",
13 | "prebuild": "npm run generate",
14 | "start": "webpack serve --mode development --env development",
15 | "prestart": "npm run generate",
16 | "generate": "dfx generate ic_websocket_backend"
17 | },
18 | "devDependencies": {
19 | "@dfinity/agent": "0.15.1",
20 | "@dfinity/candid": "0.15.1",
21 | "@dfinity/principal": "0.15.1",
22 | "assert": "2.0.0",
23 | "buffer": "6.0.3",
24 | "copy-webpack-plugin": "^11.0.0",
25 | "events": "3.3.0",
26 | "html-webpack-plugin": "5.5.0",
27 | "process": "0.11.10",
28 | "stream-browserify": "3.0.0",
29 | "terser-webpack-plugin": "^5.3.3",
30 | "util": "0.12.4",
31 | "webpack": "^5.73.0",
32 | "webpack-cli": "^4.10.0",
33 | "webpack-dev-server": "^4.8.1"
34 | },
35 | "engines": {
36 | "node": "^12 || ^14 || ^16 || ^18"
37 | },
38 | "browserslist": [
39 | "last 2 chrome version",
40 | "last 2 firefox version",
41 | "last 2 safari version",
42 | "last 2 edge version"
43 | ],
44 | "dependencies": {
45 | "@noble/ed25519": "^1.7.1"
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/utils/addNotification.js:
--------------------------------------------------------------------------------
1 | import parseHTMLString from "./parseHTMLString";
2 |
3 | const notifications = document.getElementById("notifications");
4 |
5 | export default function addNotification(text, heading) {
6 | const date = new Date(),
7 | time = new Intl.DateTimeFormat("default", {
8 | hour: "numeric",
9 | minute: "numeric",
10 | hour12: false
11 | }).format(date);
12 |
13 | let notificationHtmlString = ``;
14 | if (heading) {
15 | notificationHtmlString +=
16 | `
` + heading + ``;
17 | }
18 | notificationHtmlString +=
19 | `
` +
20 | String(text) +
21 | `
22 |
` +
23 | time +
24 | `
25 |
notifications_active
26 |
`;
27 |
28 | const newNotification = parseHTMLString(notificationHtmlString);
29 | const newNotificationHeight = heading ? 83.4 : 51.2;
30 |
31 | notifications.classList.add("inserting");
32 | notifications.style.paddingTop = newNotificationHeight + 40 + "px";
33 |
34 | setTimeout(() => {
35 | notifications.classList.remove("inserting");
36 | notifications.style.paddingTop = "30px";
37 | notifications.appendChild(newNotification);
38 |
39 | setTimeout(() => {
40 | const notification = document.querySelector(".appearing");
41 | notification.classList.add("appeared");
42 | notification.classList.remove("appearing");
43 |
44 | // dzwoneczek w prawo po 4s
45 | setTimeout(() => {
46 | notification.classList.remove("appeared");
47 | notification.classList.add("transitioned");
48 | }, 4 * 1000);
49 | }, 0);
50 | }, 0.55 * 1000);
51 | }
52 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/utils/validateBody.js:
--------------------------------------------------------------------------------
1 | import {
2 | Cbor,
3 | Certificate,
4 | // HashTree,
5 | // HttpAgent,
6 | lookup_path,
7 | reconstruct,
8 | compare
9 | } from "@dfinity/agent";
10 | // import { Principal } from "@dfinity/principal";
11 | // import { lebDecode } from "@dfinity/candid";
12 | // import { PipeArrayBuffer } from "@dfinity/candid/lib/cjs/utils/buffer";
13 |
14 | function equal(buf1, buf2) {
15 | return compare(buf1, buf2) === 0;
16 | }
17 |
18 | export default async function validateBody(
19 | canisterId,
20 | path,
21 | body,
22 | certificate,
23 | tree,
24 | agent
25 | ) {
26 | //await agent.fetchRootKey();
27 | //console.log("Root key= ");
28 | //console.log(agent.rootKey);
29 |
30 | let cert;
31 | try {
32 | cert = await Certificate.create({
33 | certificate,
34 | canisterId,
35 | rootKey: agent.rootKey
36 | });
37 | } catch (error) {
38 | return false;
39 | }
40 |
41 | const hashTree = Cbor.decode(tree);
42 | const reconstructed = await reconstruct(hashTree);
43 | const witness = cert.lookup([
44 | "canister",
45 | canisterId.toUint8Array(),
46 | "certified_data"
47 | ]);
48 |
49 | if (!witness) {
50 | throw new Error(
51 | "Could not find certified data for this canister in the certificate."
52 | );
53 | }
54 |
55 | // First validate that the Tree is as good as the certification.
56 | if (!equal(witness, reconstructed)) {
57 | console.error("Witness != Tree passed in ic-certification");
58 | return false;
59 | }
60 |
61 | // Next, calculate the SHA of the content.
62 | const sha = await crypto.subtle.digest("SHA-256", body);
63 | let treeSha = lookup_path(["websocket", path], hashTree);
64 |
65 | if (!treeSha) {
66 | // Allow fallback to `index.html`.
67 | treeSha = lookup_path(["websocket"], hashTree);
68 | }
69 |
70 | if (!treeSha) {
71 | // The tree returned in the certification header is wrong. Return false.
72 | // We don't throw here, just invalidate the request.
73 | console.error(
74 | `Invalid Tree in the header. Does not contain path ${JSON.stringify(
75 | path
76 | )}`
77 | );
78 | return false;
79 | }
80 |
81 | return !!treeSha && equal(sha, treeSha);
82 | }
83 |
--------------------------------------------------------------------------------
/ic_websocket_gateway/src/canister_methods.rs:
--------------------------------------------------------------------------------
1 | use candid::CandidType;
2 | use candid::Decode;
3 | use ed25519_compact::PublicKey;
4 | use ic_agent::{
5 | agent::http_transport::ReqwestHttpReplicaV2Transport, export::Principal,
6 | identity::BasicIdentity, Agent,
7 | };
8 | use serde::{Deserialize, Serialize};
9 | use std::sync::Arc;
10 |
11 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
12 | #[candid_path("ic_cdk::export::candid")]
13 | pub struct WebsocketMessage {
14 | pub client_id: u64,
15 | pub sequence_num: u64,
16 | pub timestamp: u64,
17 | #[serde(with = "serde_bytes")]
18 | pub message: Vec,
19 | }
20 |
21 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
22 | pub struct EncodedMessage {
23 | pub client_id: u64,
24 | pub key: String,
25 | #[serde(with = "serde_bytes")]
26 | pub val: Vec,
27 | }
28 |
29 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
30 | pub struct CertMessages {
31 | pub messages: Vec,
32 | #[serde(with = "serde_bytes")]
33 | pub cert: Vec,
34 | #[serde(with = "serde_bytes")]
35 | pub tree: Vec,
36 | }
37 |
38 | pub async fn get_new_agent(url: &str, identity: Arc, fetch_key: bool) -> Agent {
39 | let transport = ReqwestHttpReplicaV2Transport::create(url.to_string()).unwrap();
40 | let agent = Agent::builder()
41 | .with_transport(transport)
42 | .with_arc_identity(identity)
43 | .build()
44 | .unwrap();
45 | if fetch_key {
46 | agent.fetch_root_key().await.unwrap();
47 | }
48 | agent
49 | }
50 |
51 | pub async fn ws_get_client_key(
52 | agent: &Agent,
53 | canister_id: &Principal,
54 | client_id: u64,
55 | ) -> PublicKey {
56 | let args = candid::encode_args((client_id,))
57 | .map_err(|e| e.to_string())
58 | .unwrap();
59 |
60 | let res = agent
61 | .query(canister_id, "ws_get_client_key")
62 | .with_arg(&args)
63 | .call()
64 | .await
65 | .unwrap();
66 |
67 | PublicKey::from_slice(&Decode!(&res, Vec).map_err(|e| e.to_string()).unwrap()).unwrap()
68 | }
69 |
70 | pub async fn ws_open(agent: &Agent, canister_id: &Principal, msg: Vec, sig: Vec) -> bool {
71 | let args = candid::encode_args((msg, sig)).unwrap();
72 |
73 | let res = agent
74 | .update(canister_id, "ws_open")
75 | .with_arg(args)
76 | .call_and_wait()
77 | .await
78 | .unwrap();
79 |
80 | Decode!(&res, bool).map_err(|e| e.to_string()).unwrap()
81 | }
82 |
83 | pub async fn ws_close(agent: &Agent, canister_id: &Principal, can_client_id: u64) {
84 | let args = candid::encode_args((can_client_id,)).unwrap();
85 |
86 | let res = agent
87 | .update(canister_id, "ws_close")
88 | .with_arg(args)
89 | .call_and_wait()
90 | .await
91 | .unwrap();
92 |
93 | Decode!(&res, ()).map_err(|e| e.to_string()).unwrap()
94 | }
95 |
96 | pub async fn ws_message(agent: &Agent, canister_id: &Principal, mes: Vec) -> bool {
97 | let args = candid::encode_args((mes,)).unwrap();
98 |
99 | let res = agent
100 | .update(canister_id, "ws_message")
101 | .with_arg(args)
102 | .call_and_wait()
103 | .await
104 | .unwrap();
105 |
106 | Decode!(&res, bool).map_err(|e| e.to_string()).unwrap()
107 | }
108 |
109 | pub async fn ws_get_messages(agent: &Agent, canister_id: &Principal, nonce: u64) -> CertMessages {
110 | let args = candid::encode_args((nonce,))
111 | .map_err(|e| e.to_string())
112 | .unwrap();
113 |
114 | let res = agent
115 | .query(canister_id, "ws_get_messages")
116 | .with_arg(&args)
117 | .call()
118 | .await
119 | .unwrap();
120 |
121 | Decode!(&res, CertMessages)
122 | .map_err(|e| e.to_string())
123 | .unwrap()
124 | }
125 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/assets/main.css:
--------------------------------------------------------------------------------
1 | @import url("https://fonts.googleapis.com/css2?family=Montserrat:wght@400;500;600;700;800;900&family=Roboto:wght@400;700;900&family=Roboto+Mono&display=swap");
2 |
3 | :root {
4 | --base-padding: 1.2rem;
5 | }
6 |
7 | html {
8 | font-size: 62.5%;
9 | }
10 |
11 | body {
12 | font-family: Roboto, sans-serif;
13 | font-size: 1.4rem;
14 | margin: 0;
15 | }
16 |
17 | /* .material-symbols-outlined {
18 | font-variation-settings: "FILL" 0, "wght" 400, "GRAD" 0, "opsz" 48;
19 | } */
20 |
21 | .dfinity-logo {
22 | max-width: 41vw;
23 | max-height: 23vw;
24 | display: block;
25 | margin: 1.5rem auto 0;
26 | }
27 |
28 | .title {
29 | text-align: center;
30 | margin: 0 0 20px 0;
31 | font-family: "Roboto", sans-serif;
32 | font-weight: 900;
33 | font-size: 2.4rem;
34 | }
35 |
36 | .example-code {
37 | padding: 8px;
38 | background-color: #151515;
39 | text-align: center;
40 | font-size: 1.6rem;
41 | font-family: "Roboto Mono", monospace;
42 | display: block;
43 | margin: auto auto 16px;
44 | }
45 |
46 | .yellow {
47 | color: #dfab5c;
48 | }
49 |
50 | .blue {
51 | color: #77b7d7;
52 | }
53 |
54 | .white {
55 | color: #dfe2e7;
56 | }
57 |
58 | .purple {
59 | color: #977cdc;
60 | }
61 |
62 | .notifications-outer {
63 | padding: 0 var(--base-padding) var(--base-padding);
64 | max-width: 86rem;
65 | margin: auto;
66 | }
67 |
68 | .notifications {
69 | display: flex;
70 | flex-direction: column-reverse;
71 | justify-content: flex-end;
72 | /* align-items: flex-end; */
73 | /* border: 1px solid #222; */
74 | border-radius: 12px;
75 | padding: 30px 20px;
76 | background-color: #e2e8f0;
77 | min-height: 850px;
78 | }
79 |
80 | .notifications.inserting {
81 | transition: padding-top 0.55s cubic-bezier(0.37, 0, 0.63, 1);
82 | /* padding-top: calc(61.2px + 30px); */ /* 61.2 albo 93.4 */
83 | }
84 |
85 | .notification {
86 | background-color: #fbb03b;
87 | color: #fff;
88 | padding: 16px 90px 16px 16px;
89 | margin-bottom: 10px;
90 | border-radius: 8px;
91 | font-size: 1.6rem;
92 | font-family: "Montserrat", sans-serif;
93 | font-weight: 500;
94 | position: relative;
95 | /* min-width: 400px; */
96 | transition: opacity 0.15s ease-in-out;
97 | }
98 | .notification.transitioned {
99 | }
100 |
101 | .notification.appearing {
102 | opacity: 0;
103 | }
104 |
105 | .notification.appeared .notification-icon-bell {
106 | animation: 0.3s cubic-bezier(0.83, 0, 0.17, 1) 0.35s 4 tilt-shaking;
107 | }
108 |
109 | .notification:first-child {
110 | margin-bottom: 0;
111 | }
112 |
113 | .notification p {
114 | margin: 0 0 0 0;
115 | }
116 |
117 | .notification-title {
118 | font-size: 1.6rem;
119 | font-weight: 800;
120 | display: block;
121 | margin-bottom: 1.3rem;
122 | }
123 |
124 | .notification-title + p {
125 | /* font-weight: 600; */
126 | }
127 |
128 | .notification-icon-bell {
129 | position: absolute;
130 | top: 50%;
131 | transform: translate(0, -50%);
132 | right: 1.2rem;
133 | cursor: pointer;
134 | transition: all 0.5s;
135 | }
136 | .notification.transitioned .notification-icon-bell {
137 | opacity: 0;
138 | /* right: -2rem; */
139 | }
140 |
141 | .notification-time {
142 | position: absolute;
143 | top: 50%;
144 | right: 4.4rem;
145 | transform: translate(0, -50%);
146 | font-size: 1.4rem;
147 | transition: all 0.5s;
148 | }
149 | .notification.transitioned .notification-time {
150 | right: 1.4rem;
151 | }
152 |
153 | .icon {
154 | font-size: 2rem;
155 | }
156 |
157 | .notification-verified {
158 | font-size: 0.9rem;
159 | position: relative;
160 | color: #d1fae5;
161 | }
162 |
163 | .notification-verified .icon {
164 | font-size: 1.1em;
165 | position: relative;
166 | top: 0.17em;
167 | left: -0.1em;
168 | }
169 |
170 | @keyframes tilt-shaking {
171 | 0% {
172 | transform: translate(0, -50%) rotate(0deg);
173 | }
174 | 25% {
175 | transform: translate(0, -50%) rotate(15deg);
176 | }
177 | 50% {
178 | transform: translate(0, -50%) rotate(0deg);
179 | }
180 | 75% {
181 | transform: translate(0, -50%) rotate(-15deg);
182 | }
183 | 100% {
184 | transform: translate(0, -50%) rotate(0deg);
185 | }
186 | }
187 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require("path");
2 | const webpack = require("webpack");
3 | const HtmlWebpackPlugin = require("html-webpack-plugin");
4 | const TerserPlugin = require("terser-webpack-plugin");
5 | const CopyPlugin = require("copy-webpack-plugin");
6 |
7 | function initCanisterEnv() {
8 | let localCanisters, prodCanisters;
9 | try {
10 | localCanisters = require(path.resolve(
11 | ".dfx",
12 | "local",
13 | "canister_ids.json"
14 | ));
15 | } catch (error) {
16 | console.log("No local canister_ids.json found. Continuing production");
17 | }
18 | try {
19 | prodCanisters = require(path.resolve("canister_ids.json"));
20 | } catch (error) {
21 | console.log("No production canister_ids.json found. Continuing with local");
22 | }
23 |
24 | const network =
25 | process.env.DFX_NETWORK ||
26 | (process.env.NODE_ENV === "production" ? "ic" : "local");
27 |
28 | const canisterConfig = network === "local" ? localCanisters : prodCanisters;
29 |
30 | return Object.entries(canisterConfig).reduce((prev, current) => {
31 | const [canisterName, canisterDetails] = current;
32 | prev[canisterName.toUpperCase() + "_CANISTER_ID"] =
33 | canisterDetails[network];
34 | return prev;
35 | }, {});
36 | }
37 | const canisterEnvVariables = initCanisterEnv();
38 |
39 | const isDevelopment = process.env.NODE_ENV !== "production";
40 |
41 | const frontendDirectory = "ic_websocket_frontend";
42 |
43 | const frontend_entry = path.join("src", frontendDirectory, "src", "index.html");
44 |
45 | module.exports = {
46 | target: "web",
47 | mode: isDevelopment ? "development" : "production",
48 | entry: {
49 | // The frontend.entrypoint points to the HTML file for this build, so we need
50 | // to replace the extension to `.js`.
51 | index: path.join(__dirname, frontend_entry).replace(/\.html$/, ".js"),
52 | },
53 | devtool: isDevelopment ? "source-map" : false,
54 | optimization: {
55 | minimize: !isDevelopment,
56 | minimizer: [new TerserPlugin()],
57 | },
58 | resolve: {
59 | extensions: [".js", ".ts", ".jsx", ".tsx"],
60 | fallback: {
61 | assert: require.resolve("assert/"),
62 | buffer: require.resolve("buffer/"),
63 | events: require.resolve("events/"),
64 | stream: require.resolve("stream-browserify/"),
65 | util: require.resolve("util/"),
66 | },
67 | },
68 | output: {
69 | filename: "index.js",
70 | path: path.join(__dirname, "dist", frontendDirectory),
71 | },
72 |
73 | // Depending in the language or framework you are using for
74 | // front-end development, add module loaders to the default
75 | // webpack configuration. For example, if you are using React
76 | // modules and CSS as described in the "Adding a stylesheet"
77 | // tutorial, uncomment the following lines:
78 | // module: {
79 | // rules: [
80 | // { test: /\.(ts|tsx|jsx)$/, loader: "ts-loader" },
81 | // { test: /\.css$/, use: ['style-loader','css-loader'] }
82 | // ]
83 | // },
84 | plugins: [
85 | new HtmlWebpackPlugin({
86 | template: path.join(__dirname, frontend_entry),
87 | cache: false,
88 | }),
89 | new webpack.EnvironmentPlugin({
90 | NODE_ENV: "development",
91 | ...canisterEnvVariables,
92 | }),
93 | new webpack.ProvidePlugin({
94 | Buffer: [require.resolve("buffer/"), "Buffer"],
95 | process: require.resolve("process/browser"),
96 | }),
97 | new CopyPlugin({
98 | patterns: [
99 | {
100 | from: `src/${frontendDirectory}/src/.ic-assets.json*`,
101 | to: ".ic-assets.json5",
102 | noErrorOnMissing: true
103 | },
104 | ],
105 | }),
106 | ],
107 | // proxy /api to port 4943 during development.
108 | // if you edit dfx.json to define a project-specific local network, change the port to match.
109 | devServer: {
110 | proxy: {
111 | "/api": {
112 | target: "http://127.0.0.1:4943",
113 | changeOrigin: true,
114 | pathRewrite: {
115 | "^/api": "/api",
116 | },
117 | },
118 | },
119 | static: path.resolve(__dirname, "src", frontendDirectory, "assets"),
120 | hot: true,
121 | watchFiles: [path.resolve(__dirname, "src", frontendDirectory)],
122 | liveReload: true,
123 | },
124 | };
125 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_backend/src/lib.rs:
--------------------------------------------------------------------------------
1 | use ed25519_compact::{PublicKey, Signature};
2 | use ic_cdk::export::candid::CandidType;
3 | use ic_cdk_macros::*;
4 | use serde::{Deserialize, Serialize};
5 | use serde_cbor::from_slice;
6 |
7 | use canister::ws_on_message;
8 | use canister::ws_on_open;
9 | use sock::get_cert_messages;
10 | use sock::get_client_incoming_num;
11 | use sock::get_client_public_key;
12 | use sock::put_client_incoming_num;
13 | use sock::{
14 | delete_client, next_client_id, put_client_caller, put_client_gateway, put_client_public_key,
15 | wipe,
16 | };
17 |
18 | pub mod canister;
19 | pub mod sock;
20 |
21 | // Debug method. Wipes all data in the canister.
22 | #[update]
23 | fn ws_wipe() {
24 | wipe();
25 | }
26 |
27 | // Messages have the following required fields (both ways).
28 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
29 | #[candid_path("ic_cdk::export::candid")]
30 | pub struct WebsocketMessage {
31 | pub client_id: u64, // To or from client id.
32 | pub sequence_num: u64, // Both ways, messages should arrive with sequence numbers 0, 1, 2...
33 | pub timestamp: u64, // Timestamp of when the message was made for the recipient to inspect.
34 | #[serde(with = "serde_bytes")]
35 | pub message: Vec, // Application message encoded in binary.
36 | }
37 |
38 | // One message in the list returned to the gateway polling for messages.
39 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
40 | #[candid_path("ic_cdk::export::candid")]
41 | pub struct EncodedMessage {
42 | client_id: u64, // The client that the gateway will forward the message to.
43 | key: String, // Key for certificate verification.
44 | #[serde(with = "serde_bytes")]
45 | val: Vec, // Encoded WebsocketMessage.
46 | }
47 |
48 | // List of messages returned to the polling gateway.
49 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
50 | #[candid_path("ic_cdk::export::candid")]
51 | pub struct CertMessages {
52 | messages: Vec, // List of messages.
53 | #[serde(with = "serde_bytes")]
54 | cert: Vec, // cert+tree constitute the certificate for all returned messages.
55 | #[serde(with = "serde_bytes")]
56 | tree: Vec, // cert+tree constitute the certificate for all returned messages.
57 | }
58 |
59 | // Client submits its public key and gets a new client_id back.
60 | #[update]
61 | fn ws_register(public_key: Vec) -> u64 {
62 | let client_id = next_client_id();
63 | let client_key = PublicKey::from_slice(&public_key).unwrap();
64 | // Store the client key.
65 | put_client_public_key(client_id, client_key);
66 | // The identity (caller) used in this update call will be associated with this client_id. Remember this identity.
67 | put_client_caller(client_id);
68 | client_id
69 | }
70 |
71 | // A method for the gateway to get the client's public key and verify the signature of the first websocket message.
72 | #[query]
73 | pub fn ws_get_client_key(client_id: u64) -> Vec {
74 | get_client_public_key(client_id).unwrap().to_vec()
75 | }
76 |
77 | // The first message used in ws_open().
78 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq, Debug)]
79 | #[candid_path("ic_cdk::export::candid")]
80 | struct FirstMessage {
81 | client_id: u64,
82 | canister_id: String,
83 | }
84 |
85 | // Open the websocket connection.
86 | #[update]
87 | fn ws_open(msg: Vec, sig: Vec) -> bool {
88 | let decoded: FirstMessage = from_slice(&msg).unwrap();
89 |
90 | let client_id = decoded.client_id;
91 | let client_key = get_client_public_key(client_id).unwrap();
92 |
93 | let sig = Signature::from_slice(&sig).unwrap();
94 | let valid = client_key.verify(&msg, &sig);
95 |
96 | match valid {
97 | Ok(_) => {
98 | // Remember this gateway will get the messages for this client_id.
99 | put_client_gateway(client_id);
100 |
101 | ws_on_open(client_id);
102 | true
103 | }
104 | Err(_) => false,
105 | }
106 | }
107 |
108 | // Close the websocket connection.
109 | #[update]
110 | fn ws_close(client_id: u64) {
111 | delete_client(client_id);
112 | }
113 |
114 | // Encoded message + signature from client.
115 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
116 | #[candid_path("ic_cdk::export::candid")]
117 | struct ClientMessage {
118 | #[serde(with = "serde_bytes")]
119 | val: Vec,
120 | #[serde(with = "serde_bytes")]
121 | sig: Vec,
122 | }
123 |
124 | // Gateway calls this method to pass on the message from the client to the canister.
125 | #[update]
126 | fn ws_message(msg: Vec) -> bool {
127 | let decoded: ClientMessage = from_slice(&msg).unwrap();
128 | let content: WebsocketMessage = from_slice(&decoded.val).unwrap();
129 |
130 | let client_id = content.client_id;
131 |
132 | // Verify the signature.
133 | let client_key = get_client_public_key(client_id).unwrap();
134 | let sig = Signature::from_slice(&decoded.sig).unwrap();
135 | let valid = client_key.verify(&decoded.val, &sig);
136 |
137 | match valid {
138 | Ok(_) => {
139 | // Verify the message sequence number.
140 | if content.sequence_num == get_client_incoming_num(client_id) {
141 | put_client_incoming_num(client_id, content.sequence_num + 1);
142 | ws_on_message(content);
143 | true
144 | } else {
145 | false
146 | }
147 | }
148 | Err(_) => false,
149 | }
150 | }
151 |
152 | // Gateway polls this method to get messages for all the clients it serves.
153 | #[query]
154 | fn ws_get_messages(nonce: u64) -> CertMessages {
155 | get_cert_messages(nonce)
156 | }
157 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/src/websocketConnection.js:
--------------------------------------------------------------------------------
1 | import { ic_websocket_backend } from "../../declarations/ic_websocket_backend";
2 |
3 | import {
4 | Cbor,
5 | // Certificate,
6 | // HashTree,
7 | HttpAgent
8 | // lookup_path,
9 | // reconstruct,
10 | // compare
11 | } from "@dfinity/agent";
12 | import { Principal } from "@dfinity/principal";
13 | import addNotification from "./utils/addNotification.js";
14 | // import { lebDecode } from "@dfinity/candid";
15 | // import { PipeArrayBuffer } from "@dfinity/candid/lib/cjs/utils/buffer";
16 |
17 | import * as ed from '@noble/ed25519';
18 |
19 | import validateBody from "./utils/validateBody";
20 |
21 | export default class websocketConnection {
22 | constructor(canister_id, gateway_address, network_url, local_test) {
23 | this.canister_id = canister_id;
24 | this.next_received_num = 0; // Received signed messages need to come in the correct order, with sequence numbers 0, 1, 2...
25 | this.instance = new WebSocket(gateway_address); // Gateway address. Here localhost to reproduce the demo.
26 | this.instance.binaryType = "arraybuffer";
27 | this.bindEvents();
28 | this.key = ed.utils.randomPrivateKey(); // Generate new key for this websocket connection.
29 | this.agent = new HttpAgent({ host: network_url });
30 | if (local_test) {
31 | this.agent.fetchRootKey();
32 | }
33 | }
34 |
35 | async make_message(text) {
36 | // Our demo application uses simple text message.
37 | let content = Cbor.encode({
38 | text: text,
39 | });
40 |
41 | // Message with all required fields.
42 | let websocket_message = Cbor.encode({
43 | client_id: this.client_id, // client_id given by the canister
44 | sequence_num: this.sequence_num, // Next sequence number to ensure correct order.
45 | timestamp: Date.now() * 1000000,
46 | message: content, // Binary application message.
47 | });
48 |
49 | // Sign the message
50 | let to_sign = new Uint8Array(websocket_message);
51 | let sig = await ed.sign(to_sign, this.key);
52 |
53 | // Final signed websocket message
54 | let message = {
55 | val: websocket_message,
56 | sig: sig,
57 | };
58 |
59 | // Send CBOR encoded
60 | let ws_message = Cbor.encode(message);
61 | return ws_message;
62 | }
63 |
64 | sendMessage(message) {
65 | console.log("Sending to canister.");
66 | this.instance.send(message);
67 | this.sequence_num += 1;
68 | }
69 |
70 | bindEvents() {
71 | this.instance.onopen = this.onOpen.bind(this);
72 | this.instance.onmessage = this.onMessage.bind(this);
73 | this.instance.onclose = this.onClose.bind(this);
74 | this.instance.onerror = this.onError.bind(this);
75 | }
76 |
77 | async onOpen(event) {
78 | console.log("[open] Connection opened");
79 | // Put the public key in the canister. Get client_id from the canister.
80 | const publicKey = await ed.getPublicKey(this.key);
81 | let client_id = Number(await ic_websocket_backend.ws_register(publicKey));
82 | this.client_id = client_id;
83 | this.sequence_num = 0;
84 |
85 | // Send the first message with client and canister id
86 | let cbor_content = Cbor.encode({
87 | client_id: client_id,
88 | canister_id: this.canister_id,
89 | });
90 |
91 | // Sign so that the gateway can verify canister and client ids match
92 | let to_sign = new Uint8Array(cbor_content);
93 | let sig = await ed.sign(to_sign, this.key);
94 |
95 | let first_message = {
96 | client_canister_id: cbor_content,
97 | sig: sig,
98 | };
99 |
100 | // Send the first message
101 | let ws_message = Cbor.encode(first_message);
102 | this.sendMessage(ws_message);
103 | this.sequence_num = 0;
104 | }
105 |
106 | async onMessage(event) {
107 | const res = Cbor.decode(event.data);
108 |
109 | let key, val, cert, tree;
110 | key = res.key;
111 | val = new Uint8Array(res.val);
112 | cert = res.cert;
113 | tree = res.tree;
114 | let websocketMsg = Cbor.decode(val);
115 |
116 | // Check the sequence number
117 | let received_num = websocketMsg.sequence_num;
118 | if (received_num != this.next_received_num) {
119 | console.log(`Received message sequence number (${received_num}) does not match next expected value (${this.next_received_num}). Message ignored.`);
120 | return;
121 | }
122 | this.next_received_num += 1;
123 |
124 | // Inspect the timestamp
125 | let time = websocketMsg.timestamp;
126 | let delay_s = (Date.now() * (10 ** 6) - time) / (10 ** 9);
127 | console.log(`(time now) - (message timestamp) = ${delay_s}s`);
128 |
129 | // Verify the certificate (canister signature)
130 | let principal = Principal.fromText(this.canister_id);
131 | let valid = await validateBody(principal, key, val, cert, tree, this.agent);
132 | console.log(`Certificate validation: ${valid}`);
133 | if (!valid) {
134 | console.log(`Message ignored.`);
135 | return;
136 | }
137 |
138 | // Message has been verified
139 | let appMsg = Cbor.decode(websocketMsg.message);
140 | let text = appMsg.text;
141 | console.log(`[message] Message from canister: ${text}`);
142 | addNotification(text);
143 | this.sendMessage(await this.make_message(text + "-pong"));
144 | }
145 |
146 | onClose(event) {
147 | if (event.wasClean) {
148 | console.log(
149 | `[close] Connection closed, code=${event.code} reason=${event.reason}`
150 | );
151 | } else {
152 | console.log("[close] Connection died");
153 | }
154 | }
155 |
156 | onError(error) {
157 | console.log(`[error]`);
158 | }
159 | }
160 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_backend/src/sock.rs:
--------------------------------------------------------------------------------
1 | use ed25519_compact::PublicKey;
2 | use ic_cdk::api::{caller, data_certificate, set_certified_data, time};
3 | use ic_certified_map::{labeled, labeled_hash, AsHashTree, Hash as ICHash, RbTree};
4 | use serde::Serialize;
5 | use serde_cbor::Serializer;
6 | use sha2::{Digest, Sha256};
7 | use std::{
8 | cell::RefCell, collections::HashMap, collections::VecDeque, convert::AsRef, time::Duration,
9 | };
10 |
11 | use crate::{CertMessages, EncodedMessage, WebsocketMessage};
12 |
13 | const LABEL_WEBSOCKET: &[u8] = b"websocket";
14 | const MSG_TIMEOUT: Duration = Duration::from_secs(5 * 60);
15 | const MAX_NUMBER_OF_RETURNED_MESSAGES: usize = 50;
16 |
17 | pub struct KeyGatewayTime {
18 | key: String,
19 | gateway: String,
20 | time: u64,
21 | }
22 |
23 | thread_local! {
24 | static NEXT_CLIENT_ID: RefCell = RefCell::new(16u64);
25 | static CLIENT_CALLER_MAP: RefCell> = RefCell::new(HashMap::new());
26 | static CLIENT_PUBLIC_KEY_MAP: RefCell> = RefCell::new(HashMap::new());
27 | static CLIENT_GATEWAY_MAP: RefCell> = RefCell::new(HashMap::new());
28 | static CLIENT_MESSAGE_NUM_MAP: RefCell> = RefCell::new(HashMap::new());
29 | static CLIENT_INCOMING_NUM_MAP: RefCell> = RefCell::new(HashMap::new());
30 | static GATEWAY_MESSAGES_MAP: RefCell>> = RefCell::new(HashMap::new());
31 | static MESSAGE_DELETE_QUEUE: RefCell> = RefCell::new(VecDeque::new());
32 | static CERT_TREE: RefCell> = RefCell::new(RbTree::new());
33 | static NEXT_MESSAGE_NONCE: RefCell = RefCell::new(16u64);
34 | }
35 |
36 | pub fn wipe() {
37 | NEXT_CLIENT_ID.with(|next_id| next_id.replace(16u64));
38 | CLIENT_CALLER_MAP.with(|map| {
39 | map.borrow_mut().clear();
40 | });
41 | CLIENT_PUBLIC_KEY_MAP.with(|map| {
42 | map.borrow_mut().clear();
43 | });
44 | CLIENT_GATEWAY_MAP.with(|map| {
45 | map.borrow_mut().clear();
46 | });
47 | CLIENT_MESSAGE_NUM_MAP.with(|map| {
48 | map.borrow_mut().clear();
49 | });
50 | CLIENT_INCOMING_NUM_MAP.with(|map| {
51 | map.borrow_mut().clear();
52 | });
53 | GATEWAY_MESSAGES_MAP.with(|map| {
54 | map.borrow_mut().clear();
55 | });
56 | MESSAGE_DELETE_QUEUE.with(|vd| {
57 | vd.borrow_mut().clear();
58 | });
59 | CERT_TREE.with(|t| {
60 | t.replace(RbTree::new());
61 | });
62 | NEXT_MESSAGE_NONCE.with(|next_id| next_id.replace(16u64));
63 | }
64 |
65 | pub fn next_client_id() -> u64 {
66 | NEXT_CLIENT_ID.with(|next_id| next_id.replace_with(|&mut old| old + 1))
67 | }
68 |
69 | fn next_message_nonce() -> u64 {
70 | NEXT_MESSAGE_NONCE.with(|n| n.replace_with(|&mut old| old + 1))
71 | }
72 |
73 | pub fn put_client_public_key(client_id: u64, client_key: PublicKey) {
74 | CLIENT_PUBLIC_KEY_MAP.with(|map| {
75 | map.borrow_mut().insert(client_id, client_key);
76 | })
77 | }
78 |
79 | pub fn get_client_public_key(client_id: u64) -> Option {
80 | CLIENT_PUBLIC_KEY_MAP.with(|map| map.borrow().get(&client_id).cloned())
81 | }
82 |
83 | pub fn put_client_caller(client_id: u64) {
84 | CLIENT_CALLER_MAP.with(|map| {
85 | map.borrow_mut().insert(client_id, caller().to_string());
86 | })
87 | }
88 |
89 | pub fn put_client_gateway(client_id: u64) {
90 | CLIENT_GATEWAY_MAP.with(|map| {
91 | map.borrow_mut().insert(client_id, caller().to_string());
92 | })
93 | }
94 |
95 | pub fn get_client_gateway(client_id: u64) -> Option {
96 | CLIENT_GATEWAY_MAP.with(|map| map.borrow().get(&client_id).cloned())
97 | }
98 |
99 | pub fn next_client_message_num(client_id: u64) -> u64 {
100 | CLIENT_MESSAGE_NUM_MAP.with(|map| {
101 | let mut map = map.borrow_mut();
102 | match map.get(&client_id).cloned() {
103 | None => {
104 | map.insert(client_id, 0);
105 | 0
106 | }
107 | Some(num) => {
108 | map.insert(client_id, num + 1);
109 | num + 1
110 | }
111 | }
112 | })
113 | }
114 |
115 | pub fn get_client_incoming_num(client_id: u64) -> u64 {
116 | CLIENT_INCOMING_NUM_MAP.with(|map| *map.borrow().get(&client_id).unwrap_or(&0))
117 | }
118 |
119 | pub fn put_client_incoming_num(client_id: u64, num: u64) {
120 | CLIENT_INCOMING_NUM_MAP.with(|map| {
121 | map.borrow_mut().insert(client_id, num);
122 | })
123 | }
124 |
125 | pub fn delete_client(client_id: u64) {
126 | CLIENT_CALLER_MAP.with(|map| {
127 | map.borrow_mut().remove(&client_id);
128 | });
129 | CLIENT_PUBLIC_KEY_MAP.with(|map| {
130 | map.borrow_mut().remove(&client_id);
131 | });
132 | CLIENT_GATEWAY_MAP.with(|map| {
133 | map.borrow_mut().remove(&client_id);
134 | });
135 | CLIENT_MESSAGE_NUM_MAP.with(|map| {
136 | map.borrow_mut().remove(&client_id);
137 | });
138 | CLIENT_INCOMING_NUM_MAP.with(|map| {
139 | map.borrow_mut().remove(&client_id);
140 | });
141 | }
142 |
143 | pub fn get_cert_messages(nonce: u64) -> CertMessages {
144 | GATEWAY_MESSAGES_MAP.with(|s| {
145 | let gateway = caller().to_string();
146 |
147 | let mut s = s.borrow_mut();
148 | let gateway_messages_vec = match s.get_mut(&gateway) {
149 | None => {
150 | s.insert(gateway.clone(), VecDeque::new());
151 | s.get_mut(&gateway).unwrap()
152 | }
153 | Some(map) => map,
154 | };
155 |
156 | let smallest_key = gateway.clone() + "_" + &format!("{:0>20}", nonce.to_string());
157 | let start_index = gateway_messages_vec.partition_point(|x| x.key < smallest_key);
158 | let mut end_index = start_index;
159 | while (end_index < gateway_messages_vec.len())
160 | && (end_index < start_index + MAX_NUMBER_OF_RETURNED_MESSAGES)
161 | {
162 | end_index += 1;
163 | }
164 | let mut messages: Vec = Vec::with_capacity(end_index - start_index);
165 | for index in 0..(end_index - start_index) {
166 | messages.push(
167 | gateway_messages_vec
168 | .get(start_index + index)
169 | .unwrap()
170 | .clone(),
171 | );
172 | }
173 | if end_index > start_index {
174 | let first_key = messages.first().unwrap().key.clone();
175 | let last_key = messages.last().unwrap().key.clone();
176 | let (cert, tree) = get_cert_for_range(&first_key, &last_key);
177 | CertMessages {
178 | messages,
179 | cert,
180 | tree,
181 | }
182 | } else {
183 | CertMessages {
184 | messages,
185 | cert: Vec::new(),
186 | tree: Vec::new(),
187 | }
188 | }
189 | })
190 | }
191 |
192 | pub fn delete_message(message_info: &KeyGatewayTime) {
193 | GATEWAY_MESSAGES_MAP.with(|s| {
194 | let mut s = s.borrow_mut();
195 | let gateway_messages = s.get_mut(&message_info.gateway).unwrap();
196 | gateway_messages.pop_front();
197 | });
198 | CERT_TREE.with(|t| {
199 | t.borrow_mut().delete(message_info.key.as_ref());
200 | });
201 | }
202 |
203 | pub fn send_message_from_canister(client_id: u64, msg: Vec) {
204 | let gateway = match get_client_gateway(client_id) {
205 | None => {
206 | return;
207 | }
208 | Some(gateway) => gateway,
209 | };
210 |
211 | let time = time();
212 | let key = gateway.clone() + "_" + &format!("{:0>20}", next_message_nonce().to_string());
213 |
214 | MESSAGE_DELETE_QUEUE.with(|q| {
215 | let mut q = q.borrow_mut();
216 | q.push_back(KeyGatewayTime {
217 | key: key.clone(),
218 | gateway: gateway.clone(),
219 | time,
220 | });
221 |
222 | let front = q.front().unwrap();
223 | if Duration::from_nanos(time - front.time) > MSG_TIMEOUT {
224 | delete_message(front);
225 | q.pop_front();
226 |
227 | let front = q.front().unwrap();
228 | if Duration::from_nanos(time - front.time) > MSG_TIMEOUT {
229 | delete_message(front);
230 | q.pop_front();
231 | }
232 | }
233 | });
234 |
235 | let input = WebsocketMessage {
236 | client_id,
237 | sequence_num: next_client_message_num(client_id),
238 | timestamp: time,
239 | message: msg,
240 | };
241 |
242 | let mut data = vec![];
243 | let mut serializer = Serializer::new(&mut data);
244 | serializer.self_describe().unwrap();
245 | input.serialize(&mut serializer).unwrap();
246 |
247 | put_cert_for_message(key.clone(), &data);
248 | GATEWAY_MESSAGES_MAP.with(|s| {
249 | let mut s = s.borrow_mut();
250 | let gw_map = match s.get_mut(&gateway) {
251 | None => {
252 | s.insert(gateway.clone(), VecDeque::new());
253 | s.get_mut(&gateway).unwrap()
254 | }
255 | Some(map) => map,
256 | };
257 | gw_map.push_back(EncodedMessage {
258 | client_id,
259 | key,
260 | val: data,
261 | });
262 | });
263 | }
264 |
265 | fn put_cert_for_message(key: String, value: &Vec) {
266 | let root_hash = CERT_TREE.with(|tree| {
267 | let mut tree = tree.borrow_mut();
268 | tree.insert(key.clone(), Sha256::digest(value).into());
269 | labeled_hash(LABEL_WEBSOCKET, &tree.root_hash())
270 | });
271 |
272 | set_certified_data(&root_hash);
273 | }
274 |
275 | pub fn get_cert_for_message(key: &String) -> (Vec, Vec) {
276 | CERT_TREE.with(|tree| {
277 | let tree = tree.borrow();
278 | let witness = tree.witness(key.as_ref());
279 | let tree = labeled(LABEL_WEBSOCKET, witness);
280 |
281 | let mut data = vec![];
282 | let mut serializer = Serializer::new(&mut data);
283 | serializer.self_describe().unwrap();
284 | tree.serialize(&mut serializer).unwrap();
285 | (data_certificate().unwrap(), data)
286 | })
287 | }
288 |
289 | pub fn get_cert_for_range(first: &String, last: &String) -> (Vec, Vec) {
290 | CERT_TREE.with(|tree| {
291 | let tree = tree.borrow();
292 | let witness = tree.value_range(first.as_ref(), last.as_ref());
293 | let tree = labeled(LABEL_WEBSOCKET, witness);
294 |
295 | let mut data = vec![];
296 | let mut serializer = Serializer::new(&mut data);
297 | serializer.self_describe().unwrap();
298 | tree.serialize(&mut serializer).unwrap();
299 | (data_certificate().unwrap(), data)
300 | })
301 | }
302 |
--------------------------------------------------------------------------------
/ic_websocket_gateway/src/main.rs:
--------------------------------------------------------------------------------
1 | use async_trait::async_trait;
2 | use candid::CandidType;
3 | use ed25519_compact::Signature;
4 | use ezsockets::{Error, Server, Socket};
5 | use ic_agent::{export::Principal, identity::BasicIdentity, Agent};
6 | use serde::{Deserialize, Serialize};
7 | use serde_cbor::{from_slice, to_vec};
8 | use std::{
9 | collections::HashMap,
10 | net::SocketAddr,
11 | sync::{Arc, Mutex},
12 | time::Duration,
13 | };
14 |
15 | mod canister_methods;
16 |
17 | type SessionID = u64;
18 | type Session = ezsockets::Session;
19 |
20 | // url for local testing
21 | // for local testing also the agent needs to fetch the root key
22 | const URL: &str = "http://127.0.0.1:4943";
23 | const FETCH_KEY: bool = true;
24 |
25 | // url for mainnet
26 | // const URL: &str = "https://ic0.app";
27 | // const FETCH_KEY: bool = false;
28 |
29 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq, Debug)]
30 | #[candid_path("ic_cdk::export::candid")]
31 | struct FirstMessageFromClient {
32 | #[serde(with = "serde_bytes")]
33 | client_canister_id: Vec,
34 | #[serde(with = "serde_bytes")]
35 | sig: Vec,
36 | }
37 |
38 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq, Debug)]
39 | #[candid_path("ic_cdk::export::candid")]
40 | struct ClientCanisterId {
41 | client_id: u64,
42 | canister_id: String,
43 | }
44 |
45 | #[derive(Debug)]
46 | struct GatewaySession {
47 | id: SessionID,
48 | handle: Session,
49 | server_handle: Server,
50 | agent: Agent,
51 |
52 | canister_connected: bool,
53 | client_id: Option,
54 | canister_id: Option,
55 | }
56 |
57 | #[async_trait]
58 | impl ezsockets::SessionExt for GatewaySession {
59 | type ID = SessionID;
60 | type Args = ();
61 | type Params = ();
62 |
63 | fn id(&self) -> &Self::ID {
64 | &self.id
65 | }
66 |
67 | async fn text(&mut self, _text: String) -> Result<(), Error> {
68 | unimplemented!()
69 | }
70 |
71 | async fn binary(&mut self, bytes: Vec) -> Result<(), Error> {
72 | if !self.canister_connected {
73 | let m: FirstMessageFromClient = from_slice(&bytes).unwrap();
74 | let content: ClientCanisterId = from_slice(&m.client_canister_id).unwrap();
75 | let canister_id = Principal::from_text(&content.canister_id).unwrap();
76 |
77 | let client_key =
78 | canister_methods::ws_get_client_key(&self.agent, &canister_id, content.client_id)
79 | .await;
80 | let sig = Signature::from_slice(&m.sig).unwrap();
81 | let valid = client_key.verify(&m.client_canister_id, &sig);
82 |
83 | match valid {
84 | Ok(_) => {
85 | self.canister_connected = true;
86 | self.client_id = Some(content.client_id);
87 | self.canister_id = Some(canister_id);
88 |
89 | self.server_handle.call(ConnectCanister {
90 | session_id: self.id,
91 | session: self.handle.clone(),
92 | canister_id: content.canister_id,
93 | canister_client_id: content.client_id,
94 | });
95 | let ret = canister_methods::ws_open(
96 | &self.agent,
97 | &canister_id,
98 | m.client_canister_id,
99 | m.sig,
100 | )
101 | .await;
102 | println!("ws_open:{}", ret);
103 | }
104 | Err(_) => println!("Client's signature does not verify."),
105 | }
106 | } else {
107 | println!("Message from client #{}", self.client_id.unwrap());
108 | canister_methods::ws_message(&self.agent, &self.canister_id.unwrap(), bytes).await;
109 | }
110 | Ok(())
111 | }
112 |
113 | async fn call(&mut self, params: ()) -> Result<(), Error> {
114 | let () = params;
115 | Ok(())
116 | }
117 | }
118 |
119 | #[derive(Debug)]
120 | struct ConnectCanister {
121 | session_id: u64,
122 | session: Session,
123 | canister_id: String,
124 | canister_client_id: u64,
125 | }
126 |
127 | #[derive(Debug)]
128 | struct CanisterPoller {
129 | canister_id: String,
130 | canister_client_session_map: Arc>>,
131 | identity: Arc,
132 | }
133 |
134 | #[derive(CandidType, Clone, Deserialize, Serialize, Eq, PartialEq)]
135 | pub struct CertMessage {
136 | pub key: String,
137 | #[serde(with = "serde_bytes")]
138 | pub val: Vec,
139 | #[serde(with = "serde_bytes")]
140 | pub cert: Vec,
141 | #[serde(with = "serde_bytes")]
142 | pub tree: Vec,
143 | }
144 |
145 | impl CanisterPoller {
146 | async fn run_polling(&self) {
147 | println!("Start of polling.");
148 | let can_map = Arc::clone(&self.canister_client_session_map);
149 | let agent = canister_methods::get_new_agent(URL, self.identity.clone(), FETCH_KEY).await;
150 | let canister_id = Principal::from_text(&self.canister_id).unwrap();
151 | tokio::spawn({
152 | let interval = Duration::from_millis(200);
153 | let mut nonce: u64 = 0;
154 | async move {
155 | loop {
156 | let msgs = canister_methods::ws_get_messages(&agent, &canister_id, nonce).await;
157 |
158 | for encoded_message in msgs.messages {
159 | let client_id = encoded_message.client_id;
160 |
161 | println!(
162 | "Message to client #{} with key {}.",
163 | client_id, encoded_message.key
164 | );
165 |
166 | let map = can_map.lock().unwrap();
167 | let s = map.get(&client_id).unwrap();
168 |
169 | let m = CertMessage {
170 | key: encoded_message.key.clone(),
171 | val: encoded_message.val,
172 | cert: msgs.cert.clone(),
173 | tree: msgs.tree.clone(),
174 | };
175 |
176 | if s.alive() {
177 | s.binary(to_vec(&m).unwrap());
178 | }
179 |
180 | nonce = encoded_message
181 | .key
182 | .split('_')
183 | .last()
184 | .unwrap()
185 | .parse()
186 | .unwrap();
187 | nonce += 1
188 | }
189 |
190 | tokio::time::sleep(interval).await;
191 | }
192 | }
193 | });
194 | }
195 |
196 | fn add_session(&self, canister_client_id: u64, session: Session) {
197 | let map = &self.canister_client_session_map;
198 | let mut m = map.lock().unwrap();
199 | m.insert(canister_client_id, session);
200 | }
201 | }
202 |
203 | #[derive(Debug)]
204 | struct GatewayServer {
205 | next_session_id: u64,
206 | handle: Server,
207 | connected_canisters: HashMap,
208 | identity: Arc,
209 | close_args: HashMap,
210 | agent: Agent,
211 | }
212 |
213 | #[async_trait]
214 | impl ezsockets::ServerExt for GatewayServer {
215 | type Params = ConnectCanister;
216 | type Session = GatewaySession;
217 |
218 | async fn accept(
219 | &mut self,
220 | socket: Socket,
221 | _address: SocketAddr,
222 | _args: (),
223 | ) -> Result {
224 | let id = self.next_session_id;
225 | self.next_session_id += 1;
226 | println!("Client connected.");
227 | let agent = canister_methods::get_new_agent(URL, self.identity.clone(), FETCH_KEY).await;
228 |
229 | let session = Session::create(
230 | |handle| GatewaySession {
231 | id,
232 | handle,
233 | server_handle: self.handle.clone(),
234 | agent,
235 |
236 | canister_connected: false,
237 | client_id: None,
238 | canister_id: None,
239 | },
240 | id,
241 | socket,
242 | );
243 |
244 | Ok(session)
245 | }
246 |
247 | async fn disconnected(
248 | &mut self,
249 | id: ::ID,
250 | ) -> Result<(), Error> {
251 | let close_args = self.close_args.remove(&id).unwrap();
252 | println!("Websocket with client #{} closed.", close_args.client_id);
253 | let canister_id = Principal::from_text(&close_args.canister_id).unwrap();
254 | canister_methods::ws_close(&self.agent, &canister_id, close_args.client_id).await;
255 | Ok(())
256 | }
257 |
258 | async fn call(&mut self, add_canister: Self::Params) -> Result<(), Error> {
259 | let canister_id = add_canister.canister_id;
260 | let session = add_canister.session;
261 | let canister_client_id = add_canister.canister_client_id;
262 |
263 | self.close_args.insert(
264 | add_canister.session_id,
265 | ClientCanisterId {
266 | client_id: canister_client_id,
267 | canister_id: canister_id.clone(),
268 | },
269 | );
270 |
271 | match self.connected_canisters.get_mut(&canister_id) {
272 | None => {
273 | let identity = self.identity.clone();
274 | let poller = CanisterPoller {
275 | canister_id: canister_id.clone(),
276 | canister_client_session_map: Arc::new(Mutex::new(HashMap::new())),
277 | identity,
278 | };
279 | poller.add_session(canister_client_id, session);
280 | poller.run_polling().await;
281 | self.connected_canisters.insert(canister_id, poller);
282 | }
283 | Some(poller) => {
284 | poller.add_session(canister_client_id, session);
285 | }
286 | }
287 |
288 | Ok(())
289 | }
290 | }
291 |
292 | #[tokio::main(flavor = "multi_thread", worker_threads = 10)]
293 | async fn main() {
294 | let rng = ring::rand::SystemRandom::new();
295 | let key_pair = ring::signature::Ed25519KeyPair::generate_pkcs8(&rng)
296 | .expect("Could not generate a key pair.");
297 | let identity = BasicIdentity::from_key_pair(
298 | ring::signature::Ed25519KeyPair::from_pkcs8(key_pair.as_ref())
299 | .expect("Could not read the key pair."),
300 | );
301 | let identity = Arc::new(identity);
302 | let agent = canister_methods::get_new_agent(URL, identity.clone(), FETCH_KEY).await;
303 | agent.fetch_root_key().await.unwrap();
304 |
305 | let (server, _) = Server::create(|handle| GatewayServer {
306 | next_session_id: 0,
307 | handle,
308 | connected_canisters: HashMap::new(),
309 | identity,
310 | close_args: HashMap::new(),
311 | agent,
312 | });
313 | ezsockets::tungstenite::run(server, "127.0.0.1:8080", |_| async move { Ok(()) })
314 | .await
315 | .unwrap();
316 | }
317 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Introduction
2 |
3 | WebSockets enable web applications to maintain a full-duplex connection between the backend and the frontend. This allows for many different use-cases, such as notifications, dynamic content updates (e.g., showing new comments/likes on a post), collaborative editing, etc.
4 |
5 | At the moment, WebSockets are not supported for dapps on the Internet Computer and developers need to resort to work-arounds in the frontend to enable a similar functionality.
6 |
7 | This repository contains a proof-of-concept implementation for WebSockets on the Internet Computer. This proof-of-concept uses an intermediary service that provides a WebSocket endpoint to the dapp frontend and interfaces with the canister backend hosted on the IC.
8 |
9 | In the following, we provide an overview of the architecture and the instructions to run it yourself.
10 |
11 | # Running the demo locally
12 |
13 | 1. Run a local replica: `dfx start`
14 | 2. Run the gateway: navigate to ic_websocket_gateway and `cargo run`
15 | 3. Deploy the canisters to the local replica:
16 | - navigate to ic_websocket_canisters,
17 | - `npm install`,
18 | - `dfx deploy`,
19 | - put the correct backend canister id in index.js of the frontend canister,
20 | - `dfx deploy`.
21 | 4. Look at the frontend canister with the link given by dfx.
22 |
23 | # Contributing
24 |
25 | This repository accepts external contributions if you accept the Contributor Lincense Agreement: https://github.com/dfinity/cla/.
26 |
27 | # Overview
28 |
29 | 
30 |
31 | In order to enable WebSockets for a dapp running on the IC, we use an intermediary, which we call gateway, that provides a WebSocket endpoint for the frontend of the dapp, running in the user’s browser and interfaces with the canister backend.
32 |
33 | The gateway is needed as a WebSocket is a one-to-one connection between client and server, but the Internet Computer does not support that due to its replicated nature. The gateway translates all messages coming in on the WebSocket from the client to API canister calls for the backend and sends all messages coming from the backend on the Internet Computer out on the WebSocket with the corresponding client.
34 |
35 | # Features
36 |
37 | * General: A gateway can provide WebSockets for many different dapps at the same time. A frontend can connect through any gateway to the backend (e.g., through the geographically closest one to reduce latency).
38 | * Trustless: In order to make it impossible for the gateway to tamper with messages:
39 | - all messages are signed: messages sent by the canister are [certified](https://internetcomputer.org/how-it-works/response-certification/); messages sent by the client signed by it;
40 | - all messages have a sequence number to guarantee all messages are received in the correct order;
41 | - all messages are accompanied by a timestamp.
42 |
43 | * IMPORTANT CAVEAT: NO ENCRYPTION!
44 | No single replica can be assumed to be trusted, so the canister state cannot be assumed to be kept secret. This means that when exchanging messages with the canister, we have to keep in mind that in principle the messages could be seen by others on the canister side.
45 | We could encrypt the messages between the client and the canister (so that they’re hidden from the gateway and any other party that cannot see the canister state), but we chose not to do so to make it clear that **in principle the messages could be seen by others on the canister side**.
46 |
47 | # Components
48 |
49 | 1. Client:
50 |
51 | Client is the user that opens the websocket to communicate with a canister. Client will sign its messages.
52 | - Generates a public/private ed25519 key pair.
53 | - Makes an update call to the canister to register the public key. Canister remembers the caller associated with this key. The call returns client_id.
54 | - Opens a websocket to the given gateway address.
55 | - Sends the first message with its client_id and the canister it wants to connect to. The message is signed with the private key.
56 | - Receives certified canister messages from the websocket.
57 | - Sends messages to the canister to the websocket. Messages are signed with the private key.
58 |
59 | 2. Gateway:
60 |
61 | Gateway accepts websocket connections to enable clients to communicate with canisters with websockets. Gateway can only pass on messages between clients and canisters and cannot forge messages.
62 | - Accepts websocket connections.
63 | - Expects the first message from the websocket to contain canister_id and client_id, signed.
64 | - Makes an update call ws_open to the canister with the given id passing on the message. The method returns true if the canister correctly verifies the signature with the previously registered client_id. If the method returns false, the websocket is dropped.
65 | - If ws_open returns true, the gateway spawns a polling task that makes query calls to ws_get_messages.
66 | - ws_get_messages returns certified messages from the canister to the clients that opened the websocket with this gateway. The gateway sends respective messages to the clients over the websockets.
67 | - After receiving messages, the polling task increases the message nonce to receive later messages.
68 | - Forwards signed client messages received over the websocket to the canister with ws_message.
69 | - The gateway calls ws_close when the websocket with the client closes for any reason.
70 |
71 | 3. Backend canister:
72 |
73 | The backend canister exposes an interface that makes it possible for the gateway to facilitate websocket connections with clients.
74 | - Receives client public keys. Records the caller associated with the given public key.
75 | - Receives calls to ws_open. Verifies that the provided signature corresponds to the given client_id. Records the caller as the gateway that will poll for messages.
76 | - Receives client messages to ws_message. Verifies that the provided signature corresponds to the recorded client_id.
77 | - Queues outgoing messages in queues corresponding to the recorded gateways. Puts the associated hashes in ic_certified_map to produce certificates.
78 | - Upon queuing outgoing messages, the canister deletes up to two past messages from the queues and the corresponding hashes from the certified map if the messages were sent at least five minutes prior.
79 | - When ws_close is called by the gateway corresponding to the provided client_id, the client info is deleted.
80 |
81 | # Message flow
82 |
83 | 
84 |
85 | 1. Client generates an ed25519 key pair and makes an update call to the canister to register the public key. Canister remembers the caller associated with this key. The call returns client_id.
86 | 2. Client opens a websocket with the gateway.
87 | 3. Client sends the first message with its client_id and the canister_id it wants to connect to. The message is signed with the private key.
88 | 4. The gateway makes an update call ws_open to the canister with the given id passing on the message. The method returns true if the canister correctly verifies the signature with the previously registered client_id.
89 | 5. Client composes a message and signs it. Client sends the message to the gateway over the websocket. The gateway makes an update call to forward the message to the canister.
90 |
91 | In the other direction, the canister composes a message and places its hash in the certified data structure. The gateway polls for messages and retrieves the message together with the certificate. The gateway passes on the message and the certificate to the client over the websocket.
92 | 6. Whenever the websocket with the client is closed, the gateway calls ws_close. Afterwards no more messages can be sent from the canister to the client.
93 |
94 | # Backend canister interface
95 |
96 | * **"ws_register": (blob) -> (nat64);**
97 |
98 | Client submits its public key in binary before opening the websocket. Method returns client_id.
99 | * **"ws_get_client_key": (nat64) -> (blob);**
100 |
101 | Gateway calls this method to get a client’s public key, in order to verify its signature and accept the client’s websocket connection as valid.
102 | * **"ws_open": (blob, blob) -> (bool);**
103 |
104 | Gateway calls this method to register to poll for client’s messages. First argument is the cbor encoding of
105 | ```
106 | {
107 | client_id: u64,
108 | canister_id: String,
109 | }
110 | ```
111 | The second argument is the signature of the first argument corresponding to the client_id.
112 | * **"ws_close": (nat64) -> ();**
113 |
114 | The gateway calls this method to close the websocket corresponding to the given client_id. The canister deletes the clients data and afterwards cannot queue any more messages for the client.
115 | * **"ws_get_messages": (nat64) -> (CertMessages) query;**
116 |
117 | The canister returns the messages with the following fields:
118 | - `client_id: u64`
119 | Client will check the message is indeed for them.
120 | - `sequence_num: u64`
121 | Client will check all messages are forwarded, and that the order is preserved.
122 | - `timestamp: u64`
123 | Timestamp at which the message was published. Can be used by the client to see the delay with which the messages are forwarded.
124 | - `message: Vec`
125 | The message contents encoded in binary form.
126 | The message is cbor encoded and provided as val in the candid type:
127 | ```
128 | type Message = record {
129 | client_id: nat64;
130 | key: text;
131 | val: blob;
132 | };
133 | ```
134 | The field ‘key’ provides the argument under which the hash of ‘val’ is stored in the certified map.
135 |
136 | Up to 50 messages queued for clients of the calling gateway are returned as the candid type:
137 | ```
138 | type CertMessages = record {
139 | messages: vec Message;
140 | cert: blob;
141 | tree: blob;
142 | };
143 | ```
144 | The messages are stored in the certified map under consecutive keys. The provided ‘tree’ includes all keys in the relevant range, and thus the fields ‘cert’ and ‘tree’ serve as the certificate for all clients to which messages are addressed.
145 | * **"ws_message": (blob) -> (bool);**
146 |
147 | Gateway calls this method to pass a message from the client to the canister. The argument is the cbor encoding of the candid type
148 | ```
149 | record {
150 | val: blob;
151 | sig: blob;
152 | };
153 | ```
154 | where ‘val’ is the cbor encoding of a message with the abovementioned fields:
155 | ```
156 | client_id: u64
157 | sequence_num: u64
158 | timestamp: u64
159 | message: Vec
160 | ```
161 | and ‘sig’ is the signature corresponding to the client.
162 |
163 | # Issues and future work
164 |
165 | 1. The provided websocket server example is very rudimentary and needs to improved for real use, e.g. use SSL, harden against DDoS attacks, port scanning, proper firewall rules. The server can panic if used incorrectly, e.g. if client requests to connect to wrong canister id. Some data might be left over and not properly cleaned up after closing connections, e.g. in the current state after all connections to a certain canister are closed, the gateway continues polling for messages.
166 | 2. Error handling and reliability need to be improved. E.g. the canister panics instead of returning informative error messages if incorrect arguments are passed or methods are called in incorrect order.
167 | 3. Heartbeat messages are not implemented yet.
168 | Heartbeat messages would ensure that the client/canister can detect the gateway crashing or misbehaving by delaying messages, and timeout. As of yet, if the gateway crashes or misbehaves, it may appear to the canister that the connection is still open, while the websocket between the gateway and the client has been closed (and vice versa).
169 | 4. The authentication of the identity used to register the websocket might expire (for example if using the Internet Identity), but the resulting websocket connections don't expire, constituting a security risk.
170 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/src/ic_websocket_frontend/assets/logo2.svg:
--------------------------------------------------------------------------------
1 |
38 |
--------------------------------------------------------------------------------
/ic_websocket_canisters/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "adler"
7 | version = "1.0.2"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
10 |
11 | [[package]]
12 | name = "aho-corasick"
13 | version = "1.0.1"
14 | source = "registry+https://github.com/rust-lang/crates.io-index"
15 | checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
16 | dependencies = [
17 | "memchr",
18 | ]
19 |
20 | [[package]]
21 | name = "anyhow"
22 | version = "1.0.71"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
25 |
26 | [[package]]
27 | name = "arrayvec"
28 | version = "0.5.2"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
31 |
32 | [[package]]
33 | name = "ascii-canvas"
34 | version = "3.0.0"
35 | source = "registry+https://github.com/rust-lang/crates.io-index"
36 | checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
37 | dependencies = [
38 | "term",
39 | ]
40 |
41 | [[package]]
42 | name = "autocfg"
43 | version = "1.1.0"
44 | source = "registry+https://github.com/rust-lang/crates.io-index"
45 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
46 |
47 | [[package]]
48 | name = "base64"
49 | version = "0.13.1"
50 | source = "registry+https://github.com/rust-lang/crates.io-index"
51 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
52 |
53 | [[package]]
54 | name = "beef"
55 | version = "0.5.2"
56 | source = "registry+https://github.com/rust-lang/crates.io-index"
57 | checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
58 |
59 | [[package]]
60 | name = "binread"
61 | version = "2.2.0"
62 | source = "registry+https://github.com/rust-lang/crates.io-index"
63 | checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f"
64 | dependencies = [
65 | "binread_derive",
66 | "lazy_static",
67 | "rustversion",
68 | ]
69 |
70 | [[package]]
71 | name = "binread_derive"
72 | version = "2.1.0"
73 | source = "registry+https://github.com/rust-lang/crates.io-index"
74 | checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed"
75 | dependencies = [
76 | "either",
77 | "proc-macro2",
78 | "quote",
79 | "syn 1.0.109",
80 | ]
81 |
82 | [[package]]
83 | name = "bit-set"
84 | version = "0.5.3"
85 | source = "registry+https://github.com/rust-lang/crates.io-index"
86 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
87 | dependencies = [
88 | "bit-vec",
89 | ]
90 |
91 | [[package]]
92 | name = "bit-vec"
93 | version = "0.6.3"
94 | source = "registry+https://github.com/rust-lang/crates.io-index"
95 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
96 |
97 | [[package]]
98 | name = "bitflags"
99 | version = "1.3.2"
100 | source = "registry+https://github.com/rust-lang/crates.io-index"
101 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
102 |
103 | [[package]]
104 | name = "block-buffer"
105 | version = "0.10.4"
106 | source = "registry+https://github.com/rust-lang/crates.io-index"
107 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
108 | dependencies = [
109 | "generic-array",
110 | ]
111 |
112 | [[package]]
113 | name = "byteorder"
114 | version = "1.4.3"
115 | source = "registry+https://github.com/rust-lang/crates.io-index"
116 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
117 |
118 | [[package]]
119 | name = "candid"
120 | version = "0.8.4"
121 | source = "registry+https://github.com/rust-lang/crates.io-index"
122 | checksum = "244005a1917bb7614cd775ca8a5d59efeb5ac74397bb14ba29a19347ebd78591"
123 | dependencies = [
124 | "anyhow",
125 | "binread",
126 | "byteorder",
127 | "candid_derive",
128 | "codespan-reporting",
129 | "crc32fast",
130 | "data-encoding",
131 | "hex",
132 | "lalrpop",
133 | "lalrpop-util",
134 | "leb128",
135 | "logos",
136 | "num-bigint",
137 | "num-traits",
138 | "num_enum",
139 | "paste",
140 | "pretty",
141 | "serde",
142 | "serde_bytes",
143 | "sha2",
144 | "thiserror",
145 | ]
146 |
147 | [[package]]
148 | name = "candid_derive"
149 | version = "0.5.0"
150 | source = "registry+https://github.com/rust-lang/crates.io-index"
151 | checksum = "58f1f4db7c7d04b87b70b3a35c5dc5c2c9dd73cef8bdf6760e2f18a0d45350dd"
152 | dependencies = [
153 | "lazy_static",
154 | "proc-macro2",
155 | "quote",
156 | "syn 1.0.109",
157 | ]
158 |
159 | [[package]]
160 | name = "cc"
161 | version = "1.0.79"
162 | source = "registry+https://github.com/rust-lang/crates.io-index"
163 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
164 |
165 | [[package]]
166 | name = "cfg-if"
167 | version = "1.0.0"
168 | source = "registry+https://github.com/rust-lang/crates.io-index"
169 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
170 |
171 | [[package]]
172 | name = "codespan-reporting"
173 | version = "0.11.1"
174 | source = "registry+https://github.com/rust-lang/crates.io-index"
175 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
176 | dependencies = [
177 | "termcolor",
178 | "unicode-width",
179 | ]
180 |
181 | [[package]]
182 | name = "cpufeatures"
183 | version = "0.2.7"
184 | source = "registry+https://github.com/rust-lang/crates.io-index"
185 | checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
186 | dependencies = [
187 | "libc",
188 | ]
189 |
190 | [[package]]
191 | name = "crc32fast"
192 | version = "1.3.2"
193 | source = "registry+https://github.com/rust-lang/crates.io-index"
194 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
195 | dependencies = [
196 | "cfg-if",
197 | ]
198 |
199 | [[package]]
200 | name = "crunchy"
201 | version = "0.2.2"
202 | source = "registry+https://github.com/rust-lang/crates.io-index"
203 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
204 |
205 | [[package]]
206 | name = "crypto-common"
207 | version = "0.1.6"
208 | source = "registry+https://github.com/rust-lang/crates.io-index"
209 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
210 | dependencies = [
211 | "generic-array",
212 | "typenum",
213 | ]
214 |
215 | [[package]]
216 | name = "data-encoding"
217 | version = "2.3.3"
218 | source = "registry+https://github.com/rust-lang/crates.io-index"
219 | checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
220 |
221 | [[package]]
222 | name = "diff"
223 | version = "0.1.13"
224 | source = "registry+https://github.com/rust-lang/crates.io-index"
225 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
226 |
227 | [[package]]
228 | name = "digest"
229 | version = "0.10.6"
230 | source = "registry+https://github.com/rust-lang/crates.io-index"
231 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
232 | dependencies = [
233 | "block-buffer",
234 | "crypto-common",
235 | ]
236 |
237 | [[package]]
238 | name = "dirs-next"
239 | version = "2.0.0"
240 | source = "registry+https://github.com/rust-lang/crates.io-index"
241 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
242 | dependencies = [
243 | "cfg-if",
244 | "dirs-sys-next",
245 | ]
246 |
247 | [[package]]
248 | name = "dirs-sys-next"
249 | version = "0.1.2"
250 | source = "registry+https://github.com/rust-lang/crates.io-index"
251 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
252 | dependencies = [
253 | "libc",
254 | "redox_users",
255 | "winapi",
256 | ]
257 |
258 | [[package]]
259 | name = "ed25519-compact"
260 | version = "2.0.4"
261 | source = "registry+https://github.com/rust-lang/crates.io-index"
262 | checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
263 |
264 | [[package]]
265 | name = "either"
266 | version = "1.8.1"
267 | source = "registry+https://github.com/rust-lang/crates.io-index"
268 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
269 |
270 | [[package]]
271 | name = "ena"
272 | version = "0.14.2"
273 | source = "registry+https://github.com/rust-lang/crates.io-index"
274 | checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
275 | dependencies = [
276 | "log",
277 | ]
278 |
279 | [[package]]
280 | name = "errno"
281 | version = "0.3.1"
282 | source = "registry+https://github.com/rust-lang/crates.io-index"
283 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
284 | dependencies = [
285 | "errno-dragonfly",
286 | "libc",
287 | "windows-sys 0.48.0",
288 | ]
289 |
290 | [[package]]
291 | name = "errno-dragonfly"
292 | version = "0.1.2"
293 | source = "registry+https://github.com/rust-lang/crates.io-index"
294 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
295 | dependencies = [
296 | "cc",
297 | "libc",
298 | ]
299 |
300 | [[package]]
301 | name = "fixedbitset"
302 | version = "0.4.2"
303 | source = "registry+https://github.com/rust-lang/crates.io-index"
304 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
305 |
306 | [[package]]
307 | name = "flate2"
308 | version = "1.0.26"
309 | source = "registry+https://github.com/rust-lang/crates.io-index"
310 | checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743"
311 | dependencies = [
312 | "crc32fast",
313 | "miniz_oxide",
314 | ]
315 |
316 | [[package]]
317 | name = "fnv"
318 | version = "1.0.7"
319 | source = "registry+https://github.com/rust-lang/crates.io-index"
320 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
321 |
322 | [[package]]
323 | name = "generic-array"
324 | version = "0.14.7"
325 | source = "registry+https://github.com/rust-lang/crates.io-index"
326 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
327 | dependencies = [
328 | "typenum",
329 | "version_check",
330 | ]
331 |
332 | [[package]]
333 | name = "getrandom"
334 | version = "0.2.9"
335 | source = "registry+https://github.com/rust-lang/crates.io-index"
336 | checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
337 | dependencies = [
338 | "cfg-if",
339 | "libc",
340 | "wasi",
341 | ]
342 |
343 | [[package]]
344 | name = "half"
345 | version = "1.8.2"
346 | source = "registry+https://github.com/rust-lang/crates.io-index"
347 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
348 |
349 | [[package]]
350 | name = "hashbrown"
351 | version = "0.12.3"
352 | source = "registry+https://github.com/rust-lang/crates.io-index"
353 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
354 |
355 | [[package]]
356 | name = "hermit-abi"
357 | version = "0.3.1"
358 | source = "registry+https://github.com/rust-lang/crates.io-index"
359 | checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
360 |
361 | [[package]]
362 | name = "hex"
363 | version = "0.4.3"
364 | source = "registry+https://github.com/rust-lang/crates.io-index"
365 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
366 |
367 | [[package]]
368 | name = "ic-cdk"
369 | version = "0.6.10"
370 | source = "registry+https://github.com/rust-lang/crates.io-index"
371 | checksum = "c98b304a2657bad15bcb547625a018e13cf596676d834cfd93023395a6e2e03a"
372 | dependencies = [
373 | "candid",
374 | "cfg-if",
375 | "ic-cdk-macros",
376 | "ic0",
377 | "serde",
378 | "serde_bytes",
379 | ]
380 |
381 | [[package]]
382 | name = "ic-cdk-macros"
383 | version = "0.6.10"
384 | source = "registry+https://github.com/rust-lang/crates.io-index"
385 | checksum = "ebf50458685a0fc6b0e414cdba487610aeb199ac94db52d9fd76270565debee7"
386 | dependencies = [
387 | "candid",
388 | "proc-macro2",
389 | "quote",
390 | "serde",
391 | "serde_tokenstream",
392 | "syn 1.0.109",
393 | ]
394 |
395 | [[package]]
396 | name = "ic-certified-map"
397 | version = "0.3.4"
398 | source = "registry+https://github.com/rust-lang/crates.io-index"
399 | checksum = "6adc65afeffc619a7cd19553c66c79820908c12f42191af90cfb39e2e93c4431"
400 | dependencies = [
401 | "serde",
402 | "serde_bytes",
403 | "sha2",
404 | ]
405 |
406 | [[package]]
407 | name = "ic0"
408 | version = "0.18.9"
409 | source = "registry+https://github.com/rust-lang/crates.io-index"
410 | checksum = "978b91fc78de9d2eb0144db717839cde3b35470199ea51aca362cb6310e93dfd"
411 |
412 | [[package]]
413 | name = "ic_websocket_backend"
414 | version = "0.1.0"
415 | dependencies = [
416 | "base64",
417 | "candid",
418 | "ed25519-compact",
419 | "flate2",
420 | "ic-cdk",
421 | "ic-cdk-macros",
422 | "ic-certified-map",
423 | "serde",
424 | "serde_bytes",
425 | "serde_cbor",
426 | "sha2",
427 | ]
428 |
429 | [[package]]
430 | name = "indexmap"
431 | version = "1.9.3"
432 | source = "registry+https://github.com/rust-lang/crates.io-index"
433 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
434 | dependencies = [
435 | "autocfg",
436 | "hashbrown",
437 | ]
438 |
439 | [[package]]
440 | name = "io-lifetimes"
441 | version = "1.0.10"
442 | source = "registry+https://github.com/rust-lang/crates.io-index"
443 | checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
444 | dependencies = [
445 | "hermit-abi",
446 | "libc",
447 | "windows-sys 0.48.0",
448 | ]
449 |
450 | [[package]]
451 | name = "is-terminal"
452 | version = "0.4.7"
453 | source = "registry+https://github.com/rust-lang/crates.io-index"
454 | checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
455 | dependencies = [
456 | "hermit-abi",
457 | "io-lifetimes",
458 | "rustix",
459 | "windows-sys 0.48.0",
460 | ]
461 |
462 | [[package]]
463 | name = "itertools"
464 | version = "0.10.5"
465 | source = "registry+https://github.com/rust-lang/crates.io-index"
466 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
467 | dependencies = [
468 | "either",
469 | ]
470 |
471 | [[package]]
472 | name = "lalrpop"
473 | version = "0.19.12"
474 | source = "registry+https://github.com/rust-lang/crates.io-index"
475 | checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b"
476 | dependencies = [
477 | "ascii-canvas",
478 | "bit-set",
479 | "diff",
480 | "ena",
481 | "is-terminal",
482 | "itertools",
483 | "lalrpop-util",
484 | "petgraph",
485 | "regex",
486 | "regex-syntax 0.6.29",
487 | "string_cache",
488 | "term",
489 | "tiny-keccak",
490 | "unicode-xid",
491 | ]
492 |
493 | [[package]]
494 | name = "lalrpop-util"
495 | version = "0.19.12"
496 | source = "registry+https://github.com/rust-lang/crates.io-index"
497 | checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed"
498 | dependencies = [
499 | "regex",
500 | ]
501 |
502 | [[package]]
503 | name = "lazy_static"
504 | version = "1.4.0"
505 | source = "registry+https://github.com/rust-lang/crates.io-index"
506 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
507 |
508 | [[package]]
509 | name = "leb128"
510 | version = "0.2.5"
511 | source = "registry+https://github.com/rust-lang/crates.io-index"
512 | checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
513 |
514 | [[package]]
515 | name = "libc"
516 | version = "0.2.144"
517 | source = "registry+https://github.com/rust-lang/crates.io-index"
518 | checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
519 |
520 | [[package]]
521 | name = "linux-raw-sys"
522 | version = "0.3.7"
523 | source = "registry+https://github.com/rust-lang/crates.io-index"
524 | checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
525 |
526 | [[package]]
527 | name = "lock_api"
528 | version = "0.4.9"
529 | source = "registry+https://github.com/rust-lang/crates.io-index"
530 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
531 | dependencies = [
532 | "autocfg",
533 | "scopeguard",
534 | ]
535 |
536 | [[package]]
537 | name = "log"
538 | version = "0.4.17"
539 | source = "registry+https://github.com/rust-lang/crates.io-index"
540 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
541 | dependencies = [
542 | "cfg-if",
543 | ]
544 |
545 | [[package]]
546 | name = "logos"
547 | version = "0.12.1"
548 | source = "registry+https://github.com/rust-lang/crates.io-index"
549 | checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1"
550 | dependencies = [
551 | "logos-derive",
552 | ]
553 |
554 | [[package]]
555 | name = "logos-derive"
556 | version = "0.12.1"
557 | source = "registry+https://github.com/rust-lang/crates.io-index"
558 | checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c"
559 | dependencies = [
560 | "beef",
561 | "fnv",
562 | "proc-macro2",
563 | "quote",
564 | "regex-syntax 0.6.29",
565 | "syn 1.0.109",
566 | ]
567 |
568 | [[package]]
569 | name = "memchr"
570 | version = "2.5.0"
571 | source = "registry+https://github.com/rust-lang/crates.io-index"
572 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
573 |
574 | [[package]]
575 | name = "miniz_oxide"
576 | version = "0.7.1"
577 | source = "registry+https://github.com/rust-lang/crates.io-index"
578 | checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
579 | dependencies = [
580 | "adler",
581 | ]
582 |
583 | [[package]]
584 | name = "new_debug_unreachable"
585 | version = "1.0.4"
586 | source = "registry+https://github.com/rust-lang/crates.io-index"
587 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
588 |
589 | [[package]]
590 | name = "num-bigint"
591 | version = "0.4.3"
592 | source = "registry+https://github.com/rust-lang/crates.io-index"
593 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
594 | dependencies = [
595 | "autocfg",
596 | "num-integer",
597 | "num-traits",
598 | "serde",
599 | ]
600 |
601 | [[package]]
602 | name = "num-integer"
603 | version = "0.1.45"
604 | source = "registry+https://github.com/rust-lang/crates.io-index"
605 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
606 | dependencies = [
607 | "autocfg",
608 | "num-traits",
609 | ]
610 |
611 | [[package]]
612 | name = "num-traits"
613 | version = "0.2.15"
614 | source = "registry+https://github.com/rust-lang/crates.io-index"
615 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
616 | dependencies = [
617 | "autocfg",
618 | ]
619 |
620 | [[package]]
621 | name = "num_enum"
622 | version = "0.5.11"
623 | source = "registry+https://github.com/rust-lang/crates.io-index"
624 | checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
625 | dependencies = [
626 | "num_enum_derive",
627 | ]
628 |
629 | [[package]]
630 | name = "num_enum_derive"
631 | version = "0.5.11"
632 | source = "registry+https://github.com/rust-lang/crates.io-index"
633 | checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
634 | dependencies = [
635 | "proc-macro-crate",
636 | "proc-macro2",
637 | "quote",
638 | "syn 1.0.109",
639 | ]
640 |
641 | [[package]]
642 | name = "once_cell"
643 | version = "1.17.1"
644 | source = "registry+https://github.com/rust-lang/crates.io-index"
645 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
646 |
647 | [[package]]
648 | name = "parking_lot"
649 | version = "0.12.1"
650 | source = "registry+https://github.com/rust-lang/crates.io-index"
651 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
652 | dependencies = [
653 | "lock_api",
654 | "parking_lot_core",
655 | ]
656 |
657 | [[package]]
658 | name = "parking_lot_core"
659 | version = "0.9.7"
660 | source = "registry+https://github.com/rust-lang/crates.io-index"
661 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
662 | dependencies = [
663 | "cfg-if",
664 | "libc",
665 | "redox_syscall",
666 | "smallvec",
667 | "windows-sys 0.45.0",
668 | ]
669 |
670 | [[package]]
671 | name = "paste"
672 | version = "1.0.12"
673 | source = "registry+https://github.com/rust-lang/crates.io-index"
674 | checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
675 |
676 | [[package]]
677 | name = "petgraph"
678 | version = "0.6.3"
679 | source = "registry+https://github.com/rust-lang/crates.io-index"
680 | checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
681 | dependencies = [
682 | "fixedbitset",
683 | "indexmap",
684 | ]
685 |
686 | [[package]]
687 | name = "phf_shared"
688 | version = "0.10.0"
689 | source = "registry+https://github.com/rust-lang/crates.io-index"
690 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
691 | dependencies = [
692 | "siphasher",
693 | ]
694 |
695 | [[package]]
696 | name = "precomputed-hash"
697 | version = "0.1.1"
698 | source = "registry+https://github.com/rust-lang/crates.io-index"
699 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
700 |
701 | [[package]]
702 | name = "pretty"
703 | version = "0.10.0"
704 | source = "registry+https://github.com/rust-lang/crates.io-index"
705 | checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61"
706 | dependencies = [
707 | "arrayvec",
708 | "typed-arena",
709 | ]
710 |
711 | [[package]]
712 | name = "proc-macro-crate"
713 | version = "1.3.1"
714 | source = "registry+https://github.com/rust-lang/crates.io-index"
715 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
716 | dependencies = [
717 | "once_cell",
718 | "toml_edit",
719 | ]
720 |
721 | [[package]]
722 | name = "proc-macro2"
723 | version = "1.0.58"
724 | source = "registry+https://github.com/rust-lang/crates.io-index"
725 | checksum = "fa1fb82fc0c281dd9671101b66b771ebbe1eaf967b96ac8740dcba4b70005ca8"
726 | dependencies = [
727 | "unicode-ident",
728 | ]
729 |
730 | [[package]]
731 | name = "quote"
732 | version = "1.0.27"
733 | source = "registry+https://github.com/rust-lang/crates.io-index"
734 | checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
735 | dependencies = [
736 | "proc-macro2",
737 | ]
738 |
739 | [[package]]
740 | name = "redox_syscall"
741 | version = "0.2.16"
742 | source = "registry+https://github.com/rust-lang/crates.io-index"
743 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
744 | dependencies = [
745 | "bitflags",
746 | ]
747 |
748 | [[package]]
749 | name = "redox_users"
750 | version = "0.4.3"
751 | source = "registry+https://github.com/rust-lang/crates.io-index"
752 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
753 | dependencies = [
754 | "getrandom",
755 | "redox_syscall",
756 | "thiserror",
757 | ]
758 |
759 | [[package]]
760 | name = "regex"
761 | version = "1.8.1"
762 | source = "registry+https://github.com/rust-lang/crates.io-index"
763 | checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
764 | dependencies = [
765 | "aho-corasick",
766 | "memchr",
767 | "regex-syntax 0.7.1",
768 | ]
769 |
770 | [[package]]
771 | name = "regex-syntax"
772 | version = "0.6.29"
773 | source = "registry+https://github.com/rust-lang/crates.io-index"
774 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
775 |
776 | [[package]]
777 | name = "regex-syntax"
778 | version = "0.7.1"
779 | source = "registry+https://github.com/rust-lang/crates.io-index"
780 | checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
781 |
782 | [[package]]
783 | name = "rustix"
784 | version = "0.37.19"
785 | source = "registry+https://github.com/rust-lang/crates.io-index"
786 | checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
787 | dependencies = [
788 | "bitflags",
789 | "errno",
790 | "io-lifetimes",
791 | "libc",
792 | "linux-raw-sys",
793 | "windows-sys 0.48.0",
794 | ]
795 |
796 | [[package]]
797 | name = "rustversion"
798 | version = "1.0.12"
799 | source = "registry+https://github.com/rust-lang/crates.io-index"
800 | checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
801 |
802 | [[package]]
803 | name = "scopeguard"
804 | version = "1.1.0"
805 | source = "registry+https://github.com/rust-lang/crates.io-index"
806 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
807 |
808 | [[package]]
809 | name = "serde"
810 | version = "1.0.163"
811 | source = "registry+https://github.com/rust-lang/crates.io-index"
812 | checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
813 | dependencies = [
814 | "serde_derive",
815 | ]
816 |
817 | [[package]]
818 | name = "serde_bytes"
819 | version = "0.11.9"
820 | source = "registry+https://github.com/rust-lang/crates.io-index"
821 | checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
822 | dependencies = [
823 | "serde",
824 | ]
825 |
826 | [[package]]
827 | name = "serde_cbor"
828 | version = "0.11.2"
829 | source = "registry+https://github.com/rust-lang/crates.io-index"
830 | checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
831 | dependencies = [
832 | "half",
833 | "serde",
834 | ]
835 |
836 | [[package]]
837 | name = "serde_derive"
838 | version = "1.0.163"
839 | source = "registry+https://github.com/rust-lang/crates.io-index"
840 | checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
841 | dependencies = [
842 | "proc-macro2",
843 | "quote",
844 | "syn 2.0.16",
845 | ]
846 |
847 | [[package]]
848 | name = "serde_tokenstream"
849 | version = "0.1.7"
850 | source = "registry+https://github.com/rust-lang/crates.io-index"
851 | checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9"
852 | dependencies = [
853 | "proc-macro2",
854 | "serde",
855 | "syn 1.0.109",
856 | ]
857 |
858 | [[package]]
859 | name = "sha2"
860 | version = "0.10.6"
861 | source = "registry+https://github.com/rust-lang/crates.io-index"
862 | checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
863 | dependencies = [
864 | "cfg-if",
865 | "cpufeatures",
866 | "digest",
867 | ]
868 |
869 | [[package]]
870 | name = "siphasher"
871 | version = "0.3.10"
872 | source = "registry+https://github.com/rust-lang/crates.io-index"
873 | checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
874 |
875 | [[package]]
876 | name = "smallvec"
877 | version = "1.10.0"
878 | source = "registry+https://github.com/rust-lang/crates.io-index"
879 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
880 |
881 | [[package]]
882 | name = "string_cache"
883 | version = "0.8.7"
884 | source = "registry+https://github.com/rust-lang/crates.io-index"
885 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
886 | dependencies = [
887 | "new_debug_unreachable",
888 | "once_cell",
889 | "parking_lot",
890 | "phf_shared",
891 | "precomputed-hash",
892 | ]
893 |
894 | [[package]]
895 | name = "syn"
896 | version = "1.0.109"
897 | source = "registry+https://github.com/rust-lang/crates.io-index"
898 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
899 | dependencies = [
900 | "proc-macro2",
901 | "quote",
902 | "unicode-ident",
903 | ]
904 |
905 | [[package]]
906 | name = "syn"
907 | version = "2.0.16"
908 | source = "registry+https://github.com/rust-lang/crates.io-index"
909 | checksum = "a6f671d4b5ffdb8eadec19c0ae67fe2639df8684bd7bc4b83d986b8db549cf01"
910 | dependencies = [
911 | "proc-macro2",
912 | "quote",
913 | "unicode-ident",
914 | ]
915 |
916 | [[package]]
917 | name = "term"
918 | version = "0.7.0"
919 | source = "registry+https://github.com/rust-lang/crates.io-index"
920 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
921 | dependencies = [
922 | "dirs-next",
923 | "rustversion",
924 | "winapi",
925 | ]
926 |
927 | [[package]]
928 | name = "termcolor"
929 | version = "1.2.0"
930 | source = "registry+https://github.com/rust-lang/crates.io-index"
931 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
932 | dependencies = [
933 | "winapi-util",
934 | ]
935 |
936 | [[package]]
937 | name = "thiserror"
938 | version = "1.0.40"
939 | source = "registry+https://github.com/rust-lang/crates.io-index"
940 | checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
941 | dependencies = [
942 | "thiserror-impl",
943 | ]
944 |
945 | [[package]]
946 | name = "thiserror-impl"
947 | version = "1.0.40"
948 | source = "registry+https://github.com/rust-lang/crates.io-index"
949 | checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
950 | dependencies = [
951 | "proc-macro2",
952 | "quote",
953 | "syn 2.0.16",
954 | ]
955 |
956 | [[package]]
957 | name = "tiny-keccak"
958 | version = "2.0.2"
959 | source = "registry+https://github.com/rust-lang/crates.io-index"
960 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
961 | dependencies = [
962 | "crunchy",
963 | ]
964 |
965 | [[package]]
966 | name = "toml_datetime"
967 | version = "0.6.1"
968 | source = "registry+https://github.com/rust-lang/crates.io-index"
969 | checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
970 |
971 | [[package]]
972 | name = "toml_edit"
973 | version = "0.19.8"
974 | source = "registry+https://github.com/rust-lang/crates.io-index"
975 | checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
976 | dependencies = [
977 | "indexmap",
978 | "toml_datetime",
979 | "winnow",
980 | ]
981 |
982 | [[package]]
983 | name = "typed-arena"
984 | version = "2.0.2"
985 | source = "registry+https://github.com/rust-lang/crates.io-index"
986 | checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
987 |
988 | [[package]]
989 | name = "typenum"
990 | version = "1.16.0"
991 | source = "registry+https://github.com/rust-lang/crates.io-index"
992 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
993 |
994 | [[package]]
995 | name = "unicode-ident"
996 | version = "1.0.8"
997 | source = "registry+https://github.com/rust-lang/crates.io-index"
998 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
999 |
1000 | [[package]]
1001 | name = "unicode-width"
1002 | version = "0.1.10"
1003 | source = "registry+https://github.com/rust-lang/crates.io-index"
1004 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
1005 |
1006 | [[package]]
1007 | name = "unicode-xid"
1008 | version = "0.2.4"
1009 | source = "registry+https://github.com/rust-lang/crates.io-index"
1010 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
1011 |
1012 | [[package]]
1013 | name = "version_check"
1014 | version = "0.9.4"
1015 | source = "registry+https://github.com/rust-lang/crates.io-index"
1016 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
1017 |
1018 | [[package]]
1019 | name = "wasi"
1020 | version = "0.11.0+wasi-snapshot-preview1"
1021 | source = "registry+https://github.com/rust-lang/crates.io-index"
1022 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
1023 |
1024 | [[package]]
1025 | name = "winapi"
1026 | version = "0.3.9"
1027 | source = "registry+https://github.com/rust-lang/crates.io-index"
1028 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
1029 | dependencies = [
1030 | "winapi-i686-pc-windows-gnu",
1031 | "winapi-x86_64-pc-windows-gnu",
1032 | ]
1033 |
1034 | [[package]]
1035 | name = "winapi-i686-pc-windows-gnu"
1036 | version = "0.4.0"
1037 | source = "registry+https://github.com/rust-lang/crates.io-index"
1038 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
1039 |
1040 | [[package]]
1041 | name = "winapi-util"
1042 | version = "0.1.5"
1043 | source = "registry+https://github.com/rust-lang/crates.io-index"
1044 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
1045 | dependencies = [
1046 | "winapi",
1047 | ]
1048 |
1049 | [[package]]
1050 | name = "winapi-x86_64-pc-windows-gnu"
1051 | version = "0.4.0"
1052 | source = "registry+https://github.com/rust-lang/crates.io-index"
1053 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1054 |
1055 | [[package]]
1056 | name = "windows-sys"
1057 | version = "0.45.0"
1058 | source = "registry+https://github.com/rust-lang/crates.io-index"
1059 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
1060 | dependencies = [
1061 | "windows-targets 0.42.2",
1062 | ]
1063 |
1064 | [[package]]
1065 | name = "windows-sys"
1066 | version = "0.48.0"
1067 | source = "registry+https://github.com/rust-lang/crates.io-index"
1068 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
1069 | dependencies = [
1070 | "windows-targets 0.48.0",
1071 | ]
1072 |
1073 | [[package]]
1074 | name = "windows-targets"
1075 | version = "0.42.2"
1076 | source = "registry+https://github.com/rust-lang/crates.io-index"
1077 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
1078 | dependencies = [
1079 | "windows_aarch64_gnullvm 0.42.2",
1080 | "windows_aarch64_msvc 0.42.2",
1081 | "windows_i686_gnu 0.42.2",
1082 | "windows_i686_msvc 0.42.2",
1083 | "windows_x86_64_gnu 0.42.2",
1084 | "windows_x86_64_gnullvm 0.42.2",
1085 | "windows_x86_64_msvc 0.42.2",
1086 | ]
1087 |
1088 | [[package]]
1089 | name = "windows-targets"
1090 | version = "0.48.0"
1091 | source = "registry+https://github.com/rust-lang/crates.io-index"
1092 | checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
1093 | dependencies = [
1094 | "windows_aarch64_gnullvm 0.48.0",
1095 | "windows_aarch64_msvc 0.48.0",
1096 | "windows_i686_gnu 0.48.0",
1097 | "windows_i686_msvc 0.48.0",
1098 | "windows_x86_64_gnu 0.48.0",
1099 | "windows_x86_64_gnullvm 0.48.0",
1100 | "windows_x86_64_msvc 0.48.0",
1101 | ]
1102 |
1103 | [[package]]
1104 | name = "windows_aarch64_gnullvm"
1105 | version = "0.42.2"
1106 | source = "registry+https://github.com/rust-lang/crates.io-index"
1107 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
1108 |
1109 | [[package]]
1110 | name = "windows_aarch64_gnullvm"
1111 | version = "0.48.0"
1112 | source = "registry+https://github.com/rust-lang/crates.io-index"
1113 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
1114 |
1115 | [[package]]
1116 | name = "windows_aarch64_msvc"
1117 | version = "0.42.2"
1118 | source = "registry+https://github.com/rust-lang/crates.io-index"
1119 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
1120 |
1121 | [[package]]
1122 | name = "windows_aarch64_msvc"
1123 | version = "0.48.0"
1124 | source = "registry+https://github.com/rust-lang/crates.io-index"
1125 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
1126 |
1127 | [[package]]
1128 | name = "windows_i686_gnu"
1129 | version = "0.42.2"
1130 | source = "registry+https://github.com/rust-lang/crates.io-index"
1131 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
1132 |
1133 | [[package]]
1134 | name = "windows_i686_gnu"
1135 | version = "0.48.0"
1136 | source = "registry+https://github.com/rust-lang/crates.io-index"
1137 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
1138 |
1139 | [[package]]
1140 | name = "windows_i686_msvc"
1141 | version = "0.42.2"
1142 | source = "registry+https://github.com/rust-lang/crates.io-index"
1143 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
1144 |
1145 | [[package]]
1146 | name = "windows_i686_msvc"
1147 | version = "0.48.0"
1148 | source = "registry+https://github.com/rust-lang/crates.io-index"
1149 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
1150 |
1151 | [[package]]
1152 | name = "windows_x86_64_gnu"
1153 | version = "0.42.2"
1154 | source = "registry+https://github.com/rust-lang/crates.io-index"
1155 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
1156 |
1157 | [[package]]
1158 | name = "windows_x86_64_gnu"
1159 | version = "0.48.0"
1160 | source = "registry+https://github.com/rust-lang/crates.io-index"
1161 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
1162 |
1163 | [[package]]
1164 | name = "windows_x86_64_gnullvm"
1165 | version = "0.42.2"
1166 | source = "registry+https://github.com/rust-lang/crates.io-index"
1167 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
1168 |
1169 | [[package]]
1170 | name = "windows_x86_64_gnullvm"
1171 | version = "0.48.0"
1172 | source = "registry+https://github.com/rust-lang/crates.io-index"
1173 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
1174 |
1175 | [[package]]
1176 | name = "windows_x86_64_msvc"
1177 | version = "0.42.2"
1178 | source = "registry+https://github.com/rust-lang/crates.io-index"
1179 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
1180 |
1181 | [[package]]
1182 | name = "windows_x86_64_msvc"
1183 | version = "0.48.0"
1184 | source = "registry+https://github.com/rust-lang/crates.io-index"
1185 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
1186 |
1187 | [[package]]
1188 | name = "winnow"
1189 | version = "0.4.6"
1190 | source = "registry+https://github.com/rust-lang/crates.io-index"
1191 | checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
1192 | dependencies = [
1193 | "memchr",
1194 | ]
1195 |
--------------------------------------------------------------------------------
/ic_websocket_gateway/Cargo.lock:
--------------------------------------------------------------------------------
1 | # This file is automatically @generated by Cargo.
2 | # It is not intended for manual editing.
3 | version = 3
4 |
5 | [[package]]
6 | name = "aho-corasick"
7 | version = "1.0.1"
8 | source = "registry+https://github.com/rust-lang/crates.io-index"
9 | checksum = "67fc08ce920c31afb70f013dcce1bfc3a3195de6a228474e45e1f145b36f8d04"
10 | dependencies = [
11 | "memchr",
12 | ]
13 |
14 | [[package]]
15 | name = "anyhow"
16 | version = "1.0.71"
17 | source = "registry+https://github.com/rust-lang/crates.io-index"
18 | checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8"
19 |
20 | [[package]]
21 | name = "arrayvec"
22 | version = "0.5.2"
23 | source = "registry+https://github.com/rust-lang/crates.io-index"
24 | checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b"
25 |
26 | [[package]]
27 | name = "ascii-canvas"
28 | version = "3.0.0"
29 | source = "registry+https://github.com/rust-lang/crates.io-index"
30 | checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6"
31 | dependencies = [
32 | "term",
33 | ]
34 |
35 | [[package]]
36 | name = "async-trait"
37 | version = "0.1.68"
38 | source = "registry+https://github.com/rust-lang/crates.io-index"
39 | checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
40 | dependencies = [
41 | "proc-macro2",
42 | "quote",
43 | "syn 2.0.15",
44 | ]
45 |
46 | [[package]]
47 | name = "autocfg"
48 | version = "1.1.0"
49 | source = "registry+https://github.com/rust-lang/crates.io-index"
50 | checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
51 |
52 | [[package]]
53 | name = "backoff"
54 | version = "0.4.0"
55 | source = "registry+https://github.com/rust-lang/crates.io-index"
56 | checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1"
57 | dependencies = [
58 | "getrandom",
59 | "instant",
60 | "rand",
61 | ]
62 |
63 | [[package]]
64 | name = "base16ct"
65 | version = "0.1.1"
66 | source = "registry+https://github.com/rust-lang/crates.io-index"
67 | checksum = "349a06037c7bf932dd7e7d1f653678b2038b9ad46a74102f1fc7bd7872678cce"
68 |
69 | [[package]]
70 | name = "base32"
71 | version = "0.4.0"
72 | source = "registry+https://github.com/rust-lang/crates.io-index"
73 | checksum = "23ce669cd6c8588f79e15cf450314f9638f967fc5770ff1c7c1deb0925ea7cfa"
74 |
75 | [[package]]
76 | name = "base64"
77 | version = "0.13.1"
78 | source = "registry+https://github.com/rust-lang/crates.io-index"
79 | checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
80 |
81 | [[package]]
82 | name = "base64"
83 | version = "0.21.0"
84 | source = "registry+https://github.com/rust-lang/crates.io-index"
85 | checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a"
86 |
87 | [[package]]
88 | name = "base64ct"
89 | version = "1.6.0"
90 | source = "registry+https://github.com/rust-lang/crates.io-index"
91 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
92 |
93 | [[package]]
94 | name = "beef"
95 | version = "0.5.2"
96 | source = "registry+https://github.com/rust-lang/crates.io-index"
97 | checksum = "3a8241f3ebb85c056b509d4327ad0358fbbba6ffb340bf388f26350aeda225b1"
98 |
99 | [[package]]
100 | name = "binread"
101 | version = "2.2.0"
102 | source = "registry+https://github.com/rust-lang/crates.io-index"
103 | checksum = "16598dfc8e6578e9b597d9910ba2e73618385dc9f4b1d43dd92c349d6be6418f"
104 | dependencies = [
105 | "binread_derive",
106 | "lazy_static",
107 | "rustversion",
108 | ]
109 |
110 | [[package]]
111 | name = "binread_derive"
112 | version = "2.1.0"
113 | source = "registry+https://github.com/rust-lang/crates.io-index"
114 | checksum = "1d9672209df1714ee804b1f4d4f68c8eb2a90b1f7a07acf472f88ce198ef1fed"
115 | dependencies = [
116 | "either",
117 | "proc-macro2",
118 | "quote",
119 | "syn 1.0.109",
120 | ]
121 |
122 | [[package]]
123 | name = "bit-set"
124 | version = "0.5.3"
125 | source = "registry+https://github.com/rust-lang/crates.io-index"
126 | checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
127 | dependencies = [
128 | "bit-vec",
129 | ]
130 |
131 | [[package]]
132 | name = "bit-vec"
133 | version = "0.6.3"
134 | source = "registry+https://github.com/rust-lang/crates.io-index"
135 | checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
136 |
137 | [[package]]
138 | name = "bitflags"
139 | version = "1.3.2"
140 | source = "registry+https://github.com/rust-lang/crates.io-index"
141 | checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
142 |
143 | [[package]]
144 | name = "block-buffer"
145 | version = "0.9.0"
146 | source = "registry+https://github.com/rust-lang/crates.io-index"
147 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
148 | dependencies = [
149 | "generic-array",
150 | ]
151 |
152 | [[package]]
153 | name = "block-buffer"
154 | version = "0.10.4"
155 | source = "registry+https://github.com/rust-lang/crates.io-index"
156 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
157 | dependencies = [
158 | "generic-array",
159 | ]
160 |
161 | [[package]]
162 | name = "bls12_381"
163 | version = "0.7.1"
164 | source = "registry+https://github.com/rust-lang/crates.io-index"
165 | checksum = "a3c196a77437e7cc2fb515ce413a6401291578b5afc8ecb29a3c7ab957f05941"
166 | dependencies = [
167 | "digest 0.9.0",
168 | "ff",
169 | "group",
170 | "pairing",
171 | "rand_core",
172 | "subtle",
173 | ]
174 |
175 | [[package]]
176 | name = "bumpalo"
177 | version = "3.12.2"
178 | source = "registry+https://github.com/rust-lang/crates.io-index"
179 | checksum = "3c6ed94e98ecff0c12dd1b04c15ec0d7d9458ca8fe806cea6f12954efe74c63b"
180 |
181 | [[package]]
182 | name = "byteorder"
183 | version = "1.4.3"
184 | source = "registry+https://github.com/rust-lang/crates.io-index"
185 | checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
186 |
187 | [[package]]
188 | name = "bytes"
189 | version = "1.4.0"
190 | source = "registry+https://github.com/rust-lang/crates.io-index"
191 | checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be"
192 |
193 | [[package]]
194 | name = "candid"
195 | version = "0.8.4"
196 | source = "registry+https://github.com/rust-lang/crates.io-index"
197 | checksum = "244005a1917bb7614cd775ca8a5d59efeb5ac74397bb14ba29a19347ebd78591"
198 | dependencies = [
199 | "anyhow",
200 | "binread",
201 | "byteorder",
202 | "candid_derive",
203 | "codespan-reporting",
204 | "crc32fast",
205 | "data-encoding",
206 | "hex",
207 | "lalrpop",
208 | "lalrpop-util",
209 | "leb128",
210 | "logos",
211 | "num-bigint",
212 | "num-traits",
213 | "num_enum",
214 | "paste",
215 | "pretty",
216 | "serde",
217 | "serde_bytes",
218 | "sha2 0.10.6",
219 | "thiserror",
220 | ]
221 |
222 | [[package]]
223 | name = "candid_derive"
224 | version = "0.5.0"
225 | source = "registry+https://github.com/rust-lang/crates.io-index"
226 | checksum = "58f1f4db7c7d04b87b70b3a35c5dc5c2c9dd73cef8bdf6760e2f18a0d45350dd"
227 | dependencies = [
228 | "lazy_static",
229 | "proc-macro2",
230 | "quote",
231 | "syn 1.0.109",
232 | ]
233 |
234 | [[package]]
235 | name = "cc"
236 | version = "1.0.79"
237 | source = "registry+https://github.com/rust-lang/crates.io-index"
238 | checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
239 |
240 | [[package]]
241 | name = "cfg-if"
242 | version = "1.0.0"
243 | source = "registry+https://github.com/rust-lang/crates.io-index"
244 | checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
245 |
246 | [[package]]
247 | name = "codespan-reporting"
248 | version = "0.11.1"
249 | source = "registry+https://github.com/rust-lang/crates.io-index"
250 | checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
251 | dependencies = [
252 | "termcolor",
253 | "unicode-width",
254 | ]
255 |
256 | [[package]]
257 | name = "const-oid"
258 | version = "0.9.2"
259 | source = "registry+https://github.com/rust-lang/crates.io-index"
260 | checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913"
261 |
262 | [[package]]
263 | name = "core-foundation"
264 | version = "0.9.3"
265 | source = "registry+https://github.com/rust-lang/crates.io-index"
266 | checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
267 | dependencies = [
268 | "core-foundation-sys",
269 | "libc",
270 | ]
271 |
272 | [[package]]
273 | name = "core-foundation-sys"
274 | version = "0.8.4"
275 | source = "registry+https://github.com/rust-lang/crates.io-index"
276 | checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa"
277 |
278 | [[package]]
279 | name = "cpufeatures"
280 | version = "0.2.7"
281 | source = "registry+https://github.com/rust-lang/crates.io-index"
282 | checksum = "3e4c1eaa2012c47becbbad2ab175484c2a84d1185b566fb2cc5b8707343dfe58"
283 | dependencies = [
284 | "libc",
285 | ]
286 |
287 | [[package]]
288 | name = "crc32fast"
289 | version = "1.3.2"
290 | source = "registry+https://github.com/rust-lang/crates.io-index"
291 | checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d"
292 | dependencies = [
293 | "cfg-if",
294 | ]
295 |
296 | [[package]]
297 | name = "crunchy"
298 | version = "0.2.2"
299 | source = "registry+https://github.com/rust-lang/crates.io-index"
300 | checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
301 |
302 | [[package]]
303 | name = "crypto-bigint"
304 | version = "0.4.9"
305 | source = "registry+https://github.com/rust-lang/crates.io-index"
306 | checksum = "ef2b4b23cddf68b89b8f8069890e8c270d54e2d5fe1b143820234805e4cb17ef"
307 | dependencies = [
308 | "generic-array",
309 | "rand_core",
310 | "subtle",
311 | "zeroize",
312 | ]
313 |
314 | [[package]]
315 | name = "crypto-common"
316 | version = "0.1.6"
317 | source = "registry+https://github.com/rust-lang/crates.io-index"
318 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
319 | dependencies = [
320 | "generic-array",
321 | "typenum",
322 | ]
323 |
324 | [[package]]
325 | name = "ct-codecs"
326 | version = "1.1.1"
327 | source = "registry+https://github.com/rust-lang/crates.io-index"
328 | checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df"
329 |
330 | [[package]]
331 | name = "data-encoding"
332 | version = "2.3.3"
333 | source = "registry+https://github.com/rust-lang/crates.io-index"
334 | checksum = "23d8666cb01533c39dde32bcbab8e227b4ed6679b2c925eba05feabea39508fb"
335 |
336 | [[package]]
337 | name = "der"
338 | version = "0.6.1"
339 | source = "registry+https://github.com/rust-lang/crates.io-index"
340 | checksum = "f1a467a65c5e759bce6e65eaf91cc29f466cdc57cb65777bd646872a8a1fd4de"
341 | dependencies = [
342 | "const-oid",
343 | "pem-rfc7468",
344 | "zeroize",
345 | ]
346 |
347 | [[package]]
348 | name = "diff"
349 | version = "0.1.13"
350 | source = "registry+https://github.com/rust-lang/crates.io-index"
351 | checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
352 |
353 | [[package]]
354 | name = "digest"
355 | version = "0.9.0"
356 | source = "registry+https://github.com/rust-lang/crates.io-index"
357 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
358 | dependencies = [
359 | "generic-array",
360 | ]
361 |
362 | [[package]]
363 | name = "digest"
364 | version = "0.10.6"
365 | source = "registry+https://github.com/rust-lang/crates.io-index"
366 | checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
367 | dependencies = [
368 | "block-buffer 0.10.4",
369 | "crypto-common",
370 | "subtle",
371 | ]
372 |
373 | [[package]]
374 | name = "dirs-next"
375 | version = "2.0.0"
376 | source = "registry+https://github.com/rust-lang/crates.io-index"
377 | checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
378 | dependencies = [
379 | "cfg-if",
380 | "dirs-sys-next",
381 | ]
382 |
383 | [[package]]
384 | name = "dirs-sys-next"
385 | version = "0.1.2"
386 | source = "registry+https://github.com/rust-lang/crates.io-index"
387 | checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
388 | dependencies = [
389 | "libc",
390 | "redox_users",
391 | "winapi",
392 | ]
393 |
394 | [[package]]
395 | name = "ecdsa"
396 | version = "0.14.8"
397 | source = "registry+https://github.com/rust-lang/crates.io-index"
398 | checksum = "413301934810f597c1d19ca71c8710e99a3f1ba28a0d2ebc01551a2daeea3c5c"
399 | dependencies = [
400 | "der",
401 | "elliptic-curve",
402 | "rfc6979",
403 | "signature",
404 | ]
405 |
406 | [[package]]
407 | name = "ed25519-compact"
408 | version = "2.0.4"
409 | source = "registry+https://github.com/rust-lang/crates.io-index"
410 | checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c"
411 | dependencies = [
412 | "ct-codecs",
413 | "getrandom",
414 | ]
415 |
416 | [[package]]
417 | name = "either"
418 | version = "1.8.1"
419 | source = "registry+https://github.com/rust-lang/crates.io-index"
420 | checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91"
421 |
422 | [[package]]
423 | name = "elliptic-curve"
424 | version = "0.12.3"
425 | source = "registry+https://github.com/rust-lang/crates.io-index"
426 | checksum = "e7bb888ab5300a19b8e5bceef25ac745ad065f3c9f7efc6de1b91958110891d3"
427 | dependencies = [
428 | "base16ct",
429 | "crypto-bigint",
430 | "der",
431 | "digest 0.10.6",
432 | "ff",
433 | "generic-array",
434 | "group",
435 | "pem-rfc7468",
436 | "pkcs8",
437 | "rand_core",
438 | "sec1",
439 | "subtle",
440 | "zeroize",
441 | ]
442 |
443 | [[package]]
444 | name = "ena"
445 | version = "0.14.2"
446 | source = "registry+https://github.com/rust-lang/crates.io-index"
447 | checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
448 | dependencies = [
449 | "log",
450 | ]
451 |
452 | [[package]]
453 | name = "encoding_rs"
454 | version = "0.8.32"
455 | source = "registry+https://github.com/rust-lang/crates.io-index"
456 | checksum = "071a31f4ee85403370b58aca746f01041ede6f0da2730960ad001edc2b71b394"
457 | dependencies = [
458 | "cfg-if",
459 | ]
460 |
461 | [[package]]
462 | name = "errno"
463 | version = "0.3.1"
464 | source = "registry+https://github.com/rust-lang/crates.io-index"
465 | checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
466 | dependencies = [
467 | "errno-dragonfly",
468 | "libc",
469 | "windows-sys 0.48.0",
470 | ]
471 |
472 | [[package]]
473 | name = "errno-dragonfly"
474 | version = "0.1.2"
475 | source = "registry+https://github.com/rust-lang/crates.io-index"
476 | checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
477 | dependencies = [
478 | "cc",
479 | "libc",
480 | ]
481 |
482 | [[package]]
483 | name = "ezsockets"
484 | version = "0.4.4"
485 | source = "registry+https://github.com/rust-lang/crates.io-index"
486 | checksum = "dc95748c98d978f932b9365fd71ceda0b5e9a55738779b6aff1e66ebf2a81561"
487 | dependencies = [
488 | "async-trait",
489 | "base64 0.21.0",
490 | "cfg-if",
491 | "futures",
492 | "http",
493 | "tokio",
494 | "tokio-tungstenite",
495 | "tracing",
496 | "url",
497 | ]
498 |
499 | [[package]]
500 | name = "ff"
501 | version = "0.12.1"
502 | source = "registry+https://github.com/rust-lang/crates.io-index"
503 | checksum = "d013fc25338cc558c5c2cfbad646908fb23591e2404481826742b651c9af7160"
504 | dependencies = [
505 | "rand_core",
506 | "subtle",
507 | ]
508 |
509 | [[package]]
510 | name = "fixedbitset"
511 | version = "0.4.2"
512 | source = "registry+https://github.com/rust-lang/crates.io-index"
513 | checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
514 |
515 | [[package]]
516 | name = "fnv"
517 | version = "1.0.7"
518 | source = "registry+https://github.com/rust-lang/crates.io-index"
519 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
520 |
521 | [[package]]
522 | name = "form_urlencoded"
523 | version = "1.1.0"
524 | source = "registry+https://github.com/rust-lang/crates.io-index"
525 | checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8"
526 | dependencies = [
527 | "percent-encoding",
528 | ]
529 |
530 | [[package]]
531 | name = "futures"
532 | version = "0.3.28"
533 | source = "registry+https://github.com/rust-lang/crates.io-index"
534 | checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40"
535 | dependencies = [
536 | "futures-channel",
537 | "futures-core",
538 | "futures-executor",
539 | "futures-io",
540 | "futures-sink",
541 | "futures-task",
542 | "futures-util",
543 | ]
544 |
545 | [[package]]
546 | name = "futures-channel"
547 | version = "0.3.28"
548 | source = "registry+https://github.com/rust-lang/crates.io-index"
549 | checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2"
550 | dependencies = [
551 | "futures-core",
552 | "futures-sink",
553 | ]
554 |
555 | [[package]]
556 | name = "futures-core"
557 | version = "0.3.28"
558 | source = "registry+https://github.com/rust-lang/crates.io-index"
559 | checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c"
560 |
561 | [[package]]
562 | name = "futures-executor"
563 | version = "0.3.28"
564 | source = "registry+https://github.com/rust-lang/crates.io-index"
565 | checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0"
566 | dependencies = [
567 | "futures-core",
568 | "futures-task",
569 | "futures-util",
570 | ]
571 |
572 | [[package]]
573 | name = "futures-io"
574 | version = "0.3.28"
575 | source = "registry+https://github.com/rust-lang/crates.io-index"
576 | checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964"
577 |
578 | [[package]]
579 | name = "futures-macro"
580 | version = "0.3.28"
581 | source = "registry+https://github.com/rust-lang/crates.io-index"
582 | checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
583 | dependencies = [
584 | "proc-macro2",
585 | "quote",
586 | "syn 2.0.15",
587 | ]
588 |
589 | [[package]]
590 | name = "futures-sink"
591 | version = "0.3.28"
592 | source = "registry+https://github.com/rust-lang/crates.io-index"
593 | checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e"
594 |
595 | [[package]]
596 | name = "futures-task"
597 | version = "0.3.28"
598 | source = "registry+https://github.com/rust-lang/crates.io-index"
599 | checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65"
600 |
601 | [[package]]
602 | name = "futures-util"
603 | version = "0.3.28"
604 | source = "registry+https://github.com/rust-lang/crates.io-index"
605 | checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533"
606 | dependencies = [
607 | "futures-channel",
608 | "futures-core",
609 | "futures-io",
610 | "futures-macro",
611 | "futures-sink",
612 | "futures-task",
613 | "memchr",
614 | "pin-project-lite",
615 | "pin-utils",
616 | "slab",
617 | ]
618 |
619 | [[package]]
620 | name = "generic-array"
621 | version = "0.14.7"
622 | source = "registry+https://github.com/rust-lang/crates.io-index"
623 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
624 | dependencies = [
625 | "typenum",
626 | "version_check",
627 | ]
628 |
629 | [[package]]
630 | name = "getrandom"
631 | version = "0.2.9"
632 | source = "registry+https://github.com/rust-lang/crates.io-index"
633 | checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4"
634 | dependencies = [
635 | "cfg-if",
636 | "libc",
637 | "wasi",
638 | ]
639 |
640 | [[package]]
641 | name = "group"
642 | version = "0.12.1"
643 | source = "registry+https://github.com/rust-lang/crates.io-index"
644 | checksum = "5dfbfb3a6cfbd390d5c9564ab283a0349b9b9fcd46a706c1eb10e0db70bfbac7"
645 | dependencies = [
646 | "ff",
647 | "rand_core",
648 | "subtle",
649 | ]
650 |
651 | [[package]]
652 | name = "h2"
653 | version = "0.3.18"
654 | source = "registry+https://github.com/rust-lang/crates.io-index"
655 | checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21"
656 | dependencies = [
657 | "bytes",
658 | "fnv",
659 | "futures-core",
660 | "futures-sink",
661 | "futures-util",
662 | "http",
663 | "indexmap",
664 | "slab",
665 | "tokio",
666 | "tokio-util",
667 | "tracing",
668 | ]
669 |
670 | [[package]]
671 | name = "half"
672 | version = "1.8.2"
673 | source = "registry+https://github.com/rust-lang/crates.io-index"
674 | checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7"
675 |
676 | [[package]]
677 | name = "hashbrown"
678 | version = "0.12.3"
679 | source = "registry+https://github.com/rust-lang/crates.io-index"
680 | checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
681 |
682 | [[package]]
683 | name = "hermit-abi"
684 | version = "0.2.6"
685 | source = "registry+https://github.com/rust-lang/crates.io-index"
686 | checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
687 | dependencies = [
688 | "libc",
689 | ]
690 |
691 | [[package]]
692 | name = "hermit-abi"
693 | version = "0.3.1"
694 | source = "registry+https://github.com/rust-lang/crates.io-index"
695 | checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
696 |
697 | [[package]]
698 | name = "hex"
699 | version = "0.4.3"
700 | source = "registry+https://github.com/rust-lang/crates.io-index"
701 | checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
702 |
703 | [[package]]
704 | name = "hmac"
705 | version = "0.12.1"
706 | source = "registry+https://github.com/rust-lang/crates.io-index"
707 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
708 | dependencies = [
709 | "digest 0.10.6",
710 | ]
711 |
712 | [[package]]
713 | name = "http"
714 | version = "0.2.9"
715 | source = "registry+https://github.com/rust-lang/crates.io-index"
716 | checksum = "bd6effc99afb63425aff9b05836f029929e345a6148a14b7ecd5ab67af944482"
717 | dependencies = [
718 | "bytes",
719 | "fnv",
720 | "itoa",
721 | ]
722 |
723 | [[package]]
724 | name = "http-body"
725 | version = "0.4.5"
726 | source = "registry+https://github.com/rust-lang/crates.io-index"
727 | checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
728 | dependencies = [
729 | "bytes",
730 | "http",
731 | "pin-project-lite",
732 | ]
733 |
734 | [[package]]
735 | name = "httparse"
736 | version = "1.8.0"
737 | source = "registry+https://github.com/rust-lang/crates.io-index"
738 | checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
739 |
740 | [[package]]
741 | name = "httpdate"
742 | version = "1.0.2"
743 | source = "registry+https://github.com/rust-lang/crates.io-index"
744 | checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421"
745 |
746 | [[package]]
747 | name = "hyper"
748 | version = "0.14.26"
749 | source = "registry+https://github.com/rust-lang/crates.io-index"
750 | checksum = "ab302d72a6f11a3b910431ff93aae7e773078c769f0a3ef15fb9ec692ed147d4"
751 | dependencies = [
752 | "bytes",
753 | "futures-channel",
754 | "futures-core",
755 | "futures-util",
756 | "h2",
757 | "http",
758 | "http-body",
759 | "httparse",
760 | "httpdate",
761 | "itoa",
762 | "pin-project-lite",
763 | "socket2",
764 | "tokio",
765 | "tower-service",
766 | "tracing",
767 | "want",
768 | ]
769 |
770 | [[package]]
771 | name = "hyper-rustls"
772 | version = "0.23.2"
773 | source = "registry+https://github.com/rust-lang/crates.io-index"
774 | checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c"
775 | dependencies = [
776 | "http",
777 | "hyper",
778 | "log",
779 | "rustls",
780 | "rustls-native-certs",
781 | "tokio",
782 | "tokio-rustls",
783 | "webpki-roots",
784 | ]
785 |
786 | [[package]]
787 | name = "ic-agent"
788 | version = "0.23.2"
789 | source = "registry+https://github.com/rust-lang/crates.io-index"
790 | checksum = "59cadbe5208d33c651ea55d56eb1c38a6f917dc836cc93973faa4bb0a95b71b5"
791 | dependencies = [
792 | "async-trait",
793 | "backoff",
794 | "base32",
795 | "base64 0.13.1",
796 | "byteorder",
797 | "candid",
798 | "futures-util",
799 | "hex",
800 | "http",
801 | "http-body",
802 | "hyper-rustls",
803 | "ic-certification",
804 | "ic-verify-bls-signature",
805 | "k256",
806 | "leb128",
807 | "mime",
808 | "pem",
809 | "pkcs8",
810 | "rand",
811 | "reqwest",
812 | "ring",
813 | "rustls",
814 | "sec1",
815 | "serde",
816 | "serde_bytes",
817 | "serde_cbor",
818 | "sha2 0.10.6",
819 | "simple_asn1",
820 | "thiserror",
821 | "tokio",
822 | "url",
823 | ]
824 |
825 | [[package]]
826 | name = "ic-cdk"
827 | version = "0.7.4"
828 | source = "registry+https://github.com/rust-lang/crates.io-index"
829 | checksum = "9beb0bf1dcd0639c313630e34aa547a2b19450ddf1969c176e13225ef3b29048"
830 | dependencies = [
831 | "candid",
832 | "ic-cdk-macros",
833 | "ic0",
834 | "serde",
835 | "serde_bytes",
836 | ]
837 |
838 | [[package]]
839 | name = "ic-cdk-macros"
840 | version = "0.6.10"
841 | source = "registry+https://github.com/rust-lang/crates.io-index"
842 | checksum = "ebf50458685a0fc6b0e414cdba487610aeb199ac94db52d9fd76270565debee7"
843 | dependencies = [
844 | "candid",
845 | "proc-macro2",
846 | "quote",
847 | "serde",
848 | "serde_tokenstream",
849 | "syn 1.0.109",
850 | ]
851 |
852 | [[package]]
853 | name = "ic-certification"
854 | version = "0.23.2"
855 | source = "registry+https://github.com/rust-lang/crates.io-index"
856 | checksum = "beb68e0ea2fe6b533ddab6ae2142274f9669acacbacd83ac64bb1cd268d33104"
857 | dependencies = [
858 | "hex",
859 | "serde",
860 | "serde_bytes",
861 | "sha2 0.10.6",
862 | ]
863 |
864 | [[package]]
865 | name = "ic-verify-bls-signature"
866 | version = "0.1.0"
867 | source = "registry+https://github.com/rust-lang/crates.io-index"
868 | checksum = "583b1c03380cf86059160cc6c91dcbf56c7b5f141bf3a4f06bc79762d775fac4"
869 | dependencies = [
870 | "bls12_381",
871 | "lazy_static",
872 | "pairing",
873 | "sha2 0.9.9",
874 | ]
875 |
876 | [[package]]
877 | name = "ic0"
878 | version = "0.18.9"
879 | source = "registry+https://github.com/rust-lang/crates.io-index"
880 | checksum = "978b91fc78de9d2eb0144db717839cde3b35470199ea51aca362cb6310e93dfd"
881 |
882 | [[package]]
883 | name = "ic_websocket_gateway"
884 | version = "0.1.0"
885 | dependencies = [
886 | "async-trait",
887 | "candid",
888 | "ed25519-compact",
889 | "ezsockets",
890 | "ic-agent",
891 | "ic-cdk",
892 | "ic-cdk-macros",
893 | "ring",
894 | "serde",
895 | "serde_bytes",
896 | "serde_cbor",
897 | "tokio",
898 | "tungstenite 0.16.0",
899 | ]
900 |
901 | [[package]]
902 | name = "idna"
903 | version = "0.3.0"
904 | source = "registry+https://github.com/rust-lang/crates.io-index"
905 | checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
906 | dependencies = [
907 | "unicode-bidi",
908 | "unicode-normalization",
909 | ]
910 |
911 | [[package]]
912 | name = "indexmap"
913 | version = "1.9.3"
914 | source = "registry+https://github.com/rust-lang/crates.io-index"
915 | checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
916 | dependencies = [
917 | "autocfg",
918 | "hashbrown",
919 | ]
920 |
921 | [[package]]
922 | name = "instant"
923 | version = "0.1.12"
924 | source = "registry+https://github.com/rust-lang/crates.io-index"
925 | checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
926 | dependencies = [
927 | "cfg-if",
928 | ]
929 |
930 | [[package]]
931 | name = "io-lifetimes"
932 | version = "1.0.10"
933 | source = "registry+https://github.com/rust-lang/crates.io-index"
934 | checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
935 | dependencies = [
936 | "hermit-abi 0.3.1",
937 | "libc",
938 | "windows-sys 0.48.0",
939 | ]
940 |
941 | [[package]]
942 | name = "ipnet"
943 | version = "2.7.2"
944 | source = "registry+https://github.com/rust-lang/crates.io-index"
945 | checksum = "12b6ee2129af8d4fb011108c73d99a1b83a85977f23b82460c0ae2e25bb4b57f"
946 |
947 | [[package]]
948 | name = "is-terminal"
949 | version = "0.4.7"
950 | source = "registry+https://github.com/rust-lang/crates.io-index"
951 | checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
952 | dependencies = [
953 | "hermit-abi 0.3.1",
954 | "io-lifetimes",
955 | "rustix",
956 | "windows-sys 0.48.0",
957 | ]
958 |
959 | [[package]]
960 | name = "itertools"
961 | version = "0.10.5"
962 | source = "registry+https://github.com/rust-lang/crates.io-index"
963 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
964 | dependencies = [
965 | "either",
966 | ]
967 |
968 | [[package]]
969 | name = "itoa"
970 | version = "1.0.6"
971 | source = "registry+https://github.com/rust-lang/crates.io-index"
972 | checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
973 |
974 | [[package]]
975 | name = "js-sys"
976 | version = "0.3.62"
977 | source = "registry+https://github.com/rust-lang/crates.io-index"
978 | checksum = "68c16e1bfd491478ab155fd8b4896b86f9ede344949b641e61501e07c2b8b4d5"
979 | dependencies = [
980 | "wasm-bindgen",
981 | ]
982 |
983 | [[package]]
984 | name = "k256"
985 | version = "0.11.6"
986 | source = "registry+https://github.com/rust-lang/crates.io-index"
987 | checksum = "72c1e0b51e7ec0a97369623508396067a486bd0cbed95a2659a4b863d28cfc8b"
988 | dependencies = [
989 | "cfg-if",
990 | "ecdsa",
991 | "elliptic-curve",
992 | "sha2 0.10.6",
993 | ]
994 |
995 | [[package]]
996 | name = "lalrpop"
997 | version = "0.19.12"
998 | source = "registry+https://github.com/rust-lang/crates.io-index"
999 | checksum = "0a1cbf952127589f2851ab2046af368fd20645491bb4b376f04b7f94d7a9837b"
1000 | dependencies = [
1001 | "ascii-canvas",
1002 | "bit-set",
1003 | "diff",
1004 | "ena",
1005 | "is-terminal",
1006 | "itertools",
1007 | "lalrpop-util",
1008 | "petgraph",
1009 | "regex",
1010 | "regex-syntax 0.6.29",
1011 | "string_cache",
1012 | "term",
1013 | "tiny-keccak",
1014 | "unicode-xid",
1015 | ]
1016 |
1017 | [[package]]
1018 | name = "lalrpop-util"
1019 | version = "0.19.12"
1020 | source = "registry+https://github.com/rust-lang/crates.io-index"
1021 | checksum = "d3c48237b9604c5a4702de6b824e02006c3214327564636aef27c1028a8fa0ed"
1022 | dependencies = [
1023 | "regex",
1024 | ]
1025 |
1026 | [[package]]
1027 | name = "lazy_static"
1028 | version = "1.4.0"
1029 | source = "registry+https://github.com/rust-lang/crates.io-index"
1030 | checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1031 |
1032 | [[package]]
1033 | name = "leb128"
1034 | version = "0.2.5"
1035 | source = "registry+https://github.com/rust-lang/crates.io-index"
1036 | checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
1037 |
1038 | [[package]]
1039 | name = "libc"
1040 | version = "0.2.144"
1041 | source = "registry+https://github.com/rust-lang/crates.io-index"
1042 | checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
1043 |
1044 | [[package]]
1045 | name = "linux-raw-sys"
1046 | version = "0.3.7"
1047 | source = "registry+https://github.com/rust-lang/crates.io-index"
1048 | checksum = "ece97ea872ece730aed82664c424eb4c8291e1ff2480247ccf7409044bc6479f"
1049 |
1050 | [[package]]
1051 | name = "lock_api"
1052 | version = "0.4.9"
1053 | source = "registry+https://github.com/rust-lang/crates.io-index"
1054 | checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df"
1055 | dependencies = [
1056 | "autocfg",
1057 | "scopeguard",
1058 | ]
1059 |
1060 | [[package]]
1061 | name = "log"
1062 | version = "0.4.17"
1063 | source = "registry+https://github.com/rust-lang/crates.io-index"
1064 | checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e"
1065 | dependencies = [
1066 | "cfg-if",
1067 | ]
1068 |
1069 | [[package]]
1070 | name = "logos"
1071 | version = "0.12.1"
1072 | source = "registry+https://github.com/rust-lang/crates.io-index"
1073 | checksum = "bf8b031682c67a8e3d5446840f9573eb7fe26efe7ec8d195c9ac4c0647c502f1"
1074 | dependencies = [
1075 | "logos-derive",
1076 | ]
1077 |
1078 | [[package]]
1079 | name = "logos-derive"
1080 | version = "0.12.1"
1081 | source = "registry+https://github.com/rust-lang/crates.io-index"
1082 | checksum = "a1d849148dbaf9661a6151d1ca82b13bb4c4c128146a88d05253b38d4e2f496c"
1083 | dependencies = [
1084 | "beef",
1085 | "fnv",
1086 | "proc-macro2",
1087 | "quote",
1088 | "regex-syntax 0.6.29",
1089 | "syn 1.0.109",
1090 | ]
1091 |
1092 | [[package]]
1093 | name = "memchr"
1094 | version = "2.5.0"
1095 | source = "registry+https://github.com/rust-lang/crates.io-index"
1096 | checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
1097 |
1098 | [[package]]
1099 | name = "mime"
1100 | version = "0.3.17"
1101 | source = "registry+https://github.com/rust-lang/crates.io-index"
1102 | checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
1103 |
1104 | [[package]]
1105 | name = "mio"
1106 | version = "0.8.6"
1107 | source = "registry+https://github.com/rust-lang/crates.io-index"
1108 | checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9"
1109 | dependencies = [
1110 | "libc",
1111 | "log",
1112 | "wasi",
1113 | "windows-sys 0.45.0",
1114 | ]
1115 |
1116 | [[package]]
1117 | name = "new_debug_unreachable"
1118 | version = "1.0.4"
1119 | source = "registry+https://github.com/rust-lang/crates.io-index"
1120 | checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54"
1121 |
1122 | [[package]]
1123 | name = "num-bigint"
1124 | version = "0.4.3"
1125 | source = "registry+https://github.com/rust-lang/crates.io-index"
1126 | checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f"
1127 | dependencies = [
1128 | "autocfg",
1129 | "num-integer",
1130 | "num-traits",
1131 | "serde",
1132 | ]
1133 |
1134 | [[package]]
1135 | name = "num-integer"
1136 | version = "0.1.45"
1137 | source = "registry+https://github.com/rust-lang/crates.io-index"
1138 | checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
1139 | dependencies = [
1140 | "autocfg",
1141 | "num-traits",
1142 | ]
1143 |
1144 | [[package]]
1145 | name = "num-traits"
1146 | version = "0.2.15"
1147 | source = "registry+https://github.com/rust-lang/crates.io-index"
1148 | checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
1149 | dependencies = [
1150 | "autocfg",
1151 | ]
1152 |
1153 | [[package]]
1154 | name = "num_cpus"
1155 | version = "1.15.0"
1156 | source = "registry+https://github.com/rust-lang/crates.io-index"
1157 | checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
1158 | dependencies = [
1159 | "hermit-abi 0.2.6",
1160 | "libc",
1161 | ]
1162 |
1163 | [[package]]
1164 | name = "num_enum"
1165 | version = "0.5.11"
1166 | source = "registry+https://github.com/rust-lang/crates.io-index"
1167 | checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9"
1168 | dependencies = [
1169 | "num_enum_derive",
1170 | ]
1171 |
1172 | [[package]]
1173 | name = "num_enum_derive"
1174 | version = "0.5.11"
1175 | source = "registry+https://github.com/rust-lang/crates.io-index"
1176 | checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799"
1177 | dependencies = [
1178 | "proc-macro-crate",
1179 | "proc-macro2",
1180 | "quote",
1181 | "syn 1.0.109",
1182 | ]
1183 |
1184 | [[package]]
1185 | name = "once_cell"
1186 | version = "1.17.1"
1187 | source = "registry+https://github.com/rust-lang/crates.io-index"
1188 | checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
1189 |
1190 | [[package]]
1191 | name = "opaque-debug"
1192 | version = "0.3.0"
1193 | source = "registry+https://github.com/rust-lang/crates.io-index"
1194 | checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
1195 |
1196 | [[package]]
1197 | name = "openssl-probe"
1198 | version = "0.1.5"
1199 | source = "registry+https://github.com/rust-lang/crates.io-index"
1200 | checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
1201 |
1202 | [[package]]
1203 | name = "pairing"
1204 | version = "0.22.0"
1205 | source = "registry+https://github.com/rust-lang/crates.io-index"
1206 | checksum = "135590d8bdba2b31346f9cd1fb2a912329f5135e832a4f422942eb6ead8b6b3b"
1207 | dependencies = [
1208 | "group",
1209 | ]
1210 |
1211 | [[package]]
1212 | name = "parking_lot"
1213 | version = "0.12.1"
1214 | source = "registry+https://github.com/rust-lang/crates.io-index"
1215 | checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
1216 | dependencies = [
1217 | "lock_api",
1218 | "parking_lot_core",
1219 | ]
1220 |
1221 | [[package]]
1222 | name = "parking_lot_core"
1223 | version = "0.9.7"
1224 | source = "registry+https://github.com/rust-lang/crates.io-index"
1225 | checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521"
1226 | dependencies = [
1227 | "cfg-if",
1228 | "libc",
1229 | "redox_syscall",
1230 | "smallvec",
1231 | "windows-sys 0.45.0",
1232 | ]
1233 |
1234 | [[package]]
1235 | name = "paste"
1236 | version = "1.0.12"
1237 | source = "registry+https://github.com/rust-lang/crates.io-index"
1238 | checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79"
1239 |
1240 | [[package]]
1241 | name = "pem"
1242 | version = "1.1.1"
1243 | source = "registry+https://github.com/rust-lang/crates.io-index"
1244 | checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8"
1245 | dependencies = [
1246 | "base64 0.13.1",
1247 | ]
1248 |
1249 | [[package]]
1250 | name = "pem-rfc7468"
1251 | version = "0.6.0"
1252 | source = "registry+https://github.com/rust-lang/crates.io-index"
1253 | checksum = "24d159833a9105500e0398934e205e0773f0b27529557134ecfc51c27646adac"
1254 | dependencies = [
1255 | "base64ct",
1256 | ]
1257 |
1258 | [[package]]
1259 | name = "percent-encoding"
1260 | version = "2.2.0"
1261 | source = "registry+https://github.com/rust-lang/crates.io-index"
1262 | checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
1263 |
1264 | [[package]]
1265 | name = "petgraph"
1266 | version = "0.6.3"
1267 | source = "registry+https://github.com/rust-lang/crates.io-index"
1268 | checksum = "4dd7d28ee937e54fe3080c91faa1c3a46c06de6252988a7f4592ba2310ef22a4"
1269 | dependencies = [
1270 | "fixedbitset",
1271 | "indexmap",
1272 | ]
1273 |
1274 | [[package]]
1275 | name = "phf_shared"
1276 | version = "0.10.0"
1277 | source = "registry+https://github.com/rust-lang/crates.io-index"
1278 | checksum = "b6796ad771acdc0123d2a88dc428b5e38ef24456743ddb1744ed628f9815c096"
1279 | dependencies = [
1280 | "siphasher",
1281 | ]
1282 |
1283 | [[package]]
1284 | name = "pin-project-lite"
1285 | version = "0.2.9"
1286 | source = "registry+https://github.com/rust-lang/crates.io-index"
1287 | checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
1288 |
1289 | [[package]]
1290 | name = "pin-utils"
1291 | version = "0.1.0"
1292 | source = "registry+https://github.com/rust-lang/crates.io-index"
1293 | checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
1294 |
1295 | [[package]]
1296 | name = "pkcs8"
1297 | version = "0.9.0"
1298 | source = "registry+https://github.com/rust-lang/crates.io-index"
1299 | checksum = "9eca2c590a5f85da82668fa685c09ce2888b9430e83299debf1f34b65fd4a4ba"
1300 | dependencies = [
1301 | "der",
1302 | "spki",
1303 | ]
1304 |
1305 | [[package]]
1306 | name = "ppv-lite86"
1307 | version = "0.2.17"
1308 | source = "registry+https://github.com/rust-lang/crates.io-index"
1309 | checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
1310 |
1311 | [[package]]
1312 | name = "precomputed-hash"
1313 | version = "0.1.1"
1314 | source = "registry+https://github.com/rust-lang/crates.io-index"
1315 | checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c"
1316 |
1317 | [[package]]
1318 | name = "pretty"
1319 | version = "0.10.0"
1320 | source = "registry+https://github.com/rust-lang/crates.io-index"
1321 | checksum = "ad9940b913ee56ddd94aec2d3cd179dd47068236f42a1a6415ccf9d880ce2a61"
1322 | dependencies = [
1323 | "arrayvec",
1324 | "typed-arena",
1325 | ]
1326 |
1327 | [[package]]
1328 | name = "proc-macro-crate"
1329 | version = "1.3.1"
1330 | source = "registry+https://github.com/rust-lang/crates.io-index"
1331 | checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
1332 | dependencies = [
1333 | "once_cell",
1334 | "toml_edit",
1335 | ]
1336 |
1337 | [[package]]
1338 | name = "proc-macro2"
1339 | version = "1.0.56"
1340 | source = "registry+https://github.com/rust-lang/crates.io-index"
1341 | checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435"
1342 | dependencies = [
1343 | "unicode-ident",
1344 | ]
1345 |
1346 | [[package]]
1347 | name = "quote"
1348 | version = "1.0.27"
1349 | source = "registry+https://github.com/rust-lang/crates.io-index"
1350 | checksum = "8f4f29d145265ec1c483c7c654450edde0bfe043d3938d6972630663356d9500"
1351 | dependencies = [
1352 | "proc-macro2",
1353 | ]
1354 |
1355 | [[package]]
1356 | name = "rand"
1357 | version = "0.8.5"
1358 | source = "registry+https://github.com/rust-lang/crates.io-index"
1359 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
1360 | dependencies = [
1361 | "libc",
1362 | "rand_chacha",
1363 | "rand_core",
1364 | ]
1365 |
1366 | [[package]]
1367 | name = "rand_chacha"
1368 | version = "0.3.1"
1369 | source = "registry+https://github.com/rust-lang/crates.io-index"
1370 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
1371 | dependencies = [
1372 | "ppv-lite86",
1373 | "rand_core",
1374 | ]
1375 |
1376 | [[package]]
1377 | name = "rand_core"
1378 | version = "0.6.4"
1379 | source = "registry+https://github.com/rust-lang/crates.io-index"
1380 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
1381 | dependencies = [
1382 | "getrandom",
1383 | ]
1384 |
1385 | [[package]]
1386 | name = "redox_syscall"
1387 | version = "0.2.16"
1388 | source = "registry+https://github.com/rust-lang/crates.io-index"
1389 | checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a"
1390 | dependencies = [
1391 | "bitflags",
1392 | ]
1393 |
1394 | [[package]]
1395 | name = "redox_users"
1396 | version = "0.4.3"
1397 | source = "registry+https://github.com/rust-lang/crates.io-index"
1398 | checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
1399 | dependencies = [
1400 | "getrandom",
1401 | "redox_syscall",
1402 | "thiserror",
1403 | ]
1404 |
1405 | [[package]]
1406 | name = "regex"
1407 | version = "1.8.1"
1408 | source = "registry+https://github.com/rust-lang/crates.io-index"
1409 | checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370"
1410 | dependencies = [
1411 | "aho-corasick",
1412 | "memchr",
1413 | "regex-syntax 0.7.1",
1414 | ]
1415 |
1416 | [[package]]
1417 | name = "regex-syntax"
1418 | version = "0.6.29"
1419 | source = "registry+https://github.com/rust-lang/crates.io-index"
1420 | checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
1421 |
1422 | [[package]]
1423 | name = "regex-syntax"
1424 | version = "0.7.1"
1425 | source = "registry+https://github.com/rust-lang/crates.io-index"
1426 | checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c"
1427 |
1428 | [[package]]
1429 | name = "reqwest"
1430 | version = "0.11.17"
1431 | source = "registry+https://github.com/rust-lang/crates.io-index"
1432 | checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91"
1433 | dependencies = [
1434 | "base64 0.21.0",
1435 | "bytes",
1436 | "encoding_rs",
1437 | "futures-core",
1438 | "futures-util",
1439 | "h2",
1440 | "http",
1441 | "http-body",
1442 | "hyper",
1443 | "hyper-rustls",
1444 | "ipnet",
1445 | "js-sys",
1446 | "log",
1447 | "mime",
1448 | "once_cell",
1449 | "percent-encoding",
1450 | "pin-project-lite",
1451 | "rustls",
1452 | "rustls-pemfile",
1453 | "serde",
1454 | "serde_json",
1455 | "serde_urlencoded",
1456 | "tokio",
1457 | "tokio-rustls",
1458 | "tokio-util",
1459 | "tower-service",
1460 | "url",
1461 | "wasm-bindgen",
1462 | "wasm-bindgen-futures",
1463 | "wasm-streams",
1464 | "web-sys",
1465 | "webpki-roots",
1466 | "winreg",
1467 | ]
1468 |
1469 | [[package]]
1470 | name = "rfc6979"
1471 | version = "0.3.1"
1472 | source = "registry+https://github.com/rust-lang/crates.io-index"
1473 | checksum = "7743f17af12fa0b03b803ba12cd6a8d9483a587e89c69445e3909655c0b9fabb"
1474 | dependencies = [
1475 | "crypto-bigint",
1476 | "hmac",
1477 | "zeroize",
1478 | ]
1479 |
1480 | [[package]]
1481 | name = "ring"
1482 | version = "0.16.20"
1483 | source = "registry+https://github.com/rust-lang/crates.io-index"
1484 | checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc"
1485 | dependencies = [
1486 | "cc",
1487 | "libc",
1488 | "once_cell",
1489 | "spin",
1490 | "untrusted",
1491 | "web-sys",
1492 | "winapi",
1493 | ]
1494 |
1495 | [[package]]
1496 | name = "rustix"
1497 | version = "0.37.19"
1498 | source = "registry+https://github.com/rust-lang/crates.io-index"
1499 | checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
1500 | dependencies = [
1501 | "bitflags",
1502 | "errno",
1503 | "io-lifetimes",
1504 | "libc",
1505 | "linux-raw-sys",
1506 | "windows-sys 0.48.0",
1507 | ]
1508 |
1509 | [[package]]
1510 | name = "rustls"
1511 | version = "0.20.8"
1512 | source = "registry+https://github.com/rust-lang/crates.io-index"
1513 | checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f"
1514 | dependencies = [
1515 | "log",
1516 | "ring",
1517 | "sct",
1518 | "webpki",
1519 | ]
1520 |
1521 | [[package]]
1522 | name = "rustls-native-certs"
1523 | version = "0.6.2"
1524 | source = "registry+https://github.com/rust-lang/crates.io-index"
1525 | checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50"
1526 | dependencies = [
1527 | "openssl-probe",
1528 | "rustls-pemfile",
1529 | "schannel",
1530 | "security-framework",
1531 | ]
1532 |
1533 | [[package]]
1534 | name = "rustls-pemfile"
1535 | version = "1.0.2"
1536 | source = "registry+https://github.com/rust-lang/crates.io-index"
1537 | checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
1538 | dependencies = [
1539 | "base64 0.21.0",
1540 | ]
1541 |
1542 | [[package]]
1543 | name = "rustversion"
1544 | version = "1.0.12"
1545 | source = "registry+https://github.com/rust-lang/crates.io-index"
1546 | checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06"
1547 |
1548 | [[package]]
1549 | name = "ryu"
1550 | version = "1.0.13"
1551 | source = "registry+https://github.com/rust-lang/crates.io-index"
1552 | checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041"
1553 |
1554 | [[package]]
1555 | name = "schannel"
1556 | version = "0.1.21"
1557 | source = "registry+https://github.com/rust-lang/crates.io-index"
1558 | checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3"
1559 | dependencies = [
1560 | "windows-sys 0.42.0",
1561 | ]
1562 |
1563 | [[package]]
1564 | name = "scopeguard"
1565 | version = "1.1.0"
1566 | source = "registry+https://github.com/rust-lang/crates.io-index"
1567 | checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
1568 |
1569 | [[package]]
1570 | name = "sct"
1571 | version = "0.7.0"
1572 | source = "registry+https://github.com/rust-lang/crates.io-index"
1573 | checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4"
1574 | dependencies = [
1575 | "ring",
1576 | "untrusted",
1577 | ]
1578 |
1579 | [[package]]
1580 | name = "sec1"
1581 | version = "0.3.0"
1582 | source = "registry+https://github.com/rust-lang/crates.io-index"
1583 | checksum = "3be24c1842290c45df0a7bf069e0c268a747ad05a192f2fd7dcfdbc1cba40928"
1584 | dependencies = [
1585 | "base16ct",
1586 | "der",
1587 | "generic-array",
1588 | "pkcs8",
1589 | "subtle",
1590 | "zeroize",
1591 | ]
1592 |
1593 | [[package]]
1594 | name = "security-framework"
1595 | version = "2.8.2"
1596 | source = "registry+https://github.com/rust-lang/crates.io-index"
1597 | checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254"
1598 | dependencies = [
1599 | "bitflags",
1600 | "core-foundation",
1601 | "core-foundation-sys",
1602 | "libc",
1603 | "security-framework-sys",
1604 | ]
1605 |
1606 | [[package]]
1607 | name = "security-framework-sys"
1608 | version = "2.8.0"
1609 | source = "registry+https://github.com/rust-lang/crates.io-index"
1610 | checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4"
1611 | dependencies = [
1612 | "core-foundation-sys",
1613 | "libc",
1614 | ]
1615 |
1616 | [[package]]
1617 | name = "serde"
1618 | version = "1.0.163"
1619 | source = "registry+https://github.com/rust-lang/crates.io-index"
1620 | checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
1621 | dependencies = [
1622 | "serde_derive",
1623 | ]
1624 |
1625 | [[package]]
1626 | name = "serde_bytes"
1627 | version = "0.11.9"
1628 | source = "registry+https://github.com/rust-lang/crates.io-index"
1629 | checksum = "416bda436f9aab92e02c8e10d49a15ddd339cea90b6e340fe51ed97abb548294"
1630 | dependencies = [
1631 | "serde",
1632 | ]
1633 |
1634 | [[package]]
1635 | name = "serde_cbor"
1636 | version = "0.11.2"
1637 | source = "registry+https://github.com/rust-lang/crates.io-index"
1638 | checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5"
1639 | dependencies = [
1640 | "half",
1641 | "serde",
1642 | ]
1643 |
1644 | [[package]]
1645 | name = "serde_derive"
1646 | version = "1.0.163"
1647 | source = "registry+https://github.com/rust-lang/crates.io-index"
1648 | checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
1649 | dependencies = [
1650 | "proc-macro2",
1651 | "quote",
1652 | "syn 2.0.15",
1653 | ]
1654 |
1655 | [[package]]
1656 | name = "serde_json"
1657 | version = "1.0.96"
1658 | source = "registry+https://github.com/rust-lang/crates.io-index"
1659 | checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1"
1660 | dependencies = [
1661 | "itoa",
1662 | "ryu",
1663 | "serde",
1664 | ]
1665 |
1666 | [[package]]
1667 | name = "serde_tokenstream"
1668 | version = "0.1.7"
1669 | source = "registry+https://github.com/rust-lang/crates.io-index"
1670 | checksum = "797ba1d80299b264f3aac68ab5d12e5825a561749db4df7cd7c8083900c5d4e9"
1671 | dependencies = [
1672 | "proc-macro2",
1673 | "serde",
1674 | "syn 1.0.109",
1675 | ]
1676 |
1677 | [[package]]
1678 | name = "serde_urlencoded"
1679 | version = "0.7.1"
1680 | source = "registry+https://github.com/rust-lang/crates.io-index"
1681 | checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
1682 | dependencies = [
1683 | "form_urlencoded",
1684 | "itoa",
1685 | "ryu",
1686 | "serde",
1687 | ]
1688 |
1689 | [[package]]
1690 | name = "sha-1"
1691 | version = "0.9.8"
1692 | source = "registry+https://github.com/rust-lang/crates.io-index"
1693 | checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6"
1694 | dependencies = [
1695 | "block-buffer 0.9.0",
1696 | "cfg-if",
1697 | "cpufeatures",
1698 | "digest 0.9.0",
1699 | "opaque-debug",
1700 | ]
1701 |
1702 | [[package]]
1703 | name = "sha1"
1704 | version = "0.10.5"
1705 | source = "registry+https://github.com/rust-lang/crates.io-index"
1706 | checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
1707 | dependencies = [
1708 | "cfg-if",
1709 | "cpufeatures",
1710 | "digest 0.10.6",
1711 | ]
1712 |
1713 | [[package]]
1714 | name = "sha2"
1715 | version = "0.9.9"
1716 | source = "registry+https://github.com/rust-lang/crates.io-index"
1717 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
1718 | dependencies = [
1719 | "block-buffer 0.9.0",
1720 | "cfg-if",
1721 | "cpufeatures",
1722 | "digest 0.9.0",
1723 | "opaque-debug",
1724 | ]
1725 |
1726 | [[package]]
1727 | name = "sha2"
1728 | version = "0.10.6"
1729 | source = "registry+https://github.com/rust-lang/crates.io-index"
1730 | checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0"
1731 | dependencies = [
1732 | "cfg-if",
1733 | "cpufeatures",
1734 | "digest 0.10.6",
1735 | ]
1736 |
1737 | [[package]]
1738 | name = "signal-hook-registry"
1739 | version = "1.4.1"
1740 | source = "registry+https://github.com/rust-lang/crates.io-index"
1741 | checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1"
1742 | dependencies = [
1743 | "libc",
1744 | ]
1745 |
1746 | [[package]]
1747 | name = "signature"
1748 | version = "1.6.4"
1749 | source = "registry+https://github.com/rust-lang/crates.io-index"
1750 | checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
1751 | dependencies = [
1752 | "digest 0.10.6",
1753 | "rand_core",
1754 | ]
1755 |
1756 | [[package]]
1757 | name = "simple_asn1"
1758 | version = "0.6.2"
1759 | source = "registry+https://github.com/rust-lang/crates.io-index"
1760 | checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085"
1761 | dependencies = [
1762 | "num-bigint",
1763 | "num-traits",
1764 | "thiserror",
1765 | "time",
1766 | ]
1767 |
1768 | [[package]]
1769 | name = "siphasher"
1770 | version = "0.3.10"
1771 | source = "registry+https://github.com/rust-lang/crates.io-index"
1772 | checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de"
1773 |
1774 | [[package]]
1775 | name = "slab"
1776 | version = "0.4.8"
1777 | source = "registry+https://github.com/rust-lang/crates.io-index"
1778 | checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d"
1779 | dependencies = [
1780 | "autocfg",
1781 | ]
1782 |
1783 | [[package]]
1784 | name = "smallvec"
1785 | version = "1.10.0"
1786 | source = "registry+https://github.com/rust-lang/crates.io-index"
1787 | checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
1788 |
1789 | [[package]]
1790 | name = "socket2"
1791 | version = "0.4.9"
1792 | source = "registry+https://github.com/rust-lang/crates.io-index"
1793 | checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662"
1794 | dependencies = [
1795 | "libc",
1796 | "winapi",
1797 | ]
1798 |
1799 | [[package]]
1800 | name = "spin"
1801 | version = "0.5.2"
1802 | source = "registry+https://github.com/rust-lang/crates.io-index"
1803 | checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
1804 |
1805 | [[package]]
1806 | name = "spki"
1807 | version = "0.6.0"
1808 | source = "registry+https://github.com/rust-lang/crates.io-index"
1809 | checksum = "67cf02bbac7a337dc36e4f5a693db6c21e7863f45070f7064577eb4367a3212b"
1810 | dependencies = [
1811 | "base64ct",
1812 | "der",
1813 | ]
1814 |
1815 | [[package]]
1816 | name = "string_cache"
1817 | version = "0.8.7"
1818 | source = "registry+https://github.com/rust-lang/crates.io-index"
1819 | checksum = "f91138e76242f575eb1d3b38b4f1362f10d3a43f47d182a5b359af488a02293b"
1820 | dependencies = [
1821 | "new_debug_unreachable",
1822 | "once_cell",
1823 | "parking_lot",
1824 | "phf_shared",
1825 | "precomputed-hash",
1826 | ]
1827 |
1828 | [[package]]
1829 | name = "subtle"
1830 | version = "2.4.1"
1831 | source = "registry+https://github.com/rust-lang/crates.io-index"
1832 | checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
1833 |
1834 | [[package]]
1835 | name = "syn"
1836 | version = "1.0.109"
1837 | source = "registry+https://github.com/rust-lang/crates.io-index"
1838 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
1839 | dependencies = [
1840 | "proc-macro2",
1841 | "quote",
1842 | "unicode-ident",
1843 | ]
1844 |
1845 | [[package]]
1846 | name = "syn"
1847 | version = "2.0.15"
1848 | source = "registry+https://github.com/rust-lang/crates.io-index"
1849 | checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822"
1850 | dependencies = [
1851 | "proc-macro2",
1852 | "quote",
1853 | "unicode-ident",
1854 | ]
1855 |
1856 | [[package]]
1857 | name = "term"
1858 | version = "0.7.0"
1859 | source = "registry+https://github.com/rust-lang/crates.io-index"
1860 | checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
1861 | dependencies = [
1862 | "dirs-next",
1863 | "rustversion",
1864 | "winapi",
1865 | ]
1866 |
1867 | [[package]]
1868 | name = "termcolor"
1869 | version = "1.2.0"
1870 | source = "registry+https://github.com/rust-lang/crates.io-index"
1871 | checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
1872 | dependencies = [
1873 | "winapi-util",
1874 | ]
1875 |
1876 | [[package]]
1877 | name = "thiserror"
1878 | version = "1.0.40"
1879 | source = "registry+https://github.com/rust-lang/crates.io-index"
1880 | checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
1881 | dependencies = [
1882 | "thiserror-impl",
1883 | ]
1884 |
1885 | [[package]]
1886 | name = "thiserror-impl"
1887 | version = "1.0.40"
1888 | source = "registry+https://github.com/rust-lang/crates.io-index"
1889 | checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
1890 | dependencies = [
1891 | "proc-macro2",
1892 | "quote",
1893 | "syn 2.0.15",
1894 | ]
1895 |
1896 | [[package]]
1897 | name = "time"
1898 | version = "0.3.21"
1899 | source = "registry+https://github.com/rust-lang/crates.io-index"
1900 | checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
1901 | dependencies = [
1902 | "itoa",
1903 | "serde",
1904 | "time-core",
1905 | "time-macros",
1906 | ]
1907 |
1908 | [[package]]
1909 | name = "time-core"
1910 | version = "0.1.1"
1911 | source = "registry+https://github.com/rust-lang/crates.io-index"
1912 | checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
1913 |
1914 | [[package]]
1915 | name = "time-macros"
1916 | version = "0.2.9"
1917 | source = "registry+https://github.com/rust-lang/crates.io-index"
1918 | checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b"
1919 | dependencies = [
1920 | "time-core",
1921 | ]
1922 |
1923 | [[package]]
1924 | name = "tiny-keccak"
1925 | version = "2.0.2"
1926 | source = "registry+https://github.com/rust-lang/crates.io-index"
1927 | checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
1928 | dependencies = [
1929 | "crunchy",
1930 | ]
1931 |
1932 | [[package]]
1933 | name = "tinyvec"
1934 | version = "1.6.0"
1935 | source = "registry+https://github.com/rust-lang/crates.io-index"
1936 | checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
1937 | dependencies = [
1938 | "tinyvec_macros",
1939 | ]
1940 |
1941 | [[package]]
1942 | name = "tinyvec_macros"
1943 | version = "0.1.1"
1944 | source = "registry+https://github.com/rust-lang/crates.io-index"
1945 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
1946 |
1947 | [[package]]
1948 | name = "tokio"
1949 | version = "1.28.1"
1950 | source = "registry+https://github.com/rust-lang/crates.io-index"
1951 | checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105"
1952 | dependencies = [
1953 | "autocfg",
1954 | "bytes",
1955 | "libc",
1956 | "mio",
1957 | "num_cpus",
1958 | "parking_lot",
1959 | "pin-project-lite",
1960 | "signal-hook-registry",
1961 | "socket2",
1962 | "tokio-macros",
1963 | "windows-sys 0.48.0",
1964 | ]
1965 |
1966 | [[package]]
1967 | name = "tokio-macros"
1968 | version = "2.1.0"
1969 | source = "registry+https://github.com/rust-lang/crates.io-index"
1970 | checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
1971 | dependencies = [
1972 | "proc-macro2",
1973 | "quote",
1974 | "syn 2.0.15",
1975 | ]
1976 |
1977 | [[package]]
1978 | name = "tokio-rustls"
1979 | version = "0.23.4"
1980 | source = "registry+https://github.com/rust-lang/crates.io-index"
1981 | checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
1982 | dependencies = [
1983 | "rustls",
1984 | "tokio",
1985 | "webpki",
1986 | ]
1987 |
1988 | [[package]]
1989 | name = "tokio-tungstenite"
1990 | version = "0.18.0"
1991 | source = "registry+https://github.com/rust-lang/crates.io-index"
1992 | checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
1993 | dependencies = [
1994 | "futures-util",
1995 | "log",
1996 | "tokio",
1997 | "tungstenite 0.18.0",
1998 | ]
1999 |
2000 | [[package]]
2001 | name = "tokio-util"
2002 | version = "0.7.8"
2003 | source = "registry+https://github.com/rust-lang/crates.io-index"
2004 | checksum = "806fe8c2c87eccc8b3267cbae29ed3ab2d0bd37fca70ab622e46aaa9375ddb7d"
2005 | dependencies = [
2006 | "bytes",
2007 | "futures-core",
2008 | "futures-sink",
2009 | "pin-project-lite",
2010 | "tokio",
2011 | "tracing",
2012 | ]
2013 |
2014 | [[package]]
2015 | name = "toml_datetime"
2016 | version = "0.6.1"
2017 | source = "registry+https://github.com/rust-lang/crates.io-index"
2018 | checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622"
2019 |
2020 | [[package]]
2021 | name = "toml_edit"
2022 | version = "0.19.8"
2023 | source = "registry+https://github.com/rust-lang/crates.io-index"
2024 | checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13"
2025 | dependencies = [
2026 | "indexmap",
2027 | "toml_datetime",
2028 | "winnow",
2029 | ]
2030 |
2031 | [[package]]
2032 | name = "tower-service"
2033 | version = "0.3.2"
2034 | source = "registry+https://github.com/rust-lang/crates.io-index"
2035 | checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52"
2036 |
2037 | [[package]]
2038 | name = "tracing"
2039 | version = "0.1.37"
2040 | source = "registry+https://github.com/rust-lang/crates.io-index"
2041 | checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
2042 | dependencies = [
2043 | "cfg-if",
2044 | "pin-project-lite",
2045 | "tracing-attributes",
2046 | "tracing-core",
2047 | ]
2048 |
2049 | [[package]]
2050 | name = "tracing-attributes"
2051 | version = "0.1.24"
2052 | source = "registry+https://github.com/rust-lang/crates.io-index"
2053 | checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
2054 | dependencies = [
2055 | "proc-macro2",
2056 | "quote",
2057 | "syn 2.0.15",
2058 | ]
2059 |
2060 | [[package]]
2061 | name = "tracing-core"
2062 | version = "0.1.31"
2063 | source = "registry+https://github.com/rust-lang/crates.io-index"
2064 | checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
2065 | dependencies = [
2066 | "once_cell",
2067 | ]
2068 |
2069 | [[package]]
2070 | name = "try-lock"
2071 | version = "0.2.4"
2072 | source = "registry+https://github.com/rust-lang/crates.io-index"
2073 | checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
2074 |
2075 | [[package]]
2076 | name = "tungstenite"
2077 | version = "0.16.0"
2078 | source = "registry+https://github.com/rust-lang/crates.io-index"
2079 | checksum = "6ad3713a14ae247f22a728a0456a545df14acf3867f905adff84be99e23b3ad1"
2080 | dependencies = [
2081 | "base64 0.13.1",
2082 | "byteorder",
2083 | "bytes",
2084 | "http",
2085 | "httparse",
2086 | "log",
2087 | "rand",
2088 | "sha-1",
2089 | "thiserror",
2090 | "url",
2091 | "utf-8",
2092 | ]
2093 |
2094 | [[package]]
2095 | name = "tungstenite"
2096 | version = "0.18.0"
2097 | source = "registry+https://github.com/rust-lang/crates.io-index"
2098 | checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
2099 | dependencies = [
2100 | "base64 0.13.1",
2101 | "byteorder",
2102 | "bytes",
2103 | "http",
2104 | "httparse",
2105 | "log",
2106 | "rand",
2107 | "sha1",
2108 | "thiserror",
2109 | "url",
2110 | "utf-8",
2111 | ]
2112 |
2113 | [[package]]
2114 | name = "typed-arena"
2115 | version = "2.0.2"
2116 | source = "registry+https://github.com/rust-lang/crates.io-index"
2117 | checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
2118 |
2119 | [[package]]
2120 | name = "typenum"
2121 | version = "1.16.0"
2122 | source = "registry+https://github.com/rust-lang/crates.io-index"
2123 | checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
2124 |
2125 | [[package]]
2126 | name = "unicode-bidi"
2127 | version = "0.3.13"
2128 | source = "registry+https://github.com/rust-lang/crates.io-index"
2129 | checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
2130 |
2131 | [[package]]
2132 | name = "unicode-ident"
2133 | version = "1.0.8"
2134 | source = "registry+https://github.com/rust-lang/crates.io-index"
2135 | checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
2136 |
2137 | [[package]]
2138 | name = "unicode-normalization"
2139 | version = "0.1.22"
2140 | source = "registry+https://github.com/rust-lang/crates.io-index"
2141 | checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921"
2142 | dependencies = [
2143 | "tinyvec",
2144 | ]
2145 |
2146 | [[package]]
2147 | name = "unicode-width"
2148 | version = "0.1.10"
2149 | source = "registry+https://github.com/rust-lang/crates.io-index"
2150 | checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
2151 |
2152 | [[package]]
2153 | name = "unicode-xid"
2154 | version = "0.2.4"
2155 | source = "registry+https://github.com/rust-lang/crates.io-index"
2156 | checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c"
2157 |
2158 | [[package]]
2159 | name = "untrusted"
2160 | version = "0.7.1"
2161 | source = "registry+https://github.com/rust-lang/crates.io-index"
2162 | checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
2163 |
2164 | [[package]]
2165 | name = "url"
2166 | version = "2.3.1"
2167 | source = "registry+https://github.com/rust-lang/crates.io-index"
2168 | checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
2169 | dependencies = [
2170 | "form_urlencoded",
2171 | "idna",
2172 | "percent-encoding",
2173 | ]
2174 |
2175 | [[package]]
2176 | name = "utf-8"
2177 | version = "0.7.6"
2178 | source = "registry+https://github.com/rust-lang/crates.io-index"
2179 | checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
2180 |
2181 | [[package]]
2182 | name = "version_check"
2183 | version = "0.9.4"
2184 | source = "registry+https://github.com/rust-lang/crates.io-index"
2185 | checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
2186 |
2187 | [[package]]
2188 | name = "want"
2189 | version = "0.3.0"
2190 | source = "registry+https://github.com/rust-lang/crates.io-index"
2191 | checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0"
2192 | dependencies = [
2193 | "log",
2194 | "try-lock",
2195 | ]
2196 |
2197 | [[package]]
2198 | name = "wasi"
2199 | version = "0.11.0+wasi-snapshot-preview1"
2200 | source = "registry+https://github.com/rust-lang/crates.io-index"
2201 | checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
2202 |
2203 | [[package]]
2204 | name = "wasm-bindgen"
2205 | version = "0.2.85"
2206 | source = "registry+https://github.com/rust-lang/crates.io-index"
2207 | checksum = "5b6cb788c4e39112fbe1822277ef6fb3c55cd86b95cb3d3c4c1c9597e4ac74b4"
2208 | dependencies = [
2209 | "cfg-if",
2210 | "wasm-bindgen-macro",
2211 | ]
2212 |
2213 | [[package]]
2214 | name = "wasm-bindgen-backend"
2215 | version = "0.2.85"
2216 | source = "registry+https://github.com/rust-lang/crates.io-index"
2217 | checksum = "35e522ed4105a9d626d885b35d62501b30d9666283a5c8be12c14a8bdafe7822"
2218 | dependencies = [
2219 | "bumpalo",
2220 | "log",
2221 | "once_cell",
2222 | "proc-macro2",
2223 | "quote",
2224 | "syn 2.0.15",
2225 | "wasm-bindgen-shared",
2226 | ]
2227 |
2228 | [[package]]
2229 | name = "wasm-bindgen-futures"
2230 | version = "0.4.35"
2231 | source = "registry+https://github.com/rust-lang/crates.io-index"
2232 | checksum = "083abe15c5d88556b77bdf7aef403625be9e327ad37c62c4e4129af740168163"
2233 | dependencies = [
2234 | "cfg-if",
2235 | "js-sys",
2236 | "wasm-bindgen",
2237 | "web-sys",
2238 | ]
2239 |
2240 | [[package]]
2241 | name = "wasm-bindgen-macro"
2242 | version = "0.2.85"
2243 | source = "registry+https://github.com/rust-lang/crates.io-index"
2244 | checksum = "358a79a0cb89d21db8120cbfb91392335913e4890665b1a7981d9e956903b434"
2245 | dependencies = [
2246 | "quote",
2247 | "wasm-bindgen-macro-support",
2248 | ]
2249 |
2250 | [[package]]
2251 | name = "wasm-bindgen-macro-support"
2252 | version = "0.2.85"
2253 | source = "registry+https://github.com/rust-lang/crates.io-index"
2254 | checksum = "4783ce29f09b9d93134d41297aded3a712b7b979e9c6f28c32cb88c973a94869"
2255 | dependencies = [
2256 | "proc-macro2",
2257 | "quote",
2258 | "syn 2.0.15",
2259 | "wasm-bindgen-backend",
2260 | "wasm-bindgen-shared",
2261 | ]
2262 |
2263 | [[package]]
2264 | name = "wasm-bindgen-shared"
2265 | version = "0.2.85"
2266 | source = "registry+https://github.com/rust-lang/crates.io-index"
2267 | checksum = "a901d592cafaa4d711bc324edfaff879ac700b19c3dfd60058d2b445be2691eb"
2268 |
2269 | [[package]]
2270 | name = "wasm-streams"
2271 | version = "0.2.3"
2272 | source = "registry+https://github.com/rust-lang/crates.io-index"
2273 | checksum = "6bbae3363c08332cadccd13b67db371814cd214c2524020932f0804b8cf7c078"
2274 | dependencies = [
2275 | "futures-util",
2276 | "js-sys",
2277 | "wasm-bindgen",
2278 | "wasm-bindgen-futures",
2279 | "web-sys",
2280 | ]
2281 |
2282 | [[package]]
2283 | name = "web-sys"
2284 | version = "0.3.62"
2285 | source = "registry+https://github.com/rust-lang/crates.io-index"
2286 | checksum = "16b5f940c7edfdc6d12126d98c9ef4d1b3d470011c47c76a6581df47ad9ba721"
2287 | dependencies = [
2288 | "js-sys",
2289 | "wasm-bindgen",
2290 | ]
2291 |
2292 | [[package]]
2293 | name = "webpki"
2294 | version = "0.22.0"
2295 | source = "registry+https://github.com/rust-lang/crates.io-index"
2296 | checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd"
2297 | dependencies = [
2298 | "ring",
2299 | "untrusted",
2300 | ]
2301 |
2302 | [[package]]
2303 | name = "webpki-roots"
2304 | version = "0.22.6"
2305 | source = "registry+https://github.com/rust-lang/crates.io-index"
2306 | checksum = "b6c71e40d7d2c34a5106301fb632274ca37242cd0c9d3e64dbece371a40a2d87"
2307 | dependencies = [
2308 | "webpki",
2309 | ]
2310 |
2311 | [[package]]
2312 | name = "winapi"
2313 | version = "0.3.9"
2314 | source = "registry+https://github.com/rust-lang/crates.io-index"
2315 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
2316 | dependencies = [
2317 | "winapi-i686-pc-windows-gnu",
2318 | "winapi-x86_64-pc-windows-gnu",
2319 | ]
2320 |
2321 | [[package]]
2322 | name = "winapi-i686-pc-windows-gnu"
2323 | version = "0.4.0"
2324 | source = "registry+https://github.com/rust-lang/crates.io-index"
2325 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
2326 |
2327 | [[package]]
2328 | name = "winapi-util"
2329 | version = "0.1.5"
2330 | source = "registry+https://github.com/rust-lang/crates.io-index"
2331 | checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
2332 | dependencies = [
2333 | "winapi",
2334 | ]
2335 |
2336 | [[package]]
2337 | name = "winapi-x86_64-pc-windows-gnu"
2338 | version = "0.4.0"
2339 | source = "registry+https://github.com/rust-lang/crates.io-index"
2340 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
2341 |
2342 | [[package]]
2343 | name = "windows-sys"
2344 | version = "0.42.0"
2345 | source = "registry+https://github.com/rust-lang/crates.io-index"
2346 | checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
2347 | dependencies = [
2348 | "windows_aarch64_gnullvm 0.42.2",
2349 | "windows_aarch64_msvc 0.42.2",
2350 | "windows_i686_gnu 0.42.2",
2351 | "windows_i686_msvc 0.42.2",
2352 | "windows_x86_64_gnu 0.42.2",
2353 | "windows_x86_64_gnullvm 0.42.2",
2354 | "windows_x86_64_msvc 0.42.2",
2355 | ]
2356 |
2357 | [[package]]
2358 | name = "windows-sys"
2359 | version = "0.45.0"
2360 | source = "registry+https://github.com/rust-lang/crates.io-index"
2361 | checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
2362 | dependencies = [
2363 | "windows-targets 0.42.2",
2364 | ]
2365 |
2366 | [[package]]
2367 | name = "windows-sys"
2368 | version = "0.48.0"
2369 | source = "registry+https://github.com/rust-lang/crates.io-index"
2370 | checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
2371 | dependencies = [
2372 | "windows-targets 0.48.0",
2373 | ]
2374 |
2375 | [[package]]
2376 | name = "windows-targets"
2377 | version = "0.42.2"
2378 | source = "registry+https://github.com/rust-lang/crates.io-index"
2379 | checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
2380 | dependencies = [
2381 | "windows_aarch64_gnullvm 0.42.2",
2382 | "windows_aarch64_msvc 0.42.2",
2383 | "windows_i686_gnu 0.42.2",
2384 | "windows_i686_msvc 0.42.2",
2385 | "windows_x86_64_gnu 0.42.2",
2386 | "windows_x86_64_gnullvm 0.42.2",
2387 | "windows_x86_64_msvc 0.42.2",
2388 | ]
2389 |
2390 | [[package]]
2391 | name = "windows-targets"
2392 | version = "0.48.0"
2393 | source = "registry+https://github.com/rust-lang/crates.io-index"
2394 | checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
2395 | dependencies = [
2396 | "windows_aarch64_gnullvm 0.48.0",
2397 | "windows_aarch64_msvc 0.48.0",
2398 | "windows_i686_gnu 0.48.0",
2399 | "windows_i686_msvc 0.48.0",
2400 | "windows_x86_64_gnu 0.48.0",
2401 | "windows_x86_64_gnullvm 0.48.0",
2402 | "windows_x86_64_msvc 0.48.0",
2403 | ]
2404 |
2405 | [[package]]
2406 | name = "windows_aarch64_gnullvm"
2407 | version = "0.42.2"
2408 | source = "registry+https://github.com/rust-lang/crates.io-index"
2409 | checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
2410 |
2411 | [[package]]
2412 | name = "windows_aarch64_gnullvm"
2413 | version = "0.48.0"
2414 | source = "registry+https://github.com/rust-lang/crates.io-index"
2415 | checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
2416 |
2417 | [[package]]
2418 | name = "windows_aarch64_msvc"
2419 | version = "0.42.2"
2420 | source = "registry+https://github.com/rust-lang/crates.io-index"
2421 | checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
2422 |
2423 | [[package]]
2424 | name = "windows_aarch64_msvc"
2425 | version = "0.48.0"
2426 | source = "registry+https://github.com/rust-lang/crates.io-index"
2427 | checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
2428 |
2429 | [[package]]
2430 | name = "windows_i686_gnu"
2431 | version = "0.42.2"
2432 | source = "registry+https://github.com/rust-lang/crates.io-index"
2433 | checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
2434 |
2435 | [[package]]
2436 | name = "windows_i686_gnu"
2437 | version = "0.48.0"
2438 | source = "registry+https://github.com/rust-lang/crates.io-index"
2439 | checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
2440 |
2441 | [[package]]
2442 | name = "windows_i686_msvc"
2443 | version = "0.42.2"
2444 | source = "registry+https://github.com/rust-lang/crates.io-index"
2445 | checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
2446 |
2447 | [[package]]
2448 | name = "windows_i686_msvc"
2449 | version = "0.48.0"
2450 | source = "registry+https://github.com/rust-lang/crates.io-index"
2451 | checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
2452 |
2453 | [[package]]
2454 | name = "windows_x86_64_gnu"
2455 | version = "0.42.2"
2456 | source = "registry+https://github.com/rust-lang/crates.io-index"
2457 | checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
2458 |
2459 | [[package]]
2460 | name = "windows_x86_64_gnu"
2461 | version = "0.48.0"
2462 | source = "registry+https://github.com/rust-lang/crates.io-index"
2463 | checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
2464 |
2465 | [[package]]
2466 | name = "windows_x86_64_gnullvm"
2467 | version = "0.42.2"
2468 | source = "registry+https://github.com/rust-lang/crates.io-index"
2469 | checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
2470 |
2471 | [[package]]
2472 | name = "windows_x86_64_gnullvm"
2473 | version = "0.48.0"
2474 | source = "registry+https://github.com/rust-lang/crates.io-index"
2475 | checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
2476 |
2477 | [[package]]
2478 | name = "windows_x86_64_msvc"
2479 | version = "0.42.2"
2480 | source = "registry+https://github.com/rust-lang/crates.io-index"
2481 | checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
2482 |
2483 | [[package]]
2484 | name = "windows_x86_64_msvc"
2485 | version = "0.48.0"
2486 | source = "registry+https://github.com/rust-lang/crates.io-index"
2487 | checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
2488 |
2489 | [[package]]
2490 | name = "winnow"
2491 | version = "0.4.6"
2492 | source = "registry+https://github.com/rust-lang/crates.io-index"
2493 | checksum = "61de7bac303dc551fe038e2b3cef0f571087a47571ea6e79a87692ac99b99699"
2494 | dependencies = [
2495 | "memchr",
2496 | ]
2497 |
2498 | [[package]]
2499 | name = "winreg"
2500 | version = "0.10.1"
2501 | source = "registry+https://github.com/rust-lang/crates.io-index"
2502 | checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
2503 | dependencies = [
2504 | "winapi",
2505 | ]
2506 |
2507 | [[package]]
2508 | name = "zeroize"
2509 | version = "1.6.0"
2510 | source = "registry+https://github.com/rust-lang/crates.io-index"
2511 | checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9"
2512 |
--------------------------------------------------------------------------------