Add ENS domain information

This commit is contained in:
Simon Bihel 2022-01-25 16:29:02 +00:00
parent 452bd2d9fb
commit b34027b096
No known key found for this signature in database
GPG Key ID: B7013150BEAA28FD
9 changed files with 447 additions and 43 deletions

361
Cargo.lock generated
View File

@ -197,6 +197,17 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "async_io_stream"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6d7b9decdf35d8908a7e3ef02f64c5e9b1695e230154c0e8de3969142d9b94c"
dependencies = [
"futures",
"pharos",
"rustc_version 0.4.0",
]
[[package]] [[package]]
name = "atomic" name = "atomic"
version = "0.5.1" version = "0.5.1"
@ -212,6 +223,18 @@ version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a"
[[package]]
name = "auto_impl"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7862e21c893d65a1650125d157eaeec691439379a1cee17ee49031b79236ada4"
dependencies = [
"proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "0.1.7" version = "0.1.7"
@ -528,6 +551,22 @@ dependencies = [
"version_check", "version_check",
] ]
[[package]]
name = "core-foundation"
version = "0.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
[[package]] [[package]]
name = "cpufeatures" name = "cpufeatures"
version = "0.2.1" version = "0.2.1"
@ -778,6 +817,40 @@ dependencies = [
"tiny-keccak", "tiny-keccak",
] ]
[[package]]
name = "ethers-providers"
version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e68d511a99f39a26c9b32a6f62360789ba0e214d8f4c012bf1fbdc7b00da0e4f"
dependencies = [
"async-trait",
"auto_impl",
"bytes",
"ethers-core",
"futures-channel",
"futures-core",
"futures-timer",
"futures-util",
"hex",
"parking_lot",
"pin-project",
"reqwest",
"serde",
"serde_json",
"thiserror",
"tokio",
"tokio-tungstenite",
"tokio-util",
"tracing",
"tracing-futures",
"url",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-timer",
"web-sys",
"ws_stream_wasm",
]
[[package]] [[package]]
name = "event-listener" name = "event-listener"
version = "2.5.1" version = "2.5.1"
@ -937,6 +1010,12 @@ version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72" checksum = "6ee7c6485c30167ce4dfb83ac568a849fe53274c831081476ee13e0dce1aad72"
[[package]]
name = "futures-timer"
version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c"
[[package]] [[package]]
name = "futures-util" name = "futures-util"
version = "0.3.19" version = "0.3.19"
@ -1149,9 +1228,9 @@ checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac"
dependencies = [ dependencies = [
"http", "http",
"hyper", "hyper",
"rustls", "rustls 0.20.2",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.23.2",
] ]
[[package]] [[package]]
@ -1226,6 +1305,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"js-sys",
"wasm-bindgen",
"web-sys",
] ]
[[package]] [[package]]
@ -1570,6 +1652,12 @@ dependencies = [
"url", "url",
] ]
[[package]]
name = "openssl-probe"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "ordered-float" name = "ordered-float"
version = "1.1.1" version = "1.1.1"
@ -1704,6 +1792,16 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
[[package]]
name = "pharos"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e9567389417feee6ce15dd6527a8a1ecac205ef62c2932bcf3d9f6fc5b78b414"
dependencies = [
"futures",
"rustc_version 0.4.0",
]
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.10" version = "1.0.10"
@ -1813,6 +1911,30 @@ dependencies = [
"toml", "toml",
] ]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
dependencies = [
"proc-macro-error-attr",
"proc-macro2",
"quote",
"syn",
"version_check",
]
[[package]]
name = "proc-macro-error-attr"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
dependencies = [
"proc-macro2",
"quote",
"version_check",
]
[[package]] [[package]]
name = "proc-macro-hack" name = "proc-macro-hack"
version = "0.5.19" version = "0.5.19"
@ -2013,18 +2135,18 @@ dependencies = [
"mime", "mime",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls", "rustls 0.20.2",
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"tokio", "tokio",
"tokio-rustls", "tokio-rustls 0.23.2",
"url", "url",
"wasm-bindgen", "wasm-bindgen",
"wasm-bindgen-futures", "wasm-bindgen-futures",
"web-sys", "web-sys",
"webpki-roots", "webpki-roots 0.22.2",
"winreg", "winreg",
] ]
@ -2096,7 +2218,29 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
dependencies = [ dependencies = [
"semver", "semver 0.9.0",
]
[[package]]
name = "rustc_version"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
dependencies = [
"semver 1.0.4",
]
[[package]]
name = "rustls"
version = "0.19.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7"
dependencies = [
"base64",
"log",
"ring",
"sct 0.6.1",
"webpki 0.21.4",
] ]
[[package]] [[package]]
@ -2107,8 +2251,20 @@ checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring",
"sct", "sct 0.7.0",
"webpki", "webpki 0.22.0",
]
[[package]]
name = "rustls-native-certs"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5a07b7c1885bd8ed3831c289b7870b13ef46fe0e856d288c30d9cc17d75a2092"
dependencies = [
"openssl-probe",
"rustls 0.19.1",
"schannel",
"security-framework",
] ]
[[package]] [[package]]
@ -2126,12 +2282,32 @@ version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
[[package]]
name = "schannel"
version = "0.1.19"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75"
dependencies = [
"lazy_static",
"winapi",
]
[[package]] [[package]]
name = "scopeguard" name = "scopeguard"
version = "1.1.0" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "sct"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "sct" name = "sct"
version = "0.7.0" version = "0.7.0"
@ -2155,6 +2331,29 @@ dependencies = [
"zeroize", "zeroize",
] ]
[[package]]
name = "security-framework"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d09d3c15d814eda1d6a836f2f2b56a6abc1446c8a34351cb3180d3db92ffe4ce"
dependencies = [
"bitflags",
"core-foundation",
"core-foundation-sys",
"libc",
"security-framework-sys",
]
[[package]]
name = "security-framework-sys"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e90dd10c41c6bfc633da6e0c659bd25d31e0791e5974ac42970267d59eba87f7"
dependencies = [
"core-foundation-sys",
"libc",
]
[[package]] [[package]]
name = "semver" name = "semver"
version = "0.9.0" version = "0.9.0"
@ -2164,12 +2363,24 @@ dependencies = [
"semver-parser", "semver-parser",
] ]
[[package]]
name = "semver"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012"
[[package]] [[package]]
name = "semver-parser" name = "semver-parser"
version = "0.7.0" version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
[[package]]
name = "send_wrapper"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "930c0acf610d3fdb5e2ab6213019aaa04e227ebe9547b0649ba599b16d788bd7"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.133" version = "1.0.133"
@ -2306,9 +2517,9 @@ dependencies = [
[[package]] [[package]]
name = "siwe" name = "siwe"
version = "0.1.2" version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f6557098a7ca2e561eb96f99a118edeadaad998567c28dea137c89a052545245" checksum = "51a371151a398635bf39e36ed90cd34c6264e7fd7bf1fb2337156f06f8ce836c"
dependencies = [ dependencies = [
"chrono", "chrono",
"ethers-core", "ethers-core",
@ -2316,6 +2527,7 @@ dependencies = [
"http", "http",
"iri-string", "iri-string",
"k256", "k256",
"rand",
"sha3", "sha3",
"thiserror", "thiserror",
] ]
@ -2334,11 +2546,14 @@ dependencies = [
"chrono", "chrono",
"console_error_panic_hook", "console_error_panic_hook",
"cookie", "cookie",
"ethers-core",
"ethers-providers",
"figment", "figment",
"getrandom", "getrandom",
"headers", "headers",
"hex", "hex",
"iri-string", "iri-string",
"lazy_static",
"matchit", "matchit",
"openidconnect", "openidconnect",
"rand", "rand",
@ -2429,7 +2644,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5"
dependencies = [ dependencies = [
"discard", "discard",
"rustc_version", "rustc_version 0.2.3",
"stdweb-derive", "stdweb-derive",
"stdweb-internal-macros", "stdweb-internal-macros",
"stdweb-internal-runtime", "stdweb-internal-runtime",
@ -2653,15 +2868,43 @@ dependencies = [
"syn", "syn",
] ]
[[package]]
name = "tokio-rustls"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6"
dependencies = [
"rustls 0.19.1",
"tokio",
"webpki 0.21.4",
]
[[package]] [[package]]
name = "tokio-rustls" name = "tokio-rustls"
version = "0.23.2" version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b"
dependencies = [ dependencies = [
"rustls", "rustls 0.20.2",
"tokio", "tokio",
"webpki", "webpki 0.22.0",
]
[[package]]
name = "tokio-tungstenite"
version = "0.15.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8"
dependencies = [
"futures-util",
"log",
"pin-project",
"rustls 0.19.1",
"tokio",
"tokio-rustls 0.22.0",
"tungstenite",
"webpki 0.21.4",
"webpki-roots 0.21.1",
] ]
[[package]] [[package]]
@ -2773,6 +3016,16 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "tracing-futures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2"
dependencies = [
"pin-project",
"tracing",
]
[[package]] [[package]]
name = "tracing-log" name = "tracing-log"
version = "0.1.2" version = "0.1.2"
@ -2808,6 +3061,28 @@ version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "tungstenite"
version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5"
dependencies = [
"base64",
"byteorder",
"bytes",
"http",
"httparse",
"log",
"rand",
"rustls 0.19.1",
"rustls-native-certs",
"sha-1",
"thiserror",
"url",
"utf-8",
"webpki 0.21.4",
]
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.15.0" version = "1.15.0"
@ -2896,6 +3171,12 @@ version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821" checksum = "68b90931029ab9b034b300b797048cf23723400aa757e8a2bfb9d748102f9821"
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]] [[package]]
name = "utf8-ranges" name = "utf8-ranges"
version = "1.0.4" version = "1.0.4"
@ -3018,6 +3299,21 @@ version = "0.2.78"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc"
[[package]]
name = "wasm-timer"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "be0ecb0db480561e9a7642b5d3e4187c128914e58aa84330b9493e3eb68c5e7f"
dependencies = [
"futures",
"js-sys",
"parking_lot",
"pin-utils",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.55" version = "0.3.55"
@ -3028,6 +3324,16 @@ dependencies = [
"wasm-bindgen", "wasm-bindgen",
] ]
[[package]]
name = "webpki"
version = "0.21.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea"
dependencies = [
"ring",
"untrusted",
]
[[package]] [[package]]
name = "webpki" name = "webpki"
version = "0.22.0" version = "0.22.0"
@ -3038,13 +3344,22 @@ dependencies = [
"untrusted", "untrusted",
] ]
[[package]]
name = "webpki-roots"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940"
dependencies = [
"webpki 0.21.4",
]
[[package]] [[package]]
name = "webpki-roots" name = "webpki-roots"
version = "0.22.2" version = "0.22.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449"
dependencies = [ dependencies = [
"webpki", "webpki 0.22.0",
] ]
[[package]] [[package]]
@ -3164,6 +3479,24 @@ dependencies = [
"web-sys", "web-sys",
] ]
[[package]]
name = "ws_stream_wasm"
version = "0.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "47ca1ab42f5afed7fc332b22b6e932ca5414b209465412c8cdf0ad23bc0de645"
dependencies = [
"async_io_stream",
"futures",
"js-sys",
"pharos",
"rustc_version 0.4.0",
"send_wrapper",
"thiserror",
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
]
[[package]] [[package]]
name = "wyz" name = "wyz"
version = "0.2.0" version = "0.2.0"

