├── .gitignore ├── CODEOWNERS ├── LICENSE ├── README.md ├── ic_websocket_canisters ├── Cargo.lock ├── Cargo.toml ├── dfx.json ├── package.json ├── src │ ├── ic_websocket_backend │ │ ├── Cargo.toml │ │ ├── ic_websocket_backend.did │ │ └── src │ │ │ ├── canister.rs │ │ │ ├── lib.rs │ │ │ └── sock.rs │ └── ic_websocket_frontend │ │ ├── assets │ │ ├── favicon.ico │ │ ├── logo2.svg │ │ └── main.css │ │ └── src │ │ ├── index.html │ │ ├── index.js │ │ ├── utils │ │ ├── addNotification.js │ │ ├── parseHTMLString.js │ │ └── validateBody.js │ │ └── websocketConnection.js └── webpack.config.js ├── ic_websocket_gateway ├── Cargo.lock ├── Cargo.toml └── src │ ├── canister_methods.rs │ └── main.rs └── images ├── image1.png └── image2.png /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @dfinity/boundary-node -------------------------------------------------------------------------------- /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 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright 2023 DFINITY Foundation 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /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 | ![](/images/image2.png) 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 | ![](/images/image1.png) 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/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_canisters/Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = [ 3 | "src/ic_websocket_backend", 4 | ] 5 | -------------------------------------------------------------------------------- /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/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_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_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/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_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_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_canisters/src/ic_websocket_frontend/assets/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfinity/ic-websocket-poc/9dc75d84a3e153389559c2cabd9c7dc36a321544/ic_websocket_canisters/src/ic_websocket_frontend/assets/favicon.ico -------------------------------------------------------------------------------- /ic_websocket_canisters/src/ic_websocket_frontend/assets/logo2.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /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/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 |
30 |
31 |
32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /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_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/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/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_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 | -------------------------------------------------------------------------------- /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_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 | -------------------------------------------------------------------------------- /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_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_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 | -------------------------------------------------------------------------------- /images/image1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfinity/ic-websocket-poc/9dc75d84a3e153389559c2cabd9c7dc36a321544/images/image1.png -------------------------------------------------------------------------------- /images/image2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dfinity/ic-websocket-poc/9dc75d84a3e153389559c2cabd9c7dc36a321544/images/image2.png --------------------------------------------------------------------------------