Implement EIP-4361 authentication
This commit is contained in:
parent
d3e3c1eb3e
commit
e8a29a3af1
8 changed files with 279 additions and 30 deletions
175
Cargo.lock
generated
175
Cargo.lock
generated
|
@ -101,7 +101,7 @@ dependencies = [
|
||||||
"http",
|
"http",
|
||||||
"httparse",
|
"httparse",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
"itoa",
|
"itoa 0.4.7",
|
||||||
"language-tags",
|
"language-tags",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"log",
|
"log",
|
||||||
|
@ -743,13 +743,14 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crypto-bigint"
|
name = "crypto-bigint"
|
||||||
version = "0.2.2"
|
version = "0.2.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "b32a398eb1ccfbe7e4f452bc749c44d38dd732e9a253f19da224c416f00ee7f4"
|
checksum = "f83bd3bb4314701c568e340cd8cf78c975aa0ca79e03d3f6d1677d5b0c9c0c03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"generic-array",
|
"generic-array",
|
||||||
"rand_core 0.6.2",
|
"rand_core 0.6.2",
|
||||||
"subtle",
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -762,6 +763,16 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "crypto-mac"
|
||||||
|
version = "0.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714"
|
||||||
|
dependencies = [
|
||||||
|
"generic-array",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "deadpool"
|
name = "deadpool"
|
||||||
version = "0.5.2"
|
version = "0.5.2"
|
||||||
|
@ -839,12 +850,39 @@ version = "0.4.8"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ecdsa"
|
||||||
|
version = "0.12.4"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "43ee23aa5b4f68c7a092b5c3beb25f50c406adc75e2363634f242f28ab255372"
|
||||||
|
dependencies = [
|
||||||
|
"der",
|
||||||
|
"elliptic-curve",
|
||||||
|
"hmac 0.11.0",
|
||||||
|
"signature",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "either"
|
name = "either"
|
||||||
version = "1.6.1"
|
version = "1.6.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "elliptic-curve"
|
||||||
|
version = "0.10.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "beca177dcb8eb540133e7680baff45e7cc4d93bf22002676cec549f82343721b"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-bigint",
|
||||||
|
"ff",
|
||||||
|
"generic-array",
|
||||||
|
"group",
|
||||||
|
"rand_core 0.6.2",
|
||||||
|
"subtle",
|
||||||
|
"zeroize",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "encoding_rs"
|
name = "encoding_rs"
|
||||||
version = "0.8.28"
|
version = "0.8.28"
|
||||||
|
@ -924,6 +962,16 @@ version = "0.2.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "ff"
|
||||||
|
version = "0.10.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d0f40b2dcd8bc322217a5f6559ae5f9e9d1de202a2ecee2e9eafcbece7562a4f"
|
||||||
|
dependencies = [
|
||||||
|
"rand_core 0.6.2",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fixed-hash"
|
name = "fixed-hash"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -931,7 +979,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
|
checksum = "cfcf0ed7fe52a17a03854ec54a9f76d6d84508d1c0e66bc1793301c73fc8493c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"rustc-hex",
|
"rustc-hex",
|
||||||
"static_assertions",
|
"static_assertions",
|
||||||
]
|
]
|
||||||
|
@ -1152,6 +1200,17 @@ dependencies = [
|
||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "group"
|
||||||
|
version = "0.10.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1c363a5301b8f153d80747126a04b3c82073b9fe3130571a9d170cacdeaf7912"
|
||||||
|
dependencies = [
|
||||||
|
"ff",
|
||||||
|
"rand_core 0.6.2",
|
||||||
|
"subtle",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "h2"
|
name = "h2"
|
||||||
version = "0.2.7"
|
version = "0.2.7"
|
||||||
|
@ -1208,7 +1267,17 @@ version = "0.9.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff"
|
checksum = "deae6d9dbb35ec2c502d62b8f7b1c000a0822c3b0794ba36b3149c0a1c840dff"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crypto-mac",
|
"crypto-mac 0.9.1",
|
||||||
|
"digest",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "hmac"
|
||||||
|
version = "0.11.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b"
|
||||||
|
dependencies = [
|
||||||
|
"crypto-mac 0.11.1",
|
||||||
"digest",
|
"digest",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -1239,13 +1308,13 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "http"
|
name = "http"
|
||||||
version = "0.2.4"
|
version = "0.2.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11"
|
checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytes 1.0.1",
|
"bytes 1.0.1",
|
||||||
"fnv",
|
"fnv",
|
||||||
"itoa",
|
"itoa 1.0.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1285,7 +1354,7 @@ dependencies = [
|
||||||
"http-body",
|
"http-body",
|
||||||
"httparse",
|
"httparse",
|
||||||
"httpdate",
|
"httpdate",
|
||||||
"itoa",
|
"itoa 0.4.7",
|
||||||
"pin-project 1.0.6",
|
"pin-project 1.0.6",
|
||||||
"socket2",
|
"socket2",
|
||||||
"tokio",
|
"tokio",
|
||||||
|
@ -1420,12 +1489,27 @@ version = "2.3.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iri-string"
|
||||||
|
version = "0.4.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78"
|
||||||
|
dependencies = [
|
||||||
|
"nom 7.1.0",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "itoa"
|
name = "itoa"
|
||||||
version = "0.4.7"
|
version = "0.4.7"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "js-sys"
|
name = "js-sys"
|
||||||
version = "0.3.51"
|
version = "0.3.51"
|
||||||
|
@ -1448,6 +1532,18 @@ dependencies = [
|
||||||
"serde_json",
|
"serde_json",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "k256"
|
||||||
|
version = "0.9.6"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "903ae2481bcdfdb7b68e0a9baa4b7c9aff600b9ae2e8e5bb5833b8c91ab851ea"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if 1.0.0",
|
||||||
|
"ecdsa",
|
||||||
|
"elliptic-curve",
|
||||||
|
"sha3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "keccak"
|
name = "keccak"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
@ -1632,6 +1728,12 @@ dependencies = [
|
||||||
"unicase",
|
"unicase",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "minimal-lexical"
|
||||||
|
version = "0.2.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "miniz_oxide"
|
name = "miniz_oxide"
|
||||||
version = "0.4.4"
|
version = "0.4.4"
|
||||||
|
@ -1711,7 +1813,7 @@ dependencies = [
|
||||||
"postgres-types",
|
"postgres-types",
|
||||||
"postgres_query",
|
"postgres_query",
|
||||||
"postgres_query_macro",
|
"postgres_query_macro",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"refinery",
|
"refinery",
|
||||||
"regex",
|
"regex",
|
||||||
"reqwest",
|
"reqwest",
|
||||||
|
@ -1723,6 +1825,7 @@ dependencies = [
|
||||||
"serde_yaml",
|
"serde_yaml",
|
||||||
"serial_test",
|
"serial_test",
|
||||||
"sha2",
|
"sha2",
|
||||||
|
"siwe",
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"tokio-postgres",
|
"tokio-postgres",
|
||||||
|
@ -1788,6 +1891,17 @@ dependencies = [
|
||||||
"version_check 0.9.3",
|
"version_check 0.9.3",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "nom"
|
||||||
|
version = "7.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109"
|
||||||
|
dependencies = [
|
||||||
|
"memchr",
|
||||||
|
"minimal-lexical",
|
||||||
|
"version_check 0.9.3",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "num-bigint-dig"
|
name = "num-bigint-dig"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
|
@ -1801,7 +1915,7 @@ dependencies = [
|
||||||
"num-integer",
|
"num-integer",
|
||||||
"num-iter",
|
"num-iter",
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
@ -2112,7 +2226,7 @@ dependencies = [
|
||||||
"byteorder",
|
"byteorder",
|
||||||
"bytes 0.5.6",
|
"bytes 0.5.6",
|
||||||
"fallible-iterator",
|
"fallible-iterator",
|
||||||
"hmac",
|
"hmac 0.9.0",
|
||||||
"md5",
|
"md5",
|
||||||
"memchr",
|
"memchr",
|
||||||
"rand 0.7.3",
|
"rand 0.7.3",
|
||||||
|
@ -2290,9 +2404,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rand"
|
name = "rand"
|
||||||
version = "0.8.3"
|
version = "0.8.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "0ef9e7e66b4468674bfcb0c81af8b7fa0bb154fa9f28eb840da5c447baeb8d7e"
|
checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"rand_chacha 0.3.0",
|
"rand_chacha 0.3.0",
|
||||||
|
@ -2612,7 +2726,7 @@ dependencies = [
|
||||||
"num-traits",
|
"num-traits",
|
||||||
"pkcs1",
|
"pkcs1",
|
||||||
"pkcs8",
|
"pkcs8",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"subtle",
|
"subtle",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
@ -2758,7 +2872,7 @@ version = "1.0.64"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"itoa",
|
"itoa 0.4.7",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -2770,7 +2884,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
|
checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"form_urlencoded",
|
"form_urlencoded",
|
||||||
"itoa",
|
"itoa 0.4.7",
|
||||||
"ryu",
|
"ryu",
|
||||||
"serde",
|
"serde",
|
||||||
]
|
]
|
||||||
|
@ -2862,12 +2976,37 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "signature"
|
||||||
|
version = "1.3.2"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f2807892cfa58e081aa1f1111391c7a0649d4fa127a4ffbe34bcbfb35a1171a4"
|
||||||
|
dependencies = [
|
||||||
|
"digest",
|
||||||
|
"rand_core 0.6.2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "siphasher"
|
name = "siphasher"
|
||||||
version = "0.3.5"
|
version = "0.3.5"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
|
checksum = "cbce6d4507c7e4a3962091436e56e95290cb71fa302d0d270e32130b75fbff27"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "siwe"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "git+https://github.com/silverpill/siwe-rs?branch=edition2018#9328228930af06f96ed8e0fe548bf498e959302c"
|
||||||
|
dependencies = [
|
||||||
|
"chrono",
|
||||||
|
"hex",
|
||||||
|
"http",
|
||||||
|
"iri-string",
|
||||||
|
"k256",
|
||||||
|
"rand 0.8.4",
|
||||||
|
"sha3",
|
||||||
|
"thiserror",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "slab"
|
name = "slab"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
@ -3042,7 +3181,7 @@ checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if 1.0.0",
|
"cfg-if 1.0.0",
|
||||||
"libc",
|
"libc",
|
||||||
"rand 0.8.3",
|
"rand 0.8.4",
|
||||||
"redox_syscall",
|
"redox_syscall",
|
||||||
"remove_dir_all",
|
"remove_dir_all",
|
||||||
"winapi 0.3.9",
|
"winapi 0.3.9",
|
||||||
|
|
|
@ -44,7 +44,7 @@ num_cpus = "1.13.0"
|
||||||
# Used for working with regular expressions
|
# Used for working with regular expressions
|
||||||
regex = "1.5.4"
|
regex = "1.5.4"
|
||||||
# Used to generate random numbers
|
# Used to generate random numbers
|
||||||
rand = "0.8.3"
|
rand = "0.8.4"
|
||||||
# Used for managing database migrations
|
# Used for managing database migrations
|
||||||
refinery = { version = "0.4.0", features = ["tokio-postgres"] }
|
refinery = { version = "0.4.0", features = ["tokio-postgres"] }
|
||||||
# Used for making async HTTP requests
|
# Used for making async HTTP requests
|
||||||
|
@ -64,6 +64,8 @@ serde_json = "1.0"
|
||||||
serde_yaml = "0.8.17"
|
serde_yaml = "0.8.17"
|
||||||
# Used to calculate SHA2 hashes
|
# Used to calculate SHA2 hashes
|
||||||
sha2 = "0.9.5"
|
sha2 = "0.9.5"
|
||||||
|
# Used to verify EIP-4361 signatures
|
||||||
|
siwe = { git = "https://github.com/silverpill/siwe-rs", branch = "edition2018" }
|
||||||
# Used for creating error types
|
# Used for creating error types
|
||||||
thiserror = "1.0.24"
|
thiserror = "1.0.24"
|
||||||
# Async runtime ( required for #[tokio::main] )
|
# Async runtime ( required for #[tokio::main] )
|
||||||
|
|
|
@ -19,18 +19,28 @@ paths:
|
||||||
enum:
|
enum:
|
||||||
- password
|
- password
|
||||||
- ethereum
|
- ethereum
|
||||||
|
- eip4361
|
||||||
username:
|
username:
|
||||||
description: User name (required if grant type is "password").
|
description: User name (required if grant type is "password").
|
||||||
type: string
|
type: string
|
||||||
|
message:
|
||||||
|
description: EIP-4361 message (required if grant type is "eip4361").
|
||||||
|
type: string
|
||||||
|
example: "example.com wants you to sign in with your Ethereum account:"
|
||||||
|
signature:
|
||||||
|
description: EIP-4361 signature (required if grant type is "eip4361").
|
||||||
|
type: string
|
||||||
|
example: 0x905...
|
||||||
wallet_address:
|
wallet_address:
|
||||||
description: Ethereum wallet address (required if grant type is "ethereum").
|
description: Ethereum wallet address (required if grant type is "ethereum").
|
||||||
type: string
|
type: string
|
||||||
example: null
|
example: null
|
||||||
password:
|
password:
|
||||||
|
description: Password (required if grant type is "password" or "ethereum").
|
||||||
type: string
|
type: string
|
||||||
|
example: null
|
||||||
required:
|
required:
|
||||||
- grant_type
|
- grant_type
|
||||||
- password
|
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Successful operation
|
description: Successful operation
|
||||||
|
|
74
src/ethereum/eip4361.rs
Normal file
74
src/ethereum/eip4361.rs
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
/// Sign-In with Ethereum https://eips.ethereum.org/EIPS/eip-4361
|
||||||
|
use hex::FromHex;
|
||||||
|
use siwe::Message;
|
||||||
|
use web3::types::H160;
|
||||||
|
|
||||||
|
use crate::errors::ValidationError;
|
||||||
|
|
||||||
|
/// Verifies EIP-4361 signature and returns wallet address
|
||||||
|
pub fn verify_eip4361_signature(
|
||||||
|
message: &str,
|
||||||
|
signature: &str,
|
||||||
|
instance_host: &str,
|
||||||
|
login_message: &str,
|
||||||
|
) -> Result<String, ValidationError> {
|
||||||
|
let message: Message = message.parse()
|
||||||
|
.map_err(|_| ValidationError("invalid EIP4361 message"))?;
|
||||||
|
let signature_bytes = <[u8; 65]>::from_hex(signature.trim_start_matches("0x"))
|
||||||
|
.map_err(|_| ValidationError("invalid signature string"))?;
|
||||||
|
message.verify(signature_bytes)
|
||||||
|
.map_err(|_| ValidationError("invalid signature"))?;
|
||||||
|
if message.domain != instance_host {
|
||||||
|
return Err(ValidationError("domain doesn't match instance host"));
|
||||||
|
};
|
||||||
|
let statement = message.statement
|
||||||
|
.ok_or(ValidationError("statement is missing"))?;
|
||||||
|
if statement != login_message {
|
||||||
|
return Err(ValidationError("statement doesn't match login message"));
|
||||||
|
};
|
||||||
|
if message.not_before.is_some() || message.expiration_time.is_some() {
|
||||||
|
return Err(ValidationError("message shouldn't have expiration time"));
|
||||||
|
};
|
||||||
|
// Return wallet address in lower case
|
||||||
|
let wallet_address = format!("{:#x}", H160(message.address));
|
||||||
|
Ok(wallet_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
const INSTANCE_HOST: &str = "example.com";
|
||||||
|
const LOGIN_MESSAGE: &str = "test";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_eip4361_signature() {
|
||||||
|
let message = "example.com wants you to sign in with your Ethereum account:
|
||||||
|
0x70997970C51812dc3A010C7d01b50e0d17dc79C8
|
||||||
|
|
||||||
|
test
|
||||||
|
|
||||||
|
URI: https://example.com
|
||||||
|
Version: 1
|
||||||
|
Chain ID: 1
|
||||||
|
Nonce: 3cb7760eac2f
|
||||||
|
Issued At: 2022-02-14T22:27:35.500Z";
|
||||||
|
let signature = "0x9059c9a69c31e87d887262a574abcc33f320d5b778bea8a35c6fbdea94a17e9652b99f7cdd146ed67fa8e4bb02462774b958a129c421fe8d743a43bf67dcbcd61c";
|
||||||
|
let wallet_address = verify_eip4361_signature(
|
||||||
|
message, signature,
|
||||||
|
INSTANCE_HOST, LOGIN_MESSAGE,
|
||||||
|
).unwrap();
|
||||||
|
assert_eq!(wallet_address, "0x70997970c51812dc3a010c7d01b50e0d17dc79c8");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_verify_eip4361_signature_invalid() {
|
||||||
|
let message = "abc";
|
||||||
|
let signature = "xyz";
|
||||||
|
let error = verify_eip4361_signature(
|
||||||
|
message, signature,
|
||||||
|
INSTANCE_HOST, LOGIN_MESSAGE,
|
||||||
|
).unwrap_err();
|
||||||
|
assert_eq!(error.to_string(), "invalid EIP4361 message");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
mod api;
|
mod api;
|
||||||
pub mod contracts;
|
pub mod contracts;
|
||||||
|
pub mod eip4361;
|
||||||
mod errors;
|
mod errors;
|
||||||
pub mod gate;
|
pub mod gate;
|
||||||
pub mod nft;
|
pub mod nft;
|
||||||
|
|
|
@ -5,7 +5,11 @@ pub struct TokenRequest {
|
||||||
pub grant_type: String,
|
pub grant_type: String,
|
||||||
pub username: Option<String>,
|
pub username: Option<String>,
|
||||||
pub wallet_address: Option<String>,
|
pub wallet_address: Option<String>,
|
||||||
pub password: String,
|
// Required only with "password" and "ethereum" grant types
|
||||||
|
pub password: Option<String>,
|
||||||
|
// EIP4361 message and signature
|
||||||
|
pub message: Option<String>,
|
||||||
|
pub signature: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://docs.joinmastodon.org/entities/token/
|
/// https://docs.joinmastodon.org/entities/token/
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
use actix_web::{post, web, HttpResponse, Scope as ActixScope};
|
use actix_web::{post, web, HttpResponse, Scope as ActixScope};
|
||||||
use chrono::{Duration, Utc};
|
use chrono::{Duration, Utc};
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
use crate::database::{Pool, get_database_client};
|
use crate::database::{Pool, get_database_client};
|
||||||
use crate::errors::{HttpError, ValidationError};
|
use crate::errors::{HttpError, ValidationError};
|
||||||
|
use crate::ethereum::eip4361::verify_eip4361_signature;
|
||||||
use crate::models::oauth::queries::save_oauth_token;
|
use crate::models::oauth::queries::save_oauth_token;
|
||||||
use crate::models::users::queries::{
|
use crate::models::users::queries::{
|
||||||
get_user_by_name,
|
get_user_by_name,
|
||||||
|
@ -19,6 +21,7 @@ const ACCESS_TOKEN_EXPIRES_IN: i64 = 86400 * 7;
|
||||||
/// https://oauth.net/2/grant-types/password/
|
/// https://oauth.net/2/grant-types/password/
|
||||||
#[post("/token")]
|
#[post("/token")]
|
||||||
async fn token_view(
|
async fn token_view(
|
||||||
|
config: web::Data<Config>,
|
||||||
db_pool: web::Data<Pool>,
|
db_pool: web::Data<Pool>,
|
||||||
request_data: web::Json<TokenRequest>,
|
request_data: web::Json<TokenRequest>,
|
||||||
) -> Result<HttpResponse, HttpError> {
|
) -> Result<HttpResponse, HttpError> {
|
||||||
|
@ -35,18 +38,34 @@ async fn token_view(
|
||||||
validate_wallet_address(wallet_address)?;
|
validate_wallet_address(wallet_address)?;
|
||||||
get_user_by_wallet_address(db_client, wallet_address).await?
|
get_user_by_wallet_address(db_client, wallet_address).await?
|
||||||
},
|
},
|
||||||
|
"eip4361" => {
|
||||||
|
let message = request_data.message.as_ref()
|
||||||
|
.ok_or(ValidationError("message is required"))?;
|
||||||
|
let signature = request_data.signature.as_ref()
|
||||||
|
.ok_or(ValidationError("signature is required"))?;
|
||||||
|
let wallet_address = verify_eip4361_signature(
|
||||||
|
&message,
|
||||||
|
&signature,
|
||||||
|
&config.instance().host(),
|
||||||
|
&config.login_message,
|
||||||
|
)?;
|
||||||
|
get_user_by_wallet_address(db_client, &wallet_address).await?
|
||||||
|
},
|
||||||
_ => {
|
_ => {
|
||||||
return Err(ValidationError("unsupported grant type").into());
|
return Err(ValidationError("unsupported grant type").into());
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
if request_data.grant_type == "password" || request_data.grant_type == "ethereum" {
|
||||||
|
let password = request_data.password.as_ref()
|
||||||
|
.ok_or(ValidationError("password is required"))?;
|
||||||
let password_correct = verify_password(
|
let password_correct = verify_password(
|
||||||
&user.password_hash,
|
&user.password_hash,
|
||||||
&request_data.password,
|
&password,
|
||||||
).map_err(|_| HttpError::InternalError)?;
|
).map_err(|_| HttpError::InternalError)?;
|
||||||
if !password_correct {
|
if !password_correct {
|
||||||
// Invalid signature/password
|
|
||||||
return Err(ValidationError("incorrect password").into());
|
return Err(ValidationError("incorrect password").into());
|
||||||
}
|
};
|
||||||
|
};
|
||||||
let access_token = generate_access_token();
|
let access_token = generate_access_token();
|
||||||
let created_at = Utc::now();
|
let created_at = Utc::now();
|
||||||
let expires_at = created_at + Duration::seconds(ACCESS_TOKEN_EXPIRES_IN);
|
let expires_at = created_at + Duration::seconds(ACCESS_TOKEN_EXPIRES_IN);
|
||||||
|
|
|
@ -35,7 +35,7 @@ pub async fn get_user_by_oauth_token(
|
||||||
JOIN actor_profile ON user_account.id = actor_profile.id
|
JOIN actor_profile ON user_account.id = actor_profile.id
|
||||||
WHERE
|
WHERE
|
||||||
oauth_token.token = $1
|
oauth_token.token = $1
|
||||||
AND oauth_token.expires_at > now()
|
AND oauth_token.expires_at > CURRENT_TIMESTAMP
|
||||||
",
|
",
|
||||||
&[&access_token],
|
&[&access_token],
|
||||||
).await?;
|
).await?;
|
||||||
|
|
Loading…
Reference in a new issue