View File

@ -21,7 +21,7 @@ rand = "0.8.4"
rsa = { version = "0.5.0", features = ["alloc"] } rsa = { version = "0.5.0", features = ["alloc"] }
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0.72" serde_json = "1.0.72"
siwe = "0.1.2" siwe = "0.1.3"
thiserror = "1.0.30" thiserror = "1.0.30"
tracing = "0.1.29" tracing = "0.1.29"
url = { version = "2.2", features = ["serde"] } url = { version = "2.2", features = ["serde"] }
@ -30,6 +30,9 @@ sha2 = "0.9.0"
cookie = "0.15.1" cookie = "0.15.1"
bincode = "1.3.3" bincode = "1.3.3"
async-trait = "0.1.52" async-trait = "0.1.52"
ethers-core = "0.6.3"
ethers-providers = "0.6.2"
lazy_static = "1.4"
[target.'cfg(not(target_arch = "wasm32"))'.dependencies] [target.'cfg(not(target_arch = "wasm32"))'.dependencies]
async-session = "3.0.0" async-session = "3.0.0"

View File

@ -69,16 +69,22 @@ through environment variables:
### OIDC Functionalities ### OIDC Functionalities
The current flow is very basic -- after the user is authenticated you will The current flow is very basic -- after the user is authenticated you will
receive an Ethereum address as the subject (`sub` field). receive:
- an Ethereum address as the subject (`sub` field); and
- an ENS domain as the `preferred_username` (with a fallback to the address).
For the core OIDC information, it is available under For the core OIDC information, it is available under
`/.well-known/openid-configuration`. `/.well-known/openid-configuration`.
OIDC Conformance Suite:
- 🟨 (25/29, and 10 skipped) [basic](https://www.certification.openid.net/plan-detail.html?plan=gXe7Ju1O1afZa&public=true) (`email` scope skipped, `profile` scope partially supported, ACR, `prompt=none` and request URIs yet to be supported);
- 🟩 [config](https://www.certification.openid.net/plan-detail.html?plan=SAmBjvtyfTDVn&public=true);
- 🟧 [dynamic code](https://www.certification.openid.net/plan-detail.html?plan=7rexGcCd4SWJa&public=true).
### TODO Items ### TODO Items
* Additional information, from native projects (e.g. ENS domains), to more * Additional information, from native projects (e.g. ENS domains profile
traditional ones (e.g. email). pictures), to more traditional ones (e.g. email).
* PKCE support (code challenge).
* Browser session support for the Worker version. * Browser session support for the Worker version.
## Development ## Development

View File

@ -108,6 +108,7 @@ async fn token(
private_key, private_key,
config.base_url, config.base_url,
config.require_secret, config.require_secret,
config.eth_provider,
&redis_client, &redis_client,
) )
.await?; .await?;
@ -272,6 +273,7 @@ async fn userinfo(
}; };
let claims = oidc::userinfo( let claims = oidc::userinfo(
config.base_url, config.base_url,
config.eth_provider,
private_key, private_key,
bearer.map(|b| b.0 .0), bearer.map(|b| b.0 .0),
payload, payload,

View File

@ -15,6 +15,7 @@ pub struct Config {
pub default_clients: HashMap<String, String>, pub default_clients: HashMap<String, String>,
// TODO secret is more complicated than that, and needs to be in the well-known config // TODO secret is more complicated than that, and needs to be in the well-known config
pub require_secret: bool, pub require_secret: bool,
pub eth_provider: Option<Url>,
} }
impl Default for Config { impl Default for Config {
@ -27,6 +28,7 @@ impl Default for Config {
redis_url: Url::parse("redis://localhost").unwrap(), redis_url: Url::parse("redis://localhost").unwrap(),
default_clients: HashMap::default(), default_clients: HashMap::default(),
require_secret: false, require_secret: false,
eth_provider: None,
} }
} }
} }

View File

@ -1,6 +1,7 @@
use anyhow::Result; use anyhow::Result;
use async_trait::async_trait; use async_trait::async_trait;
use chrono::{offset::Utc, DateTime}; use chrono::{offset::Utc, DateTime};
use ethers_core::types::H160;
use openidconnect::{core::CoreClientMetadata, Nonce}; use openidconnect::{core::CoreClientMetadata, Nonce};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -19,7 +20,7 @@ pub const ENTRY_LIFETIME: usize = 30;
#[derive(Clone, Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct CodeEntry { pub struct CodeEntry {
pub exchange_count: usize, pub exchange_count: usize,
pub address: String, pub address: H160,
pub nonce: Option<Nonce>, pub nonce: Option<Nonce>,
pub client_id: String, pub client_id: String,
pub auth_time: DateTime<Utc>, pub auth_time: DateTime<Utc>,

View File

@ -1,5 +1,6 @@
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use chrono::{Duration, Utc}; use chrono::{Duration, Utc};
use ethers_core::{types::H160, utils::to_checksum};
use headers::{self, authorization::Bearer}; use headers::{self, authorization::Bearer};
use hex::FromHex; use hex::FromHex;
use iri_string::types::UriString; use iri_string::types::UriString;
@ -15,16 +16,16 @@ use openidconnect::{
registration::{EmptyAdditionalClientMetadata, EmptyAdditionalClientRegistrationResponse}, registration::{EmptyAdditionalClientMetadata, EmptyAdditionalClientRegistrationResponse},
url::Url, url::Url,
AccessToken, Audience, AuthUrl, ClientId, ClientSecret, EmptyAdditionalClaims, AccessToken, Audience, AuthUrl, ClientId, ClientSecret, EmptyAdditionalClaims,
EmptyAdditionalProviderMetadata, EmptyExtraTokenFields, IssuerUrl, JsonWebKeyId, EmptyAdditionalProviderMetadata, EmptyExtraTokenFields, EndUserUsername, IssuerUrl,
JsonWebKeySetUrl, Nonce, PrivateSigningKey, RedirectUrl, RegistrationUrl, RequestUrl, JsonWebKeyId, JsonWebKeySetUrl, Nonce, PrivateSigningKey, RedirectUrl, RegistrationUrl,
ResponseTypes, Scope, StandardClaims, SubjectIdentifier, TokenUrl, UserInfoUrl, RequestUrl, ResponseTypes, Scope, StandardClaims, SubjectIdentifier, TokenUrl, UserInfoUrl,
}; };
use rsa::{pkcs1::ToRsaPrivateKey, RsaPrivateKey}; use rsa::{pkcs1::ToRsaPrivateKey, RsaPrivateKey};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use siwe::eip4361::{Message, Version}; use siwe::eip4361::{Message, Version};
use std::{str::FromStr, time}; use std::{str::FromStr, time};
use thiserror::Error; use thiserror::Error;
use tracing::info; use tracing::{error, info};
use urlencoding::decode; use urlencoding::decode;
use uuid::Uuid; use uuid::Uuid;
@ -33,6 +34,12 @@ use super::db::*;
#[cfg(not(target_arch = "wasm32"))] #[cfg(not(target_arch = "wasm32"))]
use siwe_oidc::db::*; use siwe_oidc::db::*;
lazy_static::lazy_static! {
static ref SCOPES: [Scope; 2] = [
Scope::new("openid".to_string()),
Scope::new("profile".to_string()),
];
}
const SIGNING_ALG: [CoreJwsSigningAlgorithm; 1] = [CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256]; const SIGNING_ALG: [CoreJwsSigningAlgorithm; 1] = [CoreJwsSigningAlgorithm::RsaSsaPkcs1V15Sha256];
const KID: &str = "key1"; const KID: &str = "key1";
pub const METADATA_PATH: &str = "/.well-known/openid-configuration"; pub const METADATA_PATH: &str = "/.well-known/openid-configuration";
@ -100,6 +107,7 @@ pub fn metadata(base_url: Url) -> Result<CoreProviderMetadata, CustomError> {
), ),
vec![ vec![
ResponseTypes::new(vec![CoreResponseType::Code]), ResponseTypes::new(vec![CoreResponseType::Code]),
ResponseTypes::new(vec![CoreResponseType::IdToken]),
ResponseTypes::new(vec![CoreResponseType::Token, CoreResponseType::IdToken]), ResponseTypes::new(vec![CoreResponseType::Token, CoreResponseType::IdToken]),
], ],
vec![CoreSubjectIdentifierType::Pairwise], vec![CoreSubjectIdentifierType::Pairwise],
@ -117,24 +125,14 @@ pub fn metadata(base_url: Url) -> Result<CoreProviderMetadata, CustomError> {
.map_err(|e| anyhow!("Unable to join URL: {}", e))?, .map_err(|e| anyhow!("Unable to join URL: {}", e))?,
))) )))
.set_userinfo_signing_alg_values_supported(Some(SIGNING_ALG.to_vec())) .set_userinfo_signing_alg_values_supported(Some(SIGNING_ALG.to_vec()))
.set_scopes_supported(Some(vec![ .set_scopes_supported(Some(SCOPES.to_vec()))
Scope::new("openid".to_string()),
// Scope::new("email".to_string()),
// Scope::new("profile".to_string()),
]))
.set_claims_supported(Some(vec![ .set_claims_supported(Some(vec![
CoreClaimName::new("sub".to_string()), CoreClaimName::new("sub".to_string()),
CoreClaimName::new("aud".to_string()), CoreClaimName::new("aud".to_string()),
// CoreClaimName::new("email".to_string()),
// CoreClaimName::new("email_verified".to_string()),
CoreClaimName::new("exp".to_string()), CoreClaimName::new("exp".to_string()),
CoreClaimName::new("iat".to_string()), CoreClaimName::new("iat".to_string()),
CoreClaimName::new("iss".to_string()), CoreClaimName::new("iss".to_string()),
// CoreClaimName::new("name".to_string()), CoreClaimName::new("preferred_username".to_string()),
// CoreClaimName::new("given_name".to_string()),
// CoreClaimName::new("family_name".to_string()),
// CoreClaimName::new("picture".to_string()),
// CoreClaimName::new("locale".to_string()),
])) ]))
.set_registration_endpoint(Some(RegistrationUrl::from_url( .set_registration_endpoint(Some(RegistrationUrl::from_url(
base_url base_url
@ -150,6 +148,29 @@ pub fn metadata(base_url: Url) -> Result<CoreProviderMetadata, CustomError> {
Ok(pm) Ok(pm)
} }
async fn resolve_name(eth_provider: Option<Url>, address: H160) -> String {
let address_string = to_checksum(&address, None);
if eth_provider.is_none() {
return address_string;
}
use ethers_providers::{Http, Middleware, Provider};
let provider = match Provider::<Http>::try_from(eth_provider.unwrap().to_string()) {
Ok(p) => p,
Err(e) => {
error!("Failed to initialise Eth provider: {}", e);
return address_string;
}
};
match provider.lookup_address(address).await {
Ok(n) => n,
Err(e) => {
error!("Failed to resolve Eth domain: {}", e);
address_string
}
}
}
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct TokenForm { pub struct TokenForm {
pub code: String, pub code: String,
@ -165,6 +186,7 @@ pub async fn token(
private_key: RsaPrivateKey, private_key: RsaPrivateKey,
base_url: Url, base_url: Url,
require_secret: bool, require_secret: bool,
eth_provider: Option<Url>,
db_client: &DBClientType, db_client: &DBClientType,
) -> Result<CoreTokenResponse, CustomError> { ) -> Result<CoreTokenResponse, CustomError> {
let code_entry = if let Some(c) = db_client.get_code(form.code.to_string()).await? { let code_entry = if let Some(c) = db_client.get_code(form.code.to_string()).await? {
@ -218,7 +240,13 @@ pub async fn token(
vec![Audience::new(client_id.clone())], vec![Audience::new(client_id.clone())],
Utc::now() + Duration::seconds(60), Utc::now() + Duration::seconds(60),
Utc::now(), Utc::now(),
StandardClaims::new(SubjectIdentifier::new(code_entry.address)), StandardClaims::new(SubjectIdentifier::new(to_checksum(
&code_entry.address,
None,
)))
.set_preferred_username(Some(EndUserUsername::new(
resolve_name(eth_provider, code_entry.address).await,
))),
EmptyAdditionalClaims {}, EmptyAdditionalClaims {},
) )
.set_nonce(code_entry.nonce) .set_nonce(code_entry.nonce)
@ -340,8 +368,10 @@ pub async fn authorize(
} }
let _response_type = params.response_type.as_ref().unwrap(); let _response_type = params.response_type.as_ref().unwrap();
if params.scope != Scope::new("openid".to_string()) { for scope in params.scope.as_str().split(' ') {
return Err(anyhow!("Scope not supported").into()); if !SCOPES.contains(&Scope::new(scope.to_string())) {
return Err(anyhow!("Scope not supported: {}", scope).into());
}
} }
let domain = params.redirect_uri.url().host().unwrap(); let domain = params.redirect_uri.url().host().unwrap();
@ -366,7 +396,7 @@ pub struct SiweCookie {
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
struct Web3ModalMessage { struct Web3ModalMessage {
pub domain: String, pub domain: String,
pub address: String, pub address: H160,
pub statement: String, pub statement: String,
pub uri: String, pub uri: String,
pub version: String, pub version: String,
@ -394,7 +424,7 @@ impl Web3ModalMessage {
Ok(Message { Ok(Message {
domain: self.domain.clone().try_into()?, domain: self.domain.clone().try_into()?,
address: <[u8; 20]>::from_hex(self.address.chars().skip(2).collect::<String>())?, address: self.address.0,
statement: self.statement.to_string(), statement: self.statement.to_string(),
uri: UriString::from_str(&self.uri)?, uri: UriString::from_str(&self.uri)?,
version: Version::from_str(&self.version)?, version: Version::from_str(&self.version)?,
@ -529,6 +559,7 @@ pub enum UserInfoResponse {
pub async fn userinfo( pub async fn userinfo(
base_url: Url, base_url: Url,
eth_provider: Option<Url>,
private_key: RsaPrivateKey, private_key: RsaPrivateKey,
bearer: Option<Bearer>, bearer: Option<Bearer>,
payload: UserInfoPayload, payload: UserInfoPayload,
@ -554,7 +585,13 @@ pub async fn userinfo(
}; };
let response = CoreUserInfoClaims::new( let response = CoreUserInfoClaims::new(
StandardClaims::new(SubjectIdentifier::new(code_entry.address)), StandardClaims::new(SubjectIdentifier::new(to_checksum(
&code_entry.address,
None,
)))
.set_preferred_username(Some(EndUserUsername::new(
resolve_name(eth_provider, code_entry.address).await,
))),
EmptyAdditionalClaims::default(), EmptyAdditionalClaims::default(),
) )
.set_issuer(Some(IssuerUrl::from_url(base_url.clone()))) .set_issuer(Some(IssuerUrl::from_url(base_url.clone())))

View File

@ -12,6 +12,7 @@ use super::db::CFClient;
use super::oidc::{self, CustomError, TokenForm, UserInfoPayload}; use super::oidc::{self, CustomError, TokenForm, UserInfoPayload};
const BASE_URL_KEY: &str = "BASE_URL"; const BASE_URL_KEY: &str = "BASE_URL";
const ETH_PROVIDER_KEY: &str = "ETH_PROVIDER";
const RSA_PEM_KEY: &str = "RSA_PEM"; const RSA_PEM_KEY: &str = "RSA_PEM";
// https://github.com/cloudflare/workers-rs/issues/64 // https://github.com/cloudflare/workers-rs/issues/64
@ -61,12 +62,25 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
UserInfoPayload { access_token: None } UserInfoPayload { access_token: None }
}; };
let base_url = ctx.var(BASE_URL_KEY)?.to_string().parse().unwrap(); let base_url = ctx.var(BASE_URL_KEY)?.to_string().parse().unwrap();
let eth_provider = ctx
.var(ETH_PROVIDER_KEY)
.map(|p| p.to_string().parse().unwrap())
.ok();
let private_key = RsaPrivateKey::from_pkcs1_pem(&ctx.secret(RSA_PEM_KEY)?.to_string()) let private_key = RsaPrivateKey::from_pkcs1_pem(&ctx.secret(RSA_PEM_KEY)?.to_string())
.map_err(|e| anyhow!("Failed to load private key: {}", e)) .map_err(|e| anyhow!("Failed to load private key: {}", e))
.unwrap(); .unwrap();
let url = req.url()?; let url = req.url()?;
let db_client = CFClient { ctx, url }; let db_client = CFClient { ctx, url };
match oidc::userinfo(base_url, private_key, bearer, payload, &db_client).await { match oidc::userinfo(
base_url,
eth_provider,
private_key,
bearer,
payload,
&db_client,
)
.await
{
Ok(oidc::UserInfoResponse::Json(r)) => Ok(Response::from_json(&r)?), Ok(oidc::UserInfoResponse::Json(r)) => Ok(Response::from_json(&r)?),
Ok(oidc::UserInfoResponse::Jwt(r)) => { Ok(oidc::UserInfoResponse::Jwt(r)) => {
let mut headers = Headers::new(); let mut headers = Headers::new();
@ -144,6 +158,10 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
.unwrap(); .unwrap();
let base_url = ctx.var(BASE_URL_KEY)?.to_string().parse().unwrap(); let base_url = ctx.var(BASE_URL_KEY)?.to_string().parse().unwrap();
let url = req.url()?; let url = req.url()?;
let eth_provider = ctx
.var(ETH_PROVIDER_KEY)
.map(|p| p.to_string().parse().unwrap())
.ok();
let db_client = CFClient { ctx, url }; let db_client = CFClient { ctx, url };
let token_response = oidc::token( let token_response = oidc::token(
TokenForm { TokenForm {
@ -156,6 +174,7 @@ pub async fn main(req: Request, env: Env) -> Result<Response> {
private_key, private_key,
base_url, base_url,
false, false,
eth_provider,
&db_client, &db_client,
) )
.await; .await;

View File

@ -12,6 +12,7 @@ kv_namespaces = [
[vars] [vars]
WORKERS_RS_VERSION = "0.0.7" WORKERS_RS_VERSION = "0.0.7"
BASE_URL = "https://siweoidc.spruceid.xyz" BASE_URL = "https://siweoidc.spruceid.xyz"
# ETH_PROVIDER = ""
[durable_objects] [durable_objects]
bindings = [ bindings = [