From af784d480493d069d99d3c31e406335e2785926f Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Sat, 4 Dec 2021 22:27:56 +0100 Subject: [PATCH 1/7] refactor: change database design --- .../20210810131733_create_user_table.sql | 21 ++++++++----------- .../20210810131847_create_cert_table.sql | 13 ++++++++++++ .../20210810131847_create_pub_cert_table.sql | 7 ------- ...10810132006_creaete_session_info_table.sql | 8 ------- ...210811110100_create_index_token_expiry.sql | 3 --- ...10812105135_create_table_denied_tokens.sql | 1 - ...0919114416_create_certifications_table.sql | 8 +++---- ...5182107_set_primary_key_certifications.sql | 2 +- ...te_index_on_certifications.target_cert.sql | 1 - 9 files changed, 27 insertions(+), 37 deletions(-) create mode 100644 migrations/20210810131847_create_cert_table.sql delete mode 100644 migrations/20210810131847_create_pub_cert_table.sql delete mode 100644 migrations/20210810132006_creaete_session_info_table.sql delete mode 100644 migrations/20210811110100_create_index_token_expiry.sql delete mode 100644 migrations/20210812105135_create_table_denied_tokens.sql delete mode 100644 migrations/20210926155136_create_index_on_certifications.target_cert.sql diff --git a/migrations/20210810131733_create_user_table.sql b/migrations/20210810131733_create_user_table.sql index c144726..e3059c9 100644 --- a/migrations/20210810131733_create_user_table.sql +++ b/migrations/20210810131733_create_user_table.sql @@ -1,16 +1,13 @@ CREATE TABLE users ( - user_id UUID NOT NULL UNIQUE DEFAULT gen_random_uuid() PRIMARY KEY, + "id" UUID NOT NULL UNIQUE DEFAULT uuid_generate_v4() PRIMARY KEY, -- we have to create an index for the username because it is used all the time - username VARCHAR(16) NOT NULL UNIQUE CONSTRAINT check_username CHECK (username ~* '^[a-z0-9_]{3,16}$'), - -- A argon2 hash. It uses a PHC string to represent the hash and the salt - hash TEXT NOT NULL, + -- an username is used by other users to identify each other + -- also, the user's certificate must contain this username as an userid + -- with the minkan host e.g. `my_name@some.minkan.host` + "username" VARCHAR(16) NOT NULL UNIQUE CONSTRAINT check_username CHECK (username ~* '^[a-z0-9_]{3,16}$'), -- times ALWAYS in UTC - created_at TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, - token_expiry TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, - -- the backend server has to make sure that this is unique and that the cert's uid - -- containts the username and there's no other pub cer with that fingerprint in - -- pub_certs - enc_cert BYTEA NOT NULL, - suspended BOOLEAN NOT NULL DEFAULT false, - suspended_reason TEXT + "created_at" TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, + -- this should prevent the user from taking any actions + "suspended" BOOLEAN NOT NULL DEFAULT false, + "suspended_reason" TEXT ); \ No newline at end of file diff --git a/migrations/20210810131847_create_cert_table.sql b/migrations/20210810131847_create_cert_table.sql new file mode 100644 index 0000000..17edb58 --- /dev/null +++ b/migrations/20210810131847_create_cert_table.sql @@ -0,0 +1,13 @@ +CREATE TABLE certificates ( + "user_id" UUID NOT NULL UNIQUE REFERENCES users(id) PRIMARY KEY, + -- a pgp fingerprint is a sha-1 hash which is hex encoded without spaces + -- and all UPPERCASE + "fingerprint" VARCHAR(40) NOT NULL UNIQUE CONSTRAINT check_sha1_uppercase_hex + -- a sha1 hash in uppercase hex + CHECK (fingerprint ~* '^[A-F0-9]{40}$'), + -- all openpgp packets for this certificate + -- Note: if the user uploaded a certificate with encrypted secret key + -- material, this will be in here, so remember not to return it. + -- e.g. dont use https://docs.rs/sequoia-openpgp/1.6.0/sequoia_openpgp/struct.Cert.html#method.as_tsk when exporting the certificate + "body" BYTEA NOT NULL +); \ No newline at end of file diff --git a/migrations/20210810131847_create_pub_cert_table.sql b/migrations/20210810131847_create_pub_cert_table.sql deleted file mode 100644 index bf24799..0000000 --- a/migrations/20210810131847_create_pub_cert_table.sql +++ /dev/null @@ -1,7 +0,0 @@ -CREATE TABLE pub_certs ( - user_id UUID NOT NULL UNIQUE REFERENCES users(user_id) PRIMARY KEY, - -- a pgp fingerprint is a sha-1 hash which is hex encoded without spaces - -- and all UPPERCASE - cert_fingerprint VARCHAR(40) NOT NULL UNIQUE, - pub_cert BYTEA NOT NULL -); \ No newline at end of file diff --git a/migrations/20210810132006_creaete_session_info_table.sql b/migrations/20210810132006_creaete_session_info_table.sql deleted file mode 100644 index c4fc4bb..0000000 --- a/migrations/20210810132006_creaete_session_info_table.sql +++ /dev/null @@ -1,8 +0,0 @@ -CREATE TABLE session_info ( - session_id UUID NOT NULL UNIQUE DEFAULT gen_random_uuid(), - -- Not unique because a user can have multiple sessions. We need an index here, create one! - user_id UUID NOT NULL REFERENCES users(user_id), - -- optionally a user can set a name to directly identify a session - -- e.g. "Minkan on my Laptop" - session_name VARCHAR(32) -); \ No newline at end of file diff --git a/migrations/20210811110100_create_index_token_expiry.sql b/migrations/20210811110100_create_index_token_expiry.sql deleted file mode 100644 index 48c5b03..0000000 --- a/migrations/20210811110100_create_index_token_expiry.sql +++ /dev/null @@ -1,3 +0,0 @@ --- the token expiry is updated every two minutes for every user, so an index only scan seems like a good idea --- this is for a query like SELECT token_expiry from users WHERE user_id = $1 -CREATE INDEX token_expiry_idx ON users (user_id) INCLUDE (token_expiry); \ No newline at end of file diff --git a/migrations/20210812105135_create_table_denied_tokens.sql b/migrations/20210812105135_create_table_denied_tokens.sql deleted file mode 100644 index 734e05a..0000000 --- a/migrations/20210812105135_create_table_denied_tokens.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE TABLE denied_tokens (token_id UUID UNIQUE PRIMARY KEY); \ No newline at end of file diff --git a/migrations/20210919114416_create_certifications_table.sql b/migrations/20210919114416_create_certifications_table.sql index 2c50500..10ab7e2 100644 --- a/migrations/20210919114416_create_certifications_table.sql +++ b/migrations/20210919114416_create_certifications_table.sql @@ -1,17 +1,17 @@ CREATE TABLE certifications ( -- the fingerprint of the certifying certificate -- this links the actual user that created the certification - -- in the pub_certs table - certifier_cert VARCHAR(40) NOT NULL REFERENCES pub_certs(cert_fingerprint), + -- in the certificates table + "certifier_cert" VARCHAR(40) NOT NULL REFERENCES certificates(fingerprint), -- the certificate this certification is for -- it's actually a userid packet of a certificate -- but because we assume that a user's name is the only userid -- of a certificate, this is okay because there can only be -- one certification for one userid - target_cert VARCHAR(40) NOT NULL REFERENCES pub_certs(cert_fingerprint) + "target_cert" VARCHAR(40) NOT NULL REFERENCES certificates(fingerprint) -- a user shouldn't certify itself CONSTRAINT check_no_self_signature CHECK (certifier_cert != target_cert), -- the actual certification a openpgp implementation can verify -- its a openpgp signature packet - certification BYTEA NOT NULL + "body" BYTEA NOT NULL ) \ No newline at end of file diff --git a/migrations/20210925182107_set_primary_key_certifications.sql b/migrations/20210925182107_set_primary_key_certifications.sql index eb8959f..017a945 100644 --- a/migrations/20210925182107_set_primary_key_certifications.sql +++ b/migrations/20210925182107_set_primary_key_certifications.sql @@ -1,2 +1,2 @@ -- only one certification for one user by one other user -ALTER TABLE certifications ADD PRIMARY KEY (certifier_cert, target_cert) +ALTER TABLE "certifications" ADD PRIMARY KEY ("certifier_cert", "target_cert") diff --git a/migrations/20210926155136_create_index_on_certifications.target_cert.sql b/migrations/20210926155136_create_index_on_certifications.target_cert.sql deleted file mode 100644 index fe9c672..0000000 --- a/migrations/20210926155136_create_index_on_certifications.target_cert.sql +++ /dev/null @@ -1 +0,0 @@ -CREATE INDEX target_cert_idx ON certifications (target_cert) \ No newline at end of file From a9b503082fb533b79de23084f5561cb0c368084e Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Wed, 8 Dec 2021 22:06:37 +0100 Subject: [PATCH 2/7] refactor: update dataloaders to reflect the changes in the database design --- src/loader/cert_loader.rs | 27 +++++++++++++-------------- src/loader/certification_loader.rs | 8 ++++---- src/loader/mod.rs | 3 --- src/loader/token_loader.rs | 10 ---------- src/loader/user_loader.rs | 2 +- 5 files changed, 18 insertions(+), 32 deletions(-) delete mode 100644 src/loader/token_loader.rs diff --git a/src/loader/cert_loader.rs b/src/loader/cert_loader.rs index 941b4af..9996fec 100644 --- a/src/loader/cert_loader.rs +++ b/src/loader/cert_loader.rs @@ -16,7 +16,7 @@ impl Loader for PublicCertificateLoader { async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { Ok(sqlx::query!( r#" - SELECT user_id, cert_fingerprint FROM pub_certs WHERE user_id = ANY($1) + SELECT user_id, fingerprint FROM certificates WHERE user_id = ANY($1) "#, keys, ) @@ -25,7 +25,7 @@ impl Loader for PublicCertificateLoader { ( record.user_id, Certificate::from_public( - Fingerprint::from_hex(&record.cert_fingerprint) + Fingerprint::from_hex(&record.fingerprint) .expect("invalid certificate fingerprint in database"), ), ) @@ -44,7 +44,7 @@ impl Loader for PrivateCertificateLoader { async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { Ok(sqlx::query!( r#" - SELECT user_id, cert_fingerprint FROM pub_certs WHERE user_id = ANY($1) + SELECT user_id, fingerprint FROM certificates WHERE user_id = ANY($1) "#, keys, ) @@ -53,7 +53,7 @@ impl Loader for PrivateCertificateLoader { ( record.user_id, Certificate::from_private( - Fingerprint::from_hex(&record.cert_fingerprint) + Fingerprint::from_hex(&record.fingerprint) .expect("invalid certificate fingerprint in database"), ), ) @@ -67,7 +67,7 @@ basic_loader!( UserIDLoaderByFingerprint, String, uuid::Uuid, - "SELECT cert_fingerprint AS ka, user_id AS val FROM pub_certs WHERE cert_fingerprint = ANY($1)" + "SELECT fingerprint AS ka, user_id AS val FROM certificates WHERE fingerprint = ANY($1)" ); loader_struct!(PrivateCertificateBodyLoader); @@ -83,9 +83,8 @@ impl Loader for PrivateCertificateBodyLoader { let fingerprints: Vec<_> = keys.iter().map(|c| c.fingerprint.to_hex()).collect(); Ok(sqlx::query!( r#" - SELECT enc_cert, cert_fingerprint FROM users - INNER JOIN pub_certs u ON (users.user_id = u.user_id) - WHERE u.cert_fingerprint = ANY($1) + SELECT body, fingerprint FROM certificates + WHERE fingerprint = ANY($1) "#, &fingerprints ) @@ -93,11 +92,11 @@ impl Loader for PrivateCertificateBodyLoader { .map_ok(|record| { ( Certificate { - fingerprint: Fingerprint::from_hex(&record.cert_fingerprint) + fingerprint: Fingerprint::from_hex(&record.fingerprint) .expect("invalid certificate fingerprint in database"), secret: true, }, - Bytes::from(bytes::Bytes::from(record.enc_cert)), + Bytes::from(bytes::Bytes::from(record.body)), ) }) .try_collect() @@ -118,8 +117,8 @@ impl Loader for PublicCertificateBodyLoader { let fingerprints: Vec<_> = keys.iter().map(|c| c.fingerprint.to_hex()).collect(); Ok(sqlx::query!( r#" - SELECT pub_cert, cert_fingerprint FROM pub_certs - WHERE cert_fingerprint = ANY($1) + SELECT body, fingerprint FROM certificates + WHERE fingerprint = ANY($1) "#, &fingerprints ) @@ -127,11 +126,11 @@ impl Loader for PublicCertificateBodyLoader { .map_ok(|record| { ( Certificate { - fingerprint: Fingerprint::from_hex(&record.cert_fingerprint) + fingerprint: Fingerprint::from_hex(&record.fingerprint) .expect("invalid certificate fingerprint in database"), secret: false, }, - Bytes::from(bytes::Bytes::from(record.pub_cert)), + Bytes::from(bytes::Bytes::from(record.body)), ) }) .try_collect() diff --git a/src/loader/certification_loader.rs b/src/loader/certification_loader.rs index 038a135..ab9a314 100644 --- a/src/loader/certification_loader.rs +++ b/src/loader/certification_loader.rs @@ -34,10 +34,10 @@ impl Loader for CertificationBodyLoader { .unzip(); Ok(sqlx::query!( r#" - SELECT certifier.cert_fingerprint AS certifier, target.cert_fingerprint AS target, certification + SELECT certifier.fingerprint AS certifier, target.fingerprint AS target, certifications.body FROM certifications - INNER JOIN pub_certs certifier ON (certifications.certifier_cert = certifier.cert_fingerprint) - INNER JOIN pub_certs target ON (certifications.target_cert = target.cert_fingerprint) + INNER JOIN certificates certifier ON (certifications.certifier_cert = certifier.fingerprint) + INNER JOIN certificates target ON (certifications.target_cert = target.fingerprint) WHERE target_cert = ANY($1) AND certifier_cert = ANY($2) "#, @@ -51,7 +51,7 @@ impl Loader for CertificationBodyLoader { certifier: Certificate::from_public(Fingerprint::from_hex(&record.certifier).expect("invalid cert fingerprint in database")), target: Certificate::from_public(Fingerprint::from_hex(&record.target).expect("invalid cert fingerprint in database")), }, - bytes::Bytes::from(record.certification).into(), + bytes::Bytes::from(record.body).into(), ) }) .try_collect() diff --git a/src/loader/mod.rs b/src/loader/mod.rs index 5980ddb..9decbef 100644 --- a/src/loader/mod.rs +++ b/src/loader/mod.rs @@ -1,11 +1,9 @@ mod cert_loader; mod certification_loader; -mod token_loader; mod user_loader; pub use cert_loader::*; pub use certification_loader::*; -pub use token_loader::*; pub use user_loader::*; /// loader_struct macro @@ -20,7 +18,6 @@ macro_rules! loader_struct { } impl $name { - #[allow(unused)] pub fn new(pool: sqlx::Pool) -> Self { Self { pool } } diff --git a/src/loader/token_loader.rs b/src/loader/token_loader.rs deleted file mode 100644 index 288e6d5..0000000 --- a/src/loader/token_loader.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::basic_loader; -use chrono::{DateTime, Utc}; -use uuid::Uuid; - -basic_loader!( - TokenExpiryLoader, - Uuid, - DateTime, - "SELECT user_id AS ka, token_expiry AS val FROM users WHERE user_id = ANY($1)" -); diff --git a/src/loader/user_loader.rs b/src/loader/user_loader.rs index c461f88..6a183f5 100644 --- a/src/loader/user_loader.rs +++ b/src/loader/user_loader.rs @@ -4,5 +4,5 @@ basic_loader!( UsernameLoader, uuid::Uuid, String, - "SELECT user_id AS ka, username AS val FROM users WHERE user_id = ANY($1)" + r#"SELECT "id" AS ka, username AS val FROM users WHERE "id" = ANY($1)"# ); From 131ffeb57e0eb5831afa997f6d9cec5965a34264 Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Sat, 11 Dec 2021 20:31:15 +0100 Subject: [PATCH 3/7] refactor: update migrations --- .../20210810131733_create_user_table.sql | 18 +++++++----------- .../20210810131847_create_cert_table.sql | 2 +- ...10919114416_create_certifications_table.sql | 8 +++++--- ...25182107_set_primary_key_certifications.sql | 2 -- 4 files changed, 13 insertions(+), 17 deletions(-) delete mode 100644 migrations/20210925182107_set_primary_key_certifications.sql diff --git a/migrations/20210810131733_create_user_table.sql b/migrations/20210810131733_create_user_table.sql index e3059c9..b8fa346 100644 --- a/migrations/20210810131733_create_user_table.sql +++ b/migrations/20210810131733_create_user_table.sql @@ -1,13 +1,9 @@ CREATE TABLE users ( - "id" UUID NOT NULL UNIQUE DEFAULT uuid_generate_v4() PRIMARY KEY, - -- we have to create an index for the username because it is used all the time - -- an username is used by other users to identify each other - -- also, the user's certificate must contain this username as an userid - -- with the minkan host e.g. `my_name@some.minkan.host` - "username" VARCHAR(16) NOT NULL UNIQUE CONSTRAINT check_username CHECK (username ~* '^[a-z0-9_]{3,16}$'), - -- times ALWAYS in UTC - "created_at" TIMESTAMPTZ NOT NULL DEFAULT current_timestamp, - -- this should prevent the user from taking any actions - "suspended" BOOLEAN NOT NULL DEFAULT false, - "suspended_reason" TEXT + -- refers to the `sub` claim in openid connect core + -- see https://openid.net/specs/openid-connect-core-1_0.html + -- it must be a json string (not an UUID) + "id" TEXT NOT NULL UNIQUE PRIMARY KEY, + -- refers to the `preferred_username` + -- see https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims + "username" TEXT NOT NULL ); \ No newline at end of file diff --git a/migrations/20210810131847_create_cert_table.sql b/migrations/20210810131847_create_cert_table.sql index 17edb58..e4de73b 100644 --- a/migrations/20210810131847_create_cert_table.sql +++ b/migrations/20210810131847_create_cert_table.sql @@ -1,5 +1,5 @@ CREATE TABLE certificates ( - "user_id" UUID NOT NULL UNIQUE REFERENCES users(id) PRIMARY KEY, + "user_id" TEXT NOT NULL UNIQUE REFERENCES users(id) PRIMARY KEY, -- a pgp fingerprint is a sha-1 hash which is hex encoded without spaces -- and all UPPERCASE "fingerprint" VARCHAR(40) NOT NULL UNIQUE CONSTRAINT check_sha1_uppercase_hex diff --git a/migrations/20210919114416_create_certifications_table.sql b/migrations/20210919114416_create_certifications_table.sql index 10ab7e2..8803aab 100644 --- a/migrations/20210919114416_create_certifications_table.sql +++ b/migrations/20210919114416_create_certifications_table.sql @@ -11,7 +11,9 @@ CREATE TABLE certifications ( "target_cert" VARCHAR(40) NOT NULL REFERENCES certificates(fingerprint) -- a user shouldn't certify itself CONSTRAINT check_no_self_signature CHECK (certifier_cert != target_cert), - -- the actual certification a openpgp implementation can verify - -- its a openpgp signature packet - "body" BYTEA NOT NULL + -- the actual certification an openpgp implementation can verify + -- its an openpgp signature packet as defined in in sectopm 5.2 of RFC 4880 + -- see https://datatracker.ietf.org/doc/html/rfc4880#section-5.2 + "body" BYTEA NOT NULL, + PRIMARY KEY ("certifier_cert", "target_cert") ) \ No newline at end of file diff --git a/migrations/20210925182107_set_primary_key_certifications.sql b/migrations/20210925182107_set_primary_key_certifications.sql deleted file mode 100644 index 017a945..0000000 --- a/migrations/20210925182107_set_primary_key_certifications.sql +++ /dev/null @@ -1,2 +0,0 @@ --- only one certification for one user by one other user -ALTER TABLE "certifications" ADD PRIMARY KEY ("certifier_cert", "target_cert") From 4ec342dbc5b756a1f900340b11bf364aee191809 Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Sun, 12 Dec 2021 21:58:12 +0100 Subject: [PATCH 4/7] feat: implement openid connect redirect --- Cargo.lock | 3252 +++++++--------------------- Cargo.toml | 70 +- other/config.sample | 19 +- src/ac/mod.rs | 1 - src/ac/permissions.rs | 54 - src/ac/role.rs | 1 - src/actors/authenticated_user.rs | 63 - src/actors/mod.rs | 36 - src/actors/user.rs | 232 -- src/auth/authentication.rs | 173 -- src/auth/mod.rs | 13 - src/auth/session.rs | 85 - src/auth/signup.rs | 60 - src/auth/token.rs | 187 -- src/certificate/mod.rs | 146 -- src/certificate/policy.rs | 97 - src/config.rs | 102 + src/config/mod.rs | 68 - src/fallible/errors.rs | 244 --- src/fallible/mod.rs | 221 -- src/graphql/bytes.rs | 36 - src/graphql/mod.rs | 20 - src/graphql/node.rs | 16 - src/guards/authentication_guard.rs | 79 - src/guards/mod.rs | 3 - src/loader/cert_loader.rs | 139 -- src/loader/certification_loader.rs | 60 - src/loader/mod.rs | 67 - src/loader/user_loader.rs | 8 - src/main.rs | 184 +- src/oidc.rs | 135 ++ src/trust/certification.rs | 202 -- src/trust/mod.rs | 16 - 33 files changed, 1120 insertions(+), 4969 deletions(-) delete mode 100644 src/ac/mod.rs delete mode 100644 src/ac/permissions.rs delete mode 100644 src/ac/role.rs delete mode 100644 src/actors/authenticated_user.rs delete mode 100644 src/actors/mod.rs delete mode 100644 src/actors/user.rs delete mode 100644 src/auth/authentication.rs delete mode 100644 src/auth/mod.rs delete mode 100644 src/auth/session.rs delete mode 100644 src/auth/signup.rs delete mode 100644 src/auth/token.rs delete mode 100644 src/certificate/mod.rs delete mode 100644 src/certificate/policy.rs create mode 100644 src/config.rs delete mode 100644 src/config/mod.rs delete mode 100644 src/fallible/errors.rs delete mode 100644 src/fallible/mod.rs delete mode 100644 src/graphql/bytes.rs delete mode 100644 src/graphql/mod.rs delete mode 100644 src/graphql/node.rs delete mode 100644 src/guards/authentication_guard.rs delete mode 100644 src/guards/mod.rs delete mode 100644 src/loader/cert_loader.rs delete mode 100644 src/loader/certification_loader.rs delete mode 100644 src/loader/mod.rs delete mode 100644 src/loader/user_loader.rs create mode 100644 src/oidc.rs delete mode 100644 src/trust/certification.rs delete mode 100644 src/trust/mod.rs diff --git a/Cargo.lock b/Cargo.lock index e1bf82c..094cfa4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,128 +2,67 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "actix" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1be241f88f3b1e7e9a3fbe3b5a8a0f6915b5a1d7ee0d9a248d3376d01068cc60" -dependencies = [ - "actix-rt", - "actix_derive", - "bitflags", - "bytes 0.5.6", - "crossbeam-channel 0.4.4", - "derive_more", - "futures-channel", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project 0.4.28", - "smallvec", - "tokio 0.2.25", - "tokio-util 0.3.1", - "trust-dns-proto", - "trust-dns-resolver", -] - [[package]] name = "actix-codec" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78d1833b3838dbe990df0f1f87baf640cf6146e898166afe401839d1b001e570" +checksum = "13895df506faee81e423febbae3a33b27fca71831b96bb3d60adf16ebcfea952" dependencies = [ "bitflags", - "bytes 0.5.6", + "bytes", "futures-core", "futures-sink", "log", - "pin-project 0.4.28", - "tokio 0.2.25", - "tokio-util 0.3.1", -] - -[[package]] -name = "actix-connect" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177837a10863f15ba8d3ae3ec12fac1099099529ed20083a27fdfe247381d0dc" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "derive_more", - "either", - "futures-util", - "http", - "log", - "trust-dns-proto", - "trust-dns-resolver", + "memchr", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] name = "actix-http" -version = "2.2.1" +version = "3.0.0-beta.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cb8958da437716f3f31b0e76f8daf36554128517d7df37ceba7df00f09622ee" +checksum = "a1ff7b149cc1b99967c22cb81c2c31f128ac88ed12bbf80c29c55a7511d46edb" dependencies = [ "actix-codec", - "actix-connect", "actix-rt", "actix-service", - "actix-threadpool", "actix-utils", - "base64 0.13.0", + "ahash", + "base64", "bitflags", "brotli2", - "bytes 0.5.6", - "cookie", - "copyless", + "bytes", + "bytestring", "derive_more", - "either", "encoding_rs", "flate2", - "futures-channel", "futures-core", "futures-util", - "fxhash", "h2", "http", "httparse", - "indexmap", + "httpdate", "itoa", "language-tags", - "lazy_static", + "local-channel", "log", "mime", "percent-encoding", - "pin-project 1.0.8", - "rand 0.7.3", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "sha-1 0.9.8", - "slab", - "time 0.2.27", + "pin-project", + "pin-project-lite", + "rand", + "sha-1", + "smallvec", + "zstd", ] [[package]] name = "actix-macros" -version = "0.1.3" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ca8ce00b267af8ccebbd647de0d61e0674b6e61185cc7a592ff88772bed655" +checksum = "465a6172cf69b960917811022d8f29bc0b7fa1398bc4f78b3c466673db1213b6" dependencies = [ "quote", "syn", @@ -131,11 +70,12 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.2.7" +version = "0.5.0-beta.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad299af73649e1fc893e333ccf86f377751eb95ff875d095131574c6f43452c" +checksum = "36b95ce0d76d1aa2f98b681702807475ade0f99bd4552546a6843a966d42ea3d" dependencies = [ "bytestring", + "firestorm", "http", "log", "regex", @@ -144,115 +84,59 @@ dependencies = [ [[package]] name = "actix-rt" -version = "1.1.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143fcc2912e0d1de2bcf4e2f720d2a60c28652ab4179685a1ee159e0fb3db227" +checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f" dependencies = [ "actix-macros", - "actix-threadpool", - "copyless", - "futures-channel", - "futures-util", - "smallvec", - "tokio 0.2.25", + "futures-core", + "tokio", ] [[package]] name = "actix-server" -version = "1.0.4" +version = "2.0.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45407e6e672ca24784baa667c5d32ef109ccdd8d5e0b5ebb9ef8a67f4dfb708e" +checksum = "78c9b22794b8af1c2e02434873ef858f2a7db40dbbf861ce77a04cd81ac6b767" dependencies = [ - "actix-codec", "actix-rt", "actix-service", "actix-utils", - "futures-channel", + "futures-core", "futures-util", "log", - "mio", - "mio-uds", + "mio 0.8.0", "num_cpus", - "slab", - "socket2 0.3.19", + "socket2", + "tokio", ] [[package]] name = "actix-service" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0052435d581b5be835d11f4eb3bce417c8af18d87ddf8ace99f8e67e595882bb" -dependencies = [ - "futures-util", - "pin-project 0.4.28", -] - -[[package]] -name = "actix-testing" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47239ca38799ab74ee6a8a94d1ce857014b2ac36f242f70f3f75a66f691e791c" -dependencies = [ - "actix-macros", - "actix-rt", - "actix-server", - "actix-service", - "log", - "socket2 0.3.19", -] - -[[package]] -name = "actix-threadpool" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d209f04d002854b9afd3743032a27b066158817965bf5d036824d19ac2cc0e30" -dependencies = [ - "derive_more", - "futures-channel", - "lazy_static", - "log", - "num_cpus", - "parking_lot", - "threadpool", -] - -[[package]] -name = "actix-tls" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24789b7d7361cf5503a504ebe1c10806896f61e96eca9a7350e23001aca715fb" +checksum = "8d3dc6a618b082974a08d7a4781d24d4691cba51500059bfebe6656a61ebfe1e" dependencies = [ - "actix-codec", - "actix-service", - "actix-utils", - "futures-util", + "futures-core", + "paste", + "pin-project-lite", ] [[package]] name = "actix-utils" -version = "2.0.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9022dec56632d1d7979e59af14f0597a28a830a9c1c7fec8b2327eb9f16b5a" +checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "bitflags", - "bytes 0.5.6", - "either", - "futures-channel", - "futures-sink", - "futures-util", - "log", - "pin-project 0.4.28", - "slab", + "local-waker", + "pin-project-lite", ] [[package]] name = "actix-web" -version = "3.3.2" +version = "4.0.0-beta.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e641d4a172e7faa0862241a20ff4f1f5ab0ab7c279f00c2d4587b77483477b86" +checksum = "9387ea044357f12b606b8fad0652d3804ba498954f66ae5c677236cb0bd47db4" dependencies = [ "actix-codec", "actix-http", @@ -261,129 +145,59 @@ dependencies = [ "actix-rt", "actix-server", "actix-service", - "actix-testing", - "actix-threadpool", - "actix-tls", "actix-utils", "actix-web-codegen", - "awc", - "bytes 0.5.6", + "ahash", + "bytes", + "cfg-if", + "cookie", "derive_more", + "either", "encoding_rs", - "futures-channel", "futures-core", "futures-util", - "fxhash", + "itoa", + "language-tags", "log", "mime", - "pin-project 1.0.8", + "once_cell", + "paste", + "pin-project-lite", "regex", "serde", "serde_json", "serde_urlencoded", - "socket2 0.3.19", - "time 0.2.27", - "tinyvec", + "smallvec", + "socket2", + "time 0.3.5", "url", ] -[[package]] -name = "actix-web-actors" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6edf3c2693e2a8c422800c87ee89a6a4eac7dd01109bc172a1093ce1f4f001" -dependencies = [ - "actix", - "actix-codec", - "actix-http", - "actix-web", - "bytes 0.5.6", - "futures-channel", - "futures-core", - "pin-project 0.4.28", -] - [[package]] name = "actix-web-codegen" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad26f77093333e0e7c6ffe54ebe3582d908a104e448723eec6d43d08b07143fb" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "actix-web-httpauth" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c3b11a07a3df3f7970fd8bd38cc66998b5549f507c54cc64c6e843bc82d6358" -dependencies = [ - "actix-web", - "base64 0.13.0", - "futures-util", -] - -[[package]] -name = "actix_derive" -version = "0.5.0" +version = "0.5.0-beta.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95aceadaf327f18f0df5962fedc1bde2f870566a0b9f65c89508a3b1f79334c" +checksum = "30a90b7f6c2fde9a1fe3df4da758c2c3c9d620dfa3eae4da0b6925dc0a13444a" dependencies = [ + "actix-router", "proc-macro2", "quote", "syn", ] -[[package]] -name = "addr2line" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61f2b7f93d2c7d2b08263acaa4a363b3e276806c68af6134c44f523bf1aacd" -dependencies = [ - "gimli", -] - [[package]] name = "adler" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aead" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "ahash" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "739f4a8db6605981345c5654f3a85b056ce52f37a39d34da03f25bf2151ea16e" - -[[package]] -name = "ahash" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "796540673305a66d127804eef19ad696f1f204b8c1025aaca4958c17eab32877" -dependencies = [ - "getrandom 0.2.3", - "once_cell", - "version_check", -] - [[package]] name = "ahash" version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" dependencies = [ - "getrandom 0.2.3", + "getrandom", "once_cell", "version_check", ] @@ -399,471 +213,101 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.44" +version = "1.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61604a8f862e1d5c3229fdd78f8b02c68dcf73a4c4b05fd636d12240aaa242c1" +checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" [[package]] -name = "argon2" -version = "0.2.4" +name = "arc-swap" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca5162d1b961cb589a8ca08a2aa7cabc6341e05e0bf18d66a07697900b5d2ad0" -dependencies = [ - "blake2", - "password-hash", -] +checksum = "c5d78ce20460b82d3fa150275ed9d55e21064fc7951177baacf86a145c4a4b1f" [[package]] -name = "ascii-canvas" -version = "3.0.0" +name = "async-trait" +version = "0.1.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8824ecca2e851cec16968d54a01dd372ef8f95b244fb84b84e70128be347c3c6" +checksum = "061a7acccaa286c011ddc30970520b98fa40e00c9d644633fb26b5fc63a265e3" dependencies = [ - "term", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "async-channel" -version = "1.6.1" +name = "atoi" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" +checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", + "num-traits", ] [[package]] -name = "async-executor" -version = "1.4.1" +name = "atomic" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" +checksum = "b88d82667eca772c4aa12f0f1348b3ae643424c8876448f3f7bd5787032e234c" dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", + "autocfg", ] [[package]] -name = "async-global-executor" -version = "2.0.2" +name = "atty" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", + "hermit-abi", + "libc", + "winapi", ] [[package]] -name = "async-graphql" -version = "2.10.5" +name = "autocfg" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db90708749da7ba77f48d801fb54ee31cd955865c0a54a222f0e19ac065700b7" -dependencies = [ - "async-graphql-derive", - "async-graphql-parser", - "async-graphql-value", - "async-stream", - "async-trait", - "bytes 1.1.0", - "chrono", - "fnv", - "futures-channel", - "futures-timer", - "futures-util", - "http", - "indexmap", - "lru", - "mime", - "multer", - "once_cell", - "pin-project-lite 0.2.7", - "regex", - "serde", - "serde_cbor", - "serde_json", - "static_assertions", - "tempfile", - "thiserror", - "uuid", -] +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "async-graphql-actix-web" -version = "2.10.5" +name = "base-x" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f841804b8b483660352bfea3205fa4e9dedcd3ebfda546d3dc449e4667715770" -dependencies = [ - "actix", - "actix-http", - "actix-web", - "actix-web-actors", - "async-channel", - "async-graphql", - "futures-util", - "serde_json", - "serde_urlencoded", -] +checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" [[package]] -name = "async-graphql-derive" -version = "2.10.5" +name = "base64" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa7e002edba829393e110363d7622162d4a259996a22b6bd5a4975ad0aed2163" -dependencies = [ - "Inflector", - "async-graphql-parser", - "darling", - "proc-macro-crate", - "proc-macro2", - "quote", - "syn", - "thiserror", -] +checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" [[package]] -name = "async-graphql-parser" -version = "2.10.5" +name = "bitflags" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9443f5154cedcf2e2b189083b81f3761ee94c31a1d99c740421cacb8eada323c" -dependencies = [ - "async-graphql-value", - "pest", - "pest_derive", - "serde", - "serde_json", -] +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] -name = "async-graphql-value" -version = "2.10.5" +name = "block-buffer" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c50fc17991b098c92cc0d8a6f9a1a45090403329898c7a724ac8b833802ad2b1" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "bytes 1.1.0", - "serde", - "serde_json", + "generic-array", ] [[package]] -name = "async-io" -version = "1.6.0" +name = "block-buffer" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" +checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2 0.4.2", - "waker-fn", - "winapi 0.3.9", + "generic-array", ] [[package]] -name = "async-lock" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-std" -version = "1.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8056f1455169ab86dd47b47391e4ab0cbd25410a70e9fe675544f49bafaf952" -dependencies = [ - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "crossbeam-utils 0.8.5", - "futures-channel", - "futures-core", - "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", - "memchr", - "num_cpus", - "once_cell", - "pin-project-lite 0.2.7", - "pin-utils", - "slab", - "wasm-bindgen-futures", -] - -[[package]] -name = "async-stream" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171374e7e3b2504e0e5236e3b59260560f9fe94bfe9ac39ba5e4e929c5590625" -dependencies = [ - "async-stream-impl", - "futures-core", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "648ed8c8d2ce5409ccd57453d9d1b214b342a0d69376a6feda1fd6cae3299308" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "async-task" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" - -[[package]] -name = "async-trait" -version = "0.1.51" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "atoi" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "616896e05fc0e2649463a93a15183c6a16bf03413a7af88ef1285ddedfa9cda5" -dependencies = [ - "num-traits", -] - -[[package]] -name = "atomic" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3410529e8288c463bedb5930f82833bc0c90e5d2fe639a56582a4d09220b281" -dependencies = [ - "autocfg 1.0.1", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - -[[package]] -name = "atty" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -dependencies = [ - "hermit-abi", - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" - -[[package]] -name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "awc" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b381e490e7b0cfc37ebc54079b0413d8093ef43d14a4e4747083f7fa47a9e691" -dependencies = [ - "actix-codec", - "actix-http", - "actix-rt", - "actix-service", - "base64 0.13.0", - "bytes 0.5.6", - "cfg-if 1.0.0", - "derive_more", - "futures-core", - "log", - "mime", - "percent-encoding", - "rand 0.7.3", - "serde", - "serde_json", - "serde_urlencoded", -] - -[[package]] -name = "backtrace" -version = "0.3.62" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "091bcdf2da9950f96aa522681ce805e6857f6ca8df73833d35736ab2dc78e152" -dependencies = [ - "addr2line", - "cc", - "cfg-if 1.0.0", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] - -[[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - -[[package]] -name = "base64" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" - -[[package]] -name = "base64" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" - -[[package]] -name = "base64ct" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6b4d9b1225d28d360ec6a231d65af1fd99a2a095154c8040689617290569c5c" - -[[package]] -name = "bindgen" -version = "0.57.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd4865004a46a0aafb2a0a5eb19d3c9fc46ee5f063a6cfc605c69ac9ecf5263d" -dependencies = [ - "bitflags", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", -] - -[[package]] -name = "bit-set" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e11e16035ea35e4e5997b393eacbf6f63983188f7a2ad25bfb13465f5ad59de" -dependencies = [ - "bit-vec", -] - -[[package]] -name = "bit-vec" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "blake2" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a4e37d16930f5459780f5621038b6382b9bb37c19016f39fb6b5808d831f174" -dependencies = [ - "crypto-mac 0.8.0", - "digest 0.9.0", - "opaque-debug 0.3.0", -] - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array 0.12.4", -] - -[[package]] -name = "block-buffer" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "blocking" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - -[[package]] -name = "brotli-sys" -version = "0.3.2" +name = "brotli-sys" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" dependencies = [ @@ -881,51 +325,18 @@ dependencies = [ "libc", ] -[[package]] -name = "buffered-reader" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497e2d235e4c51a70a48dde8d824ae96765971c39e4fa0e58dd74a5a5011abcb" -dependencies = [ - "libc", -] - -[[package]] -name = "build_const" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ae4235e6dac0694637c763029ecea1a2ec9e4e06ec2729bd21ba4d9c863eb7" - [[package]] name = "bumpalo" version = "3.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "bytecount" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" - [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.1.0" @@ -941,58 +352,18 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90706ba19e97b90786e19dc0d5e2abd80008d99d4c0c5d1ad0b5e72cec7c494d" dependencies = [ - "bytes 1.1.0", -] - -[[package]] -name = "cache-padded" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" - -[[package]] -name = "cargo-platform" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" -dependencies = [ - "serde", -] - -[[package]] -name = "cargo_metadata" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" -dependencies = [ - "cargo-platform", - "semver 0.11.0", - "semver-parser 0.10.2", - "serde", - "serde_json", + "bytes", ] [[package]] name = "cc" -version = "1.0.71" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c2681d6594606957bbb8631c4b90a7fcaaa72cdb714743a437b156d6a7eedd" - -[[package]] -name = "cexpr" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4aedb84272dbe89af497cf81375129abda4fc0a9e7c5d317498c15cc30c0d27" +checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" dependencies = [ - "nom 5.1.2", + "jobserver", ] -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -1009,61 +380,21 @@ dependencies = [ "num-integer", "num-traits", "serde", - "time 0.1.43", - "winapi 0.3.9", -] - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "clang-sys" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10612c0ec0e0a1ff0e97980647cb058a6e7aedb913d01d009c406b8b7d0b26ee" -dependencies = [ - "glob", - "libc", - "libloading", -] - -[[package]] -name = "cmac" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73d4de4f7724e5fe70addfb2bd37c2abd2f95084a429d7773b0b9645499b4272" -dependencies = [ - "crypto-mac 0.10.1", - "dbl", + "winapi", ] [[package]] name = "combine" -version = "4.6.1" +version = "4.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a909e4d93292cd8e9c42e189f61681eff9d67b6541f96b8a1a737f23737bd001" +checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "memchr", - "pin-project-lite 0.2.7", - "tokio 1.12.0", - "tokio-util 0.6.8", -] - -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] @@ -1080,9 +411,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.14.4" +version = "0.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" +checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" dependencies = [ "percent-encoding", "time 0.2.27", @@ -1090,10 +421,20 @@ dependencies = [ ] [[package]] -name = "copyless" -version = "0.1.5" +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 = "a2df960f5d869b2dd8532793fde43eb5427cceb126c929747a26823ab0eeb536" +checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc" [[package]] name = "cpufeatures" @@ -1106,30 +447,26 @@ dependencies = [ [[package]] name = "crc" -version = "1.8.1" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d663548de7f5cca343f1e0a48d14dcfb0e9eb4e079ec58883b7251539fa10aeb" +checksum = "49fc9a695bca7f35f5f4c15cddc84415f66a74ea78eef08e90c5024f2b540e23" dependencies = [ - "build_const", + "crc-catalog", ] [[package]] -name = "crc32fast" -version = "1.2.1" +name = "crc-catalog" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" -dependencies = [ - "cfg-if 1.0.0", -] +checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" [[package]] -name = "crossbeam-channel" -version = "0.4.4" +name = "crc32fast" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" +checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" dependencies = [ - "crossbeam-utils 0.7.2", - "maybe-uninit", + "cfg-if", ] [[package]] @@ -1138,23 +475,8 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.5", -] - -[[package]] -name = "crossbeam-epoch" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "crossbeam-utils 0.7.2", - "lazy_static", - "maybe-uninit", - "memoffset", - "scopeguard", + "cfg-if", + "crossbeam-utils", ] [[package]] @@ -1163,19 +485,8 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils 0.8.5", -] - -[[package]] -name = "crossbeam-utils" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" -dependencies = [ - "autocfg 1.0.1", - "cfg-if 0.1.10", - "lazy_static", + "cfg-if", + "crossbeam-utils", ] [[package]] @@ -1184,336 +495,126 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "cfg-if 1.0.0", - "lazy_static", -] - -[[package]] -name = "crunchy" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" - -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array 0.14.4", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "cipher", - "generic-array 0.14.4", - "subtle", -] - -[[package]] -name = "ctor" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccc0a48a9b826acdf4028595adc9db92caea352f7af011a3034acd172a52a0aa" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - -[[package]] -name = "curve25519-dalek" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" -dependencies = [ - "byteorder", - "digest 0.9.0", - "rand_core 0.5.1", - "subtle", - "zeroize", -] - -[[package]] -name = "darling" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2c43f534ea4b0b049015d00269734195e6d3f0f6635cb692251aca6f9f8b3c" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e91455b86830a1c21799d94524df0845183fa55bafd9aa137b01c7d1065fa36" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn", -] - -[[package]] -name = "darling_macro" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29b5acf0dea37a7f66f7b25d2c5e93fd46f8f6968b1a5d7a3e02e97768afc95a" -dependencies = [ - "darling_core", - "quote", - "syn", -] - -[[package]] -name = "dbl" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e797687b5f09528a48fcb63b6914d0255b8a6c760699a919af37042f09d9b3" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "derive_more" -version = "0.99.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40eebddd2156ce1bb37b20bbe5151340a31828b1f2d22ba4141f3531710e38df" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version 0.3.3", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array 0.12.4", -] - -[[package]] -name = "digest" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" -dependencies = [ - "generic-array 0.14.4", -] - -[[package]] -name = "directories" -version = "3.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69600ff1703123957937708eb27f7a564e48885c537782722ed0ba3189ce1d7" -dependencies = [ - "dirs-sys", -] - -[[package]] -name = "dirs-next" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" -dependencies = [ - "cfg-if 1.0.0", - "dirs-sys-next", -] - -[[package]] -name = "dirs-sys" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - -[[package]] -name = "dirs-sys-next" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" -dependencies = [ - "libc", - "redox_users", - "winapi 0.3.9", -] - -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - -[[package]] -name = "doc-comment" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10" - -[[package]] -name = "dotenv" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" - -[[package]] -name = "dtoa" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" + "cfg-if", + "lazy_static", +] [[package]] -name = "dyn-clone" -version = "1.0.4" +name = "crypto-common" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee2626afccd7561a06cf1367e2950c4718ea04565e20fb5029b6c7d8ad09abcf" +checksum = "567569e659735adb39ff2d4c20600f7cd78be5471f8c58ab162bce3c03fdbc5f" +dependencies = [ + "generic-array", +] [[package]] -name = "eax" -version = "0.3.0" +name = "crypto-mac" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1f76e7a5e594b299a0fa9a99de627530725e341df41376aa342aecb2c5eb76e" +checksum = "b1d1a86f49236c215f271d40892d5fc950490551400b02ef360692c29815c714" dependencies = [ - "aead", - "cipher", - "cmac", - "ctr", + "generic-array", "subtle", ] [[package]] -name = "ed25519" -version = "1.2.0" +name = "derive_more" +version = "0.99.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4620d40f6d2601794401d6dd95a5cf69b6c157852539470eeda433a99b3c0efc" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" dependencies = [ - "signature", + "convert_case", + "proc-macro2", + "quote", + "rustc_version 0.4.0", + "syn", ] [[package]] -name = "ed25519-dalek" -version = "1.0.1" +name = "digest" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" dependencies = [ - "curve25519-dalek", - "ed25519", - "rand 0.7.3", - "sha2", - "zeroize", + "generic-array", ] [[package]] -name = "either" -version = "1.6.1" +name = "digest" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "8549e6bfdecd113b7e221fe60b433087f6957387a20f8118ebca9b12af19143d" dependencies = [ - "serde", + "block-buffer 0.10.0", + "crypto-common", + "generic-array", ] [[package]] -name = "ena" -version = "0.14.0" +name = "dirs" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7402b94a93c24e742487327a7cd839dc9d36fec9de9fb25b09f2dae459f36c3" +checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" dependencies = [ - "log", + "dirs-sys", ] [[package]] -name = "encoding_rs" -version = "0.8.29" +name = "dirs-sys" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a74ea89a0a1b98f6332de42c95baff457ada66d1cb4030f9ff151b2041a1c746" +checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" dependencies = [ - "cfg-if 1.0.0", + "libc", + "redox_users", + "winapi", ] [[package]] -name = "enum-as-inner" -version = "0.3.3" +name = "discard" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" -dependencies = [ - "heck", - "proc-macro2", - "quote", - "syn", -] +checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" [[package]] -name = "env_logger" -version = "0.7.1" +name = "dotenv" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" -dependencies = [ - "atty", - "humantime", - "log", - "regex", - "termcolor", -] +checksum = "77c90badedccf4105eca100756a0b1289e191f6fcbdadd3cee1d2f614f97da8f" [[package]] -name = "error-chain" -version = "0.12.4" +name = "dtoa" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d2f06b9cac1506ece98fe3231e3cc9c4410ec3d5b1f24ae1c8946f0742cdefc" -dependencies = [ - "version_check", -] +checksum = "56899898ce76aaf4a0f24d914c97ea6ed976d42fec6ad33fcbb0a1103e07b2b0" [[package]] -name = "event-listener" -version = "2.5.1" +name = "either" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" [[package]] -name = "fake-simd" -version = "0.1.2" +name = "encoding_rs" +version = "0.8.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" +checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +dependencies = [ + "cfg-if", +] [[package]] -name = "fastrand" -version = "1.5.0" +name = "env_logger" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" dependencies = [ - "instant", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] @@ -1531,10 +632,10 @@ dependencies = [ ] [[package]] -name = "fixedbitset" -version = "0.2.0" +name = "firestorm" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ab347416e802de484e4d03c7316c48f1ecb56574dfd4a46a80f173ce1de04d" +checksum = "31586bda1b136406162e381a3185a506cdfc1631708dd40cba2f6628d8634499" [[package]] name = "flate2" @@ -1542,7 +643,7 @@ version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e6988e897c1c9c485f43b47a529cef42fde0547f9d8d41a7062518f1d8fc53f" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide", @@ -1555,36 +656,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] -name = "form_urlencoded" -version = "1.0.1" +name = "foreign-types" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" dependencies = [ - "matches", - "percent-encoding", + "foreign-types-shared", ] [[package]] -name = "fuchsia-zircon" -version = "0.3.3" +name = "foreign-types-shared" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" +name = "form_urlencoded" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" +checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +dependencies = [ + "matches", + "percent-encoding", +] [[package]] name = "futures" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a12aa0eb539080d55c3f2d45a67c3b58b6b0773c1a3ca2dfec66d58c97fd66ca" +checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" dependencies = [ "futures-channel", "futures-core", @@ -1597,9 +697,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5da6ba8c3bb3c165d3c7319fc1cc8304facf1fb8db99c5de877183c08a273888" +checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" dependencies = [ "futures-core", "futures-sink", @@ -1607,15 +707,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d1c26957f23603395cd326b0ffe64124b818f4449552f960d815cfba83a53d" +checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" [[package]] name = "futures-executor" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45025be030969d763025784f7f355043dc6bc74093e4ecc5000ca4dc50d8745c" +checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" dependencies = [ "futures-core", "futures-task", @@ -1623,34 +723,28 @@ dependencies = [ ] [[package]] -name = "futures-io" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "522de2a0fe3e380f1bc577ba0474108faf3f6b18321dbf60b3b9c39a75073377" - -[[package]] -name = "futures-lite" -version = "1.12.0" +name = "futures-intrusive" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" +checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" dependencies = [ - "fastrand", "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite 0.2.7", - "waker-fn", + "lock_api", + "parking_lot", ] +[[package]] +name = "futures-io" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" + [[package]] name = "futures-macro" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18e4a4b95cea4b4ccbcf1c5675ca7c4ee4e9e75eb79944d07defde18068f79bb" +checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" dependencies = [ - "autocfg 1.0.1", - "proc-macro-hack", "proc-macro2", "quote", "syn", @@ -1658,29 +752,22 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36ea153c13024fe480590b3e3d4cad89a0cfacecc24577b68f86c6ced9c2bc11" +checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" [[package]] name = "futures-task" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d3d00f4eddb73e498a54394f228cd55853bdf059259e8e7bc6e69d408892e99" - -[[package]] -name = "futures-timer" -version = "3.0.2" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" [[package]] name = "futures-util" -version = "0.3.17" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36568465210a3a6ee45e1f165136d68671471a501e632e9a98d96872222b5481" +checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" dependencies = [ - "autocfg 1.0.1", "futures-channel", "futures-core", "futures-io", @@ -1688,31 +775,11 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.7", + "pin-project-lite", "pin-utils", - "proc-macro-hack", - "proc-macro-nested", "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "generic-array" version = "0.14.4" @@ -1723,60 +790,26 @@ dependencies = [ "version_check", ] -[[package]] -name = "getrandom" -version = "0.1.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.9.0+wasi-snapshot-preview1", -] - [[package]] name = "getrandom" version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", - "libc", - "wasi 0.10.2+wasi-snapshot-preview1", -] - -[[package]] -name = "gimli" -version = "0.25.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0a01e0497841a3b2db4f8afa483cce65f7e96a3498bd6c541734792aeac8fe7" - -[[package]] -name = "glob" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" - -[[package]] -name = "gloo-timers" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" -dependencies = [ - "futures-channel", - "futures-core", + "cfg-if", "js-sys", + "libc", + "wasi", "wasm-bindgen", - "web-sys", ] [[package]] name = "h2" -version = "0.2.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e4728fd124914ad25e99e3d15a9361a879f6620f63cb56bbb08f95abb97a535" +checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" dependencies = [ - "bytes 0.5.6", + "bytes", "fnv", "futures-core", "futures-sink", @@ -1784,25 +817,9 @@ dependencies = [ "http", "indexmap", "slab", - "tokio 0.2.25", - "tokio-util 0.3.1", + "tokio", + "tokio-util", "tracing", - "tracing-futures", -] - -[[package]] -name = "half" -version = "1.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" - -[[package]] -name = "hashbrown" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" -dependencies = [ - "ahash 0.4.7", ] [[package]] @@ -1811,16 +828,16 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash 0.7.6", + "ahash", ] [[package]] name = "hashlink" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d99cf782f0dc4372d26846bec3de7804ceb5df083c2d4462c0b8d2330e894fa8" +checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf" dependencies = [ - "hashbrown 0.9.1", + "hashbrown", ] [[package]] @@ -1849,56 +866,90 @@ checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" [[package]] name = "hmac" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +checksum = "2a2a2320eb7ec0ebe8da8f744d7812d9fc4cb4d09344ac01898dbcb6a20ae69b" dependencies = [ - "crypto-mac 0.10.1", + "crypto-mac", "digest 0.9.0", ] -[[package]] -name = "hostname" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" -dependencies = [ - "libc", - "match_cfg", - "winapi 0.3.9", -] - [[package]] name = "http" version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" dependencies = [ - "bytes 1.1.0", + "bytes", "fnv", "itoa", ] +[[package]] +name = "http-body" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +dependencies = [ + "bytes", + "http", + "pin-project-lite", +] + [[package]] name = "httparse" version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +[[package]] +name = "httpdate" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" + [[package]] name = "humantime" -version = "1.3.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "hyper" +version = "0.14.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" dependencies = [ - "quick-error", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "hyper-rustls" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +dependencies = [ + "http", + "hyper", + "rustls 0.20.2", + "tokio", + "tokio-rustls 0.23.1", +] [[package]] name = "idna" @@ -1917,8 +968,8 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" dependencies = [ - "autocfg 1.0.1", - "hashbrown 0.11.2", + "autocfg", + "hashbrown", ] [[package]] @@ -1933,41 +984,29 @@ version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] -name = "iovec" -version = "0.1.4" +name = "ipnet" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" -dependencies = [ - "libc", -] +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] -name = "ipconfig" -version = "0.2.2" +name = "itertools" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" +checksum = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" dependencies = [ - "socket2 0.3.19", - "widestring", - "winapi 0.3.9", - "winreg", + "either", ] -[[package]] -name = "ipnetwork" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02c3eaab3ac0ede60ffa41add21970a7df7d91772c03383aac6c2c3d53cc716b" - [[package]] name = "itertools" -version = "0.10.1" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69ddb889f9d0d08a67338271fa9b62996bc788c7796a5c18cf057420aaed5eaf" +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" dependencies = [ "either", ] @@ -1979,127 +1018,58 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" [[package]] -name = "js-sys" -version = "0.3.55" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" -dependencies = [ - "wasm-bindgen", -] - -[[package]] -name = "jsonwebtoken" -version = "8.0.0-beta.4" +name = "jobserver" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e6b9ea0eb2e0b7d564132dda3eba400ff2ad0558c61e59b853873897e3d28" +checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" dependencies = [ - "base64 0.13.0", - "pem", - "ring", - "serde", - "serde_json", - "simple_asn1", -] - -[[package]] -name = "kernel32-sys" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" -dependencies = [ - "winapi 0.2.8", - "winapi-build", -] - -[[package]] -name = "kv-log-macro" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" -dependencies = [ - "log", -] - -[[package]] -name = "lalrpop" -version = "0.19.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15174f1c529af5bf1283c3bc0058266b483a67156f79589fab2a25e23cf8988" -dependencies = [ - "ascii-canvas", - "atty", - "bit-set", - "diff", - "ena", - "itertools", - "lalrpop-util", - "petgraph", - "pico-args", - "regex", - "regex-syntax", - "string_cache", - "term", - "tiny-keccak", - "unicode-xid", + "libc", ] [[package]] -name = "lalrpop-util" -version = "0.19.6" +name = "js-sys" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e58cce361efcc90ba8a0a5f982c741ff86b603495bb15a998412e957dcd278" +checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" dependencies = [ - "regex", + "wasm-bindgen", ] [[package]] name = "language-tags" -version = "0.2.2" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" +checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" [[package]] name = "lazy_static" version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -dependencies = [ - "spin 0.5.2", -] - -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.105" +version = "0.2.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "869d572136620d55835903746bcb5cdc54cb2851fd0aeec53220b4bb65ef3013" +checksum = "8e167738f1866a7ec625567bae89ca0d44477232a4f7c52b1c7f2adc2c98804f" [[package]] -name = "libloading" -version = "0.7.1" +name = "local-channel" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cf036d15402bea3c5d4de17b3fce76b3e4a56ebc1f577be0e7a72f7c607cf0" +checksum = "6246c68cf195087205a0512559c97e15eaf95198bf0e206d662092cdcb03fe9f" dependencies = [ - "cfg-if 1.0.0", - "winapi 0.3.9", + "futures-core", + "futures-sink", + "futures-util", + "local-waker", ] [[package]] -name = "libm" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a" - -[[package]] -name = "linked-hash-map" -version = "0.5.4" +name = "local-waker" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" +checksum = "84f9a2d3e27ce99ce2c3aad0b09b1a7b916293ea9b2bf624c13fe646fadd8da4" [[package]] name = "lock_api" @@ -2116,61 +1086,15 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", - "value-bag", -] - -[[package]] -name = "lru" -version = "0.6.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ea2d928b485416e8908cff2d97d621db22b27f7b3b6729e438bcf42c671ba91" -dependencies = [ - "hashbrown 0.11.2", -] - -[[package]] -name = "lru-cache" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" -dependencies = [ - "linked-hash-map", -] - -[[package]] -name = "mach" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b823e83b2affd8f40a9ee8c29dbc56404c1e34cd2710921f2801e2cf29527afa" -dependencies = [ - "libc", + "cfg-if", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "match_cfg" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" - [[package]] name = "matches" version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" -[[package]] -name = "maybe-uninit" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" - [[package]] name = "md-5" version = "0.9.1" @@ -2179,7 +1103,7 @@ checksum = "7b5a279bb9607f9f53c22d496eade00d138d1bdcccd07d74650387cf94942a15" dependencies = [ "block-buffer 0.9.0", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug", ] [[package]] @@ -2188,21 +1112,6 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" -[[package]] -name = "memoffset" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "043175f069eda7b85febe4a74abbaeff828d9f8b448515d3151a14a3542811aa" -dependencies = [ - "autocfg 1.0.1", -] - -[[package]] -name = "memsec" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2af4f95d8737f4ffafbd1fb3c703cdc898868a244a59786793cba0520ebdcbdd" - [[package]] name = "mime" version = "0.3.16" @@ -2211,9 +1120,9 @@ checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" [[package]] name = "minimal-lexical" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" @@ -2222,191 +1131,88 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" dependencies = [ "adler", - "autocfg 1.0.1", + "autocfg", ] [[package]] name = "minkan_server" version = "0.1.0" dependencies = [ - "actix", "actix-web", - "actix-web-httpauth", "anyhow", - "argon2", - "async-graphql", - "async-graphql-actix-web", - "async-trait", - "bitflags", - "bytes 1.1.0", - "chrono", - "directories", + "base64", + "bytes", + "env_logger", "figment", - "futures", - "hex", - "jsonwebtoken", - "lazy_static", "log", - "moka", - "pretty_env_logger", - "r2d2", - "rand 0.8.4", + "openidconnect", "redis", - "regex", - "sequoia-openpgp", "serde", - "serde_cbor", "serde_json", + "sha2 0.10.0", "sqlx", - "thiserror", - "uuid", + "tokio", + "url", ] [[package]] name = "mio" -version = "0.6.23" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", "miow", - "net2", - "slab", - "winapi 0.2.8", + "ntapi", + "winapi", ] [[package]] -name = "mio-uds" -version = "0.6.8" +name = "mio" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afcb699eb26d4332647cc848492bbc15eafb26f08d0304550d5aa1f612e066f0" +checksum = "ba272f85fa0b41fc91872be579b3bbe0f56b792aa361a380eb669469f68dafb2" dependencies = [ - "iovec", "libc", - "mio", -] - -[[package]] -name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "moka" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9059092f53dfb5e675db0cca75a326913aa85773f9d3e2ea201e412cf3a15a52" -dependencies = [ - "async-io", - "async-lock", - "crossbeam-channel 0.5.1", - "moka-cht", - "num_cpus", - "once_cell", - "parking_lot", - "quanta", - "scheduled-thread-pool", - "skeptic", - "thiserror", - "uuid", -] - -[[package]] -name = "moka-cht" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "829e4b3f52dff046d1824842169dc0a91319f5e923e20a651b4e85697e03feea" -dependencies = [ - "crossbeam-epoch", - "num_cpus", -] - -[[package]] -name = "multer" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "408327e2999b839cd1af003fc01b2019a6c10a1361769542203f6fedc5179680" -dependencies = [ - "bytes 1.1.0", - "encoding_rs", - "futures-util", - "http", - "httparse", "log", - "mime", - "spin 0.9.2", - "twoway", - "version_check", + "miow", + "ntapi", + "winapi", ] [[package]] -name = "net2" -version = "0.2.37" +name = "miow" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "nettle" -version = "7.0.2" +name = "native-tls" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dbaef96ce04e0dafb03b2c5d3803975c84080f876356cb67f44cf85963cedb7" +checksum = "48ba9f7719b5a0f42f338907614285fb5fd70e53858141f69898a1fb7203b24d" dependencies = [ - "getrandom 0.1.16", + "lazy_static", "libc", - "nettle-sys", - "thiserror", -] - -[[package]] -name = "nettle-sys" -version = "2.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b95aff9e61c8d8132e41dceae74c6e526edcac8d120072c87a300b9ab7e75226" -dependencies = [ - "bindgen", - "pkg-config", - "vcpkg", -] - -[[package]] -name = "new_debug_unreachable" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" - -[[package]] -name = "nom" -version = "5.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb4262d26ed83a1c0a33a38fe2bb15797329c85770da05e6b828ddb782627af" -dependencies = [ - "memchr", - "version_check", + "log", + "openssl", + "openssl-probe", + "openssl-sys", + "schannel", + "security-framework", + "security-framework-sys", + "tempfile", ] [[package]] name = "nom" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ "memchr", "minimal-lexical", @@ -2414,30 +1220,23 @@ dependencies = [ ] [[package]] -name = "num-bigint" -version = "0.4.2" +name = "ntapi" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74e768dff5fb39a41b3bcd30bb25cf989706c90d028d1ad71971987aa309d535" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" dependencies = [ - "autocfg 1.0.1", - "num-integer", - "num-traits", + "winapi", ] [[package]] -name = "num-bigint-dig" -version = "0.6.1" +name = "num-bigint" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d51546d704f52ef14b3c962b5776e53d5b862e5790e40a350d366c209bd7f7a" +checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" dependencies = [ - "autocfg 0.1.7", - "byteorder", - "lazy_static", - "libm", + "autocfg", "num-integer", - "num-iter", "num-traits", - "smallvec", ] [[package]] @@ -2446,18 +1245,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" dependencies = [ - "autocfg 1.0.1", - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.42" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" -dependencies = [ - "autocfg 1.0.1", - "num-integer", + "autocfg", "num-traits", ] @@ -2467,7 +1255,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" dependencies = [ - "autocfg 1.0.1", + "autocfg", ] [[package]] @@ -2481,12 +1269,23 @@ dependencies = [ ] [[package]] -name = "object" -version = "0.27.1" +name = "oauth2" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67ac1d3f9a1d3616fd9a60c8d74296f22406a238b6a72f5cc1e6f314df4ffbf9" +checksum = "80e47cfc4c0a1a519d9a025ebfbac3a2439d1b5cdf397d72dcb79b11d9920dab" dependencies = [ - "memchr", + "base64", + "chrono", + "getrandom", + "http", + "rand", + "reqwest", + "serde", + "serde_json", + "serde_path_to_error", + "sha2 0.9.8", + "thiserror", + "url", ] [[package]] @@ -2495,12 +1294,6 @@ version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "opaque-debug" version = "0.3.0" @@ -2508,188 +1301,139 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - -[[package]] -name = "parking_lot" -version = "0.11.2" +name = "openidconnect" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" +checksum = "7d523cf32bdf7696f36bc4198a42c34b65f0227b97f2f501ebfbe016baa5bc52" dependencies = [ - "instant", - "lock_api", - "parking_lot_core", + "base64", + "chrono", + "http", + "itertools 0.9.0", + "log", + "num-bigint", + "oauth2", + "rand", + "ring", + "serde", + "serde-value", + "serde_derive", + "serde_json", + "serde_path_to_error", + "thiserror", + "untrusted", + "url", ] [[package]] -name = "parking_lot_core" -version = "0.8.5" +name = "openssl" +version = "0.10.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" +checksum = "0c7ae222234c30df141154f159066c5093ff73b63204dcda7121eb082fc56a95" dependencies = [ - "cfg-if 1.0.0", - "instant", + "bitflags", + "cfg-if", + "foreign-types", "libc", - "redox_syscall", - "smallvec", - "winapi 0.3.9", -] - -[[package]] -name = "password-hash" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e0b28ace46c5a396546bcf443bf422b57049617433d8854227352a4a9b24e7" -dependencies = [ - "base64ct", - "rand_core 0.6.3", - "subtle", -] - -[[package]] -name = "pear" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi", -] - -[[package]] -name = "pear_codegen" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn", -] - -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - -[[package]] -name = "pem" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f2373df5233932a893d3bc2c78a0bf3f6d12590a1edd546b4fbefcac32c5c0f" -dependencies = [ - "base64 0.13.0", "once_cell", - "regex", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", + "openssl-sys", ] [[package]] -name = "pest_derive" -version = "2.1.0" +name = "openssl-probe" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] +checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" [[package]] -name = "pest_generator" -version = "2.1.3" +name = "openssl-sys" +version = "0.9.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" +checksum = "7e46109c383602735fa0a2e48dd2b7c892b048e1bf69e5c3b1d804b7d9c203cb" dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", + "autocfg", + "cc", + "libc", + "pkg-config", + "vcpkg", ] [[package]] -name = "pest_meta" -version = "2.1.3" +name = "ordered-float" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" +checksum = "3305af35278dd29f46fcdd139e0b1fbfae2153f0e5928b39b035542dd31e37b7" dependencies = [ - "maplit", - "pest", - "sha-1 0.8.2", + "num-traits", ] [[package]] -name = "petgraph" -version = "0.5.1" +name = "parking_lot" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "467d164a6de56270bd7c4d070df81d07beace25012d5103ced4e9ff08d6afdb7" +checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ - "fixedbitset", - "indexmap", + "instant", + "lock_api", + "parking_lot_core", ] [[package]] -name = "phf_shared" -version = "0.8.0" +name = "parking_lot_core" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" dependencies = [ - "siphasher", + "cfg-if", + "instant", + "libc", + "redox_syscall", + "smallvec", + "winapi", ] [[package]] -name = "pico-args" -version = "0.4.2" +name = "paste" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db8bcd96cb740d03149cbad5518db9fd87126a10ab519c011893b1754134c468" +checksum = "0744126afe1a6dd7f394cb50a716dbe086cb06e255e53d8d0185d82828358fb5" [[package]] -name = "pin-project" -version = "0.4.28" +name = "pear" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918192b5c59119d51e0cd221f4d49dde9112824ba717369e903c97d076083d0f" +checksum = "15e44241c5e4c868e3eaa78b7c1848cadd6344ed4f54d029832d32b415a58702" dependencies = [ - "pin-project-internal 0.4.28", + "inlinable_string", + "pear_codegen", + "yansi", ] [[package]] -name = "pin-project" -version = "1.0.8" +name = "pear_codegen" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" +checksum = "82a5ca643c2303ecb740d506539deba189e16f2754040a42901cd8105d0282d0" dependencies = [ - "pin-project-internal 1.0.8", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "syn", ] [[package]] -name = "pin-project-internal" -version = "0.4.28" +name = "percent-encoding" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" + +[[package]] +name = "pin-project" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3be26700300be6d9d23264c73211d8190e755b6b5ca7a1b28230025511b52a5e" +checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" dependencies = [ - "proc-macro2", - "quote", - "syn", + "pin-project-internal", ] [[package]] @@ -2703,12 +1447,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.7" @@ -2723,54 +1461,15 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pkg-config" -version = "0.3.22" +version = "0.3.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12295df4f294471248581bc09bef3c38a5e46f1e36d6a37353621a0c6c357e1f" - -[[package]] -name = "polling" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi 0.3.9", -] +checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "ppv-lite86" -version = "0.2.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3ca011bd0129ff4ae15cd04c4eef202cadf6c51c21e47aba319b4e0501db741" - -[[package]] -name = "precomputed-hash" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" - -[[package]] -name = "pretty_env_logger" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" -dependencies = [ - "env_logger", - "log", -] - -[[package]] -name = "proc-macro-crate" -version = "1.1.0" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ebace6889caf889b4d3f76becee12e90353f2b8c7d875534a71e5742f8f6f83" -dependencies = [ - "thiserror", - "toml", -] +checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" [[package]] name = "proc-macro-hack" @@ -2778,17 +1477,11 @@ version = "0.5.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" -[[package]] -name = "proc-macro-nested" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc881b2c22681370c6a780e47af9840ef841837bc98118431d4e1868bd0c1086" - [[package]] name = "proc-macro2" -version = "1.0.30" +version = "1.0.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edc3358ebc67bc8b7fa0c007f945b0b18226f78437d61bec735a9eb96b61ee70" +checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" dependencies = [ "unicode-xid", ] @@ -2806,39 +1499,6 @@ dependencies = [ "yansi", ] -[[package]] -name = "pulldown-cmark" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "quanta" -version = "0.9.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20afe714292d5e879d8b12740aa223c6a88f118af41870e8b6196e39a02238a8" -dependencies = [ - "crossbeam-utils 0.8.5", - "libc", - "mach", - "once_cell", - "raw-cpuid", - "wasi 0.10.2+wasi-snapshot-preview1", - "web-sys", - "winapi 0.3.9", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.10" @@ -2859,19 +1519,6 @@ dependencies = [ "scheduled-thread-pool", ] -[[package]] -name = "rand" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" -dependencies = [ - "getrandom 0.1.16", - "libc", - "rand_chacha 0.2.2", - "rand_core 0.5.1", - "rand_hc 0.2.0", -] - [[package]] name = "rand" version = "0.8.4" @@ -2879,19 +1526,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" dependencies = [ "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.3", - "rand_hc 0.3.1", -] - -[[package]] -name = "rand_chacha" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" -dependencies = [ - "ppv-lite86", - "rand_core 0.5.1", + "rand_chacha", + "rand_core", + "rand_hc", ] [[package]] @@ -2901,16 +1538,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", -] - -[[package]] -name = "rand_core" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" -dependencies = [ - "getrandom 0.1.16", + "rand_core", ] [[package]] @@ -2919,16 +1547,7 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom 0.2.3", -] - -[[package]] -name = "rand_hc" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" -dependencies = [ - "rand_core 0.5.1", + "getrandom", ] [[package]] @@ -2937,37 +1556,31 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" dependencies = [ - "rand_core 0.6.3", -] - -[[package]] -name = "raw-cpuid" -version = "10.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "929f54e29691d4e6a9cc558479de70db7aa3d98cd6fe7ab86d7507aa2886b9d2" -dependencies = [ - "bitflags", + "rand_core", ] [[package]] name = "redis" -version = "0.21.3" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd71bdb3d0d6e9183e675c977f652fbf8abc3b63fcb722e9abb42f82ef839b65" +checksum = "7f23ceed4c0e76b322657c2c3352ea116f9ec60a1a1aefeb3c84ed062c50865b" dependencies = [ - "async-std", + "arc-swap", "async-trait", - "bytes 1.1.0", + "bytes", "combine", "dtoa", + "futures", "futures-util", "itoa", + "native-tls", "percent-encoding", - "pin-project-lite 0.2.7", + "pin-project-lite", "r2d2", "sha1", - "tokio 1.12.0", - "tokio-util 0.6.8", + "tokio", + "tokio-native-tls", + "tokio-util", "url", ] @@ -2986,7 +1599,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom 0.2.3", + "getrandom", "redox_syscall", ] @@ -3013,17 +1626,44 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] -name = "resolv-conf" -version = "0.7.0" +name = "reqwest" +version = "0.11.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" dependencies = [ - "hostname", - "quick-error", + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rustls 0.20.2", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "tokio", + "tokio-rustls 0.23.1", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg", ] [[package]] @@ -3035,24 +1675,12 @@ dependencies = [ "cc", "libc", "once_cell", - "spin 0.5.2", + "spin", "untrusted", "web-sys", - "winapi 0.3.9", + "winapi", ] -[[package]] -name = "rustc-demangle" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" - -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustc_version" version = "0.2.3" @@ -3064,45 +1692,61 @@ dependencies = [ [[package]] name = "rustc_version" -version = "0.3.3" +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 = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" dependencies = [ - "semver 0.11.0", + "base64", + "log", + "ring", + "sct 0.6.1", + "webpki 0.21.4", ] [[package]] name = "rustls" -version = "0.18.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d1126dcf58e93cee7d098dbda643b5f92ed724f1f6a63007c1116eed6700c81" +checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" dependencies = [ - "base64 0.12.3", "log", "ring", - "sct", - "webpki", + "sct 0.7.0", + "webpki 0.22.0", ] [[package]] -name = "rustversion" -version = "1.0.5" +name = "rustls-pemfile" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61b3909d758bb75c79f23d4736fac9433868679d3ad2ea7a61e3c25cfda9a088" +checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +dependencies = [ + "base64", +] [[package]] name = "ryu" -version = "1.0.5" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +checksum = "254df5081ce98661a883445175e52efe99d1cb2a5552891d965d2f5d0cad1c16" [[package]] -name = "same-file" -version = "1.0.6" +name = "schannel" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" dependencies = [ - "winapi-util", + "lazy_static", + "winapi", ] [[package]] @@ -3131,93 +1775,83 @@ dependencies = [ ] [[package]] -name = "semver" -version = "0.9.0" +name = "sct" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "semver-parser 0.7.0", + "ring", + "untrusted", ] [[package]] -name = "semver" -version = "0.11.0" +name = "security-framework" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" +checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" dependencies = [ - "semver-parser 0.10.2", - "serde", + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", ] [[package]] -name = "semver-parser" -version = "0.7.0" +name = "security-framework-sys" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +dependencies = [ + "core-foundation-sys", + "libc", +] [[package]] -name = "semver-parser" -version = "0.10.2" +name = "semver" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" dependencies = [ - "pest", + "semver-parser", ] [[package]] -name = "sequoia-openpgp" -version = "1.5.0" +name = "semver" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d99023a5010403956bae568a28dc7574a447665477509edd35ddd547cff1e6ec" -dependencies = [ - "anyhow", - "backtrace", - "base64 0.13.0", - "buffered-reader", - "chrono", - "dyn-clone", - "eax", - "ed25519-dalek", - "idna", - "lalrpop", - "lalrpop-util", - "lazy_static", - "libc", - "memsec", - "nettle", - "num-bigint-dig", - "regex", - "regex-syntax", - "sha1collisiondetection", - "thiserror", - "win-crypto-ng", - "winapi 0.3.9", -] +checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" [[package]] name = "serde" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f12d06de37cf59146fbdecab66aa99f9fe4f78722e3607577a5375d66bd0c913" +checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" dependencies = [ "serde_derive", ] [[package]] -name = "serde_cbor" -version = "0.11.2" +name = "serde-value" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +checksum = "5a65a7291a8a568adcae4c10a677ebcedbc6c9cec91c054dee2ce40b0e3290eb" dependencies = [ - "half", + "ordered-float", "serde", ] [[package]] name = "serde_derive" -version = "1.0.130" +version = "1.0.131" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7bc1a1ab1961464eae040d96713baa5a724a8152c1222492465b54322ec508b" +checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" dependencies = [ "proc-macro2", "quote", @@ -3226,16 +1860,24 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.68" +version = "1.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f690853975602e1bfe1ccbf50504d67174e3bcf340f23b5ea9992e0587a52d8" +checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" dependencies = [ - "indexmap", "itoa", "ryu", "serde", ] +[[package]] +name = "serde_path_to_error" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0421d4f173fab82d72d6babf36d57fae38b994ca5c2d78e704260ba6d12118b" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -3248,18 +1890,6 @@ dependencies = [ "serde", ] -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer 0.7.3", - "digest 0.8.1", - "fake-simd", - "opaque-debug 0.2.3", -] - [[package]] name = "sha-1" version = "0.9.8" @@ -3267,10 +1897,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug", ] [[package]] @@ -3279,17 +1909,6 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" -[[package]] -name = "sha1collisiondetection" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a6cf187c4059b3e63de2358b7e2f9a2261b6f3fd8ef4e7342308d0863ed082" -dependencies = [ - "digest 0.9.0", - "generic-array 0.14.4", - "libc", -] - [[package]] name = "sha2" version = "0.9.8" @@ -3297,17 +1916,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" dependencies = [ "block-buffer 0.9.0", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest 0.9.0", - "opaque-debug 0.3.0", + "opaque-debug", ] [[package]] -name = "shlex" -version = "0.1.1" +name = "sha2" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdf1b9db47230893d76faad238fd6097fd6d6a9245cd7a4d90dbd639536bbd2" +checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.0", +] [[package]] name = "signal-hook-registry" @@ -3318,45 +1942,6 @@ dependencies = [ "libc", ] -[[package]] -name = "signature" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02658e48d89f2bec991f9a78e69cfa4c316f8d6a6c4ec12fae1aeb263d486788" - -[[package]] -name = "simple_asn1" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eb4ea60fb301dc81dfc113df680571045d375ab7345d171c5dc7d7e13107a80" -dependencies = [ - "chrono", - "num-bigint", - "num-traits", - "thiserror", -] - -[[package]] -name = "siphasher" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533494a8f9b724d33625ab53c6c4800f7cc445895924a8ef649222dcb76e938b" - -[[package]] -name = "skeptic" -version = "0.13.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "188b810342d98f23f0bb875045299f34187b559370b041eb11520c905370a888" -dependencies = [ - "bytecount", - "cargo_metadata", - "error-chain", - "glob", - "pulldown-cmark", - "tempfile", - "walkdir", -] - [[package]] name = "slab" version = "0.4.5" @@ -3369,17 +1954,6 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" -[[package]] -name = "socket2" -version = "0.3.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "winapi 0.3.9", -] - [[package]] name = "socket2" version = "0.4.2" @@ -3387,7 +1961,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3396,28 +1970,22 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" -[[package]] -name = "spin" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511254be0c5bcf062b019a6c89c01a664aa359ded62f78aa72c6fc137c0590e5" - [[package]] name = "sqlformat" version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4b7922be017ee70900be125523f38bdd644f4f06a1b16e8fa5a8ee8c34bffd4" dependencies = [ - "itertools", - "nom 7.0.0", + "itertools 0.10.3", + "nom", "unicode_categories", ] [[package]] name = "sqlx" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a98f9bf17b690f026b6fec565293a995b46dfbd6293debcb654dcffd2d1b34" +checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43" dependencies = [ "sqlx-core", "sqlx-macros", @@ -3425,29 +1993,30 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36bb6a2ca3345a86493bc3b71eabc2c6c16a8bb1aa476cf5303bee27f67627d7" +checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1" dependencies = [ - "ahash 0.6.3", + "ahash", "atoi", - "base64 0.13.0", + "base64", "bitflags", "byteorder", - "bytes 0.5.6", - "chrono", + "bytes", "crc", - "crossbeam-channel 0.5.1", + "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils 0.8.5", + "crossbeam-utils", + "dirs", "either", "futures-channel", "futures-core", + "futures-intrusive", "futures-util", "hashlink", "hex", "hmac", - "ipnetwork", + "indexmap", "itoa", "libc", "log", @@ -3456,41 +2025,37 @@ dependencies = [ "once_cell", "parking_lot", "percent-encoding", - "rand 0.7.3", - "rustls", + "rand", + "rustls 0.19.1", "serde", - "sha-1 0.9.8", - "sha2", + "serde_json", + "sha-1", + "sha2 0.9.8", "smallvec", "sqlformat", "sqlx-rt", "stringprep", "thiserror", + "tokio-stream", "url", - "uuid", - "webpki", + "webpki 0.21.4", "webpki-roots", "whoami", ] [[package]] name = "sqlx-macros" -version = "0.4.2" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b5ada8b3b565331275ce913368565a273a74faf2a34da58c4dc010ce3286844" +checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" dependencies = [ - "cargo_metadata", "dotenv", "either", - "futures", "heck", - "hex", - "lazy_static", + "once_cell", "proc-macro2", "quote", - "serde", - "serde_json", - "sha2", + "sha2 0.9.8", "sqlx-core", "sqlx-rt", "syn", @@ -3499,15 +2064,14 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.2.0" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63fc5454c9dd7aaea3a0eeeb65ca40d06d0d8e7413a8184f7c3a3ffa5056190b" +checksum = "0d1bd069de53442e7a320f525a6d4deb8bb0621ac7a55f7eccbc2b58b57f43d0" dependencies = [ "actix-rt", - "actix-threadpool", "once_cell", - "tokio 0.2.25", - "tokio-rustls", + "tokio", + "tokio-rustls 0.22.0", ] [[package]] @@ -3519,12 +2083,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "static_assertions" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" - [[package]] name = "stdweb" version = "0.4.20" @@ -3574,19 +2132,6 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" -[[package]] -name = "string_cache" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "923f0f39b6267d37d23ce71ae7235602134b250ace715dd2c90421998ddac0c6" -dependencies = [ - "lazy_static", - "new_debug_unreachable", - "parking_lot", - "phf_shared", - "precomputed-hash", -] - [[package]] name = "stringprep" version = "0.1.2" @@ -3597,12 +2142,6 @@ dependencies = [ "unicode-normalization", ] -[[package]] -name = "strsim" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" - [[package]] name = "subtle" version = "2.4.1" @@ -3611,24 +2150,12 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.80" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "synstructure" -version = "0.12.6" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" dependencies = [ "proc-macro2", "quote", - "syn", "unicode-xid", ] @@ -3638,23 +2165,12 @@ version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", - "rand 0.8.4", + "rand", "redox_syscall", "remove_dir_all", - "winapi 0.3.9", -] - -[[package]] -name = "term" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f" -dependencies = [ - "dirs-next", - "rustversion", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3686,25 +2202,6 @@ dependencies = [ "syn", ] -[[package]] -name = "threadpool" -version = "1.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d050e60b33d41c19108b32cea32164033a9013fe3b46cbd4457559bfbf77afaa" -dependencies = [ - "num_cpus", -] - -[[package]] -name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi 0.3.9", -] - [[package]] name = "time" version = "0.2.27" @@ -3717,7 +2214,17 @@ dependencies = [ "stdweb", "time-macros", "version_check", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "time" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" +dependencies = [ + "itoa", + "libc", ] [[package]] @@ -3743,20 +2250,11 @@ dependencies = [ "syn", ] -[[package]] -name = "tiny-keccak" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237" -dependencies = [ - "crunchy", -] - [[package]] name = "tinyvec" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f83b2a3d4d9091d0abd7eba4dc2710b1718583bd4d8992e2190720ea38f391f7" +checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" dependencies = [ "tinyvec_macros", ] @@ -3769,89 +2267,78 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "0.2.25" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6703a273949a90131b290be1fe7b039d0fc884aa1935860dfcbe056f28cd8092" +checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" dependencies = [ - "bytes 0.5.6", - "fnv", - "futures-core", - "iovec", - "lazy_static", + "autocfg", + "bytes", "libc", "memchr", - "mio", - "mio-uds", + "mio 0.7.14", "num_cpus", - "pin-project-lite 0.1.12", + "once_cell", + "parking_lot", + "pin-project-lite", "signal-hook-registry", - "slab", - "tokio-macros", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "tokio" -version = "1.12.0" +name = "tokio-native-tls" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2c2416fdedca8443ae44b4527de1ea633af61d8f7169ffa6e72c5b53d24efcc" +checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b" dependencies = [ - "autocfg 1.0.1", - "bytes 1.1.0", - "memchr", - "pin-project-lite 0.2.7", + "native-tls", + "tokio", ] [[package]] -name = "tokio-macros" -version = "0.2.6" +name = "tokio-rustls" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e44da00bfc73a25f814cd8d7e57a68a5c31b74b3152a0a1d1f590c97ed06265a" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "proc-macro2", - "quote", - "syn", + "rustls 0.19.1", + "tokio", + "webpki 0.21.4", ] [[package]] name = "tokio-rustls" -version = "0.14.1" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e12831b255bcfa39dc0436b01e19fea231a37db570686c06ee72c423479f889a" +checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689" dependencies = [ - "futures-core", - "rustls", - "tokio 0.2.25", - "webpki", + "rustls 0.20.2", + "tokio", + "webpki 0.22.0", ] [[package]] -name = "tokio-util" -version = "0.3.1" +name = "tokio-stream" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be8242891f2b6cbef26a2d7e8605133c2c554cd35b3e4948ea892d6d68436499" +checksum = "50145484efff8818b5ccd256697f36863f587da82cf8b409c53adf1e840798e3" dependencies = [ - "bytes 0.5.6", "futures-core", - "futures-io", - "futures-sink", - "log", - "pin-project-lite 0.1.12", - "tokio 0.2.25", + "pin-project-lite", + "tokio", ] [[package]] name = "tokio-util" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d3725d3efa29485e87311c5b699de63cde14b00ed4d256b8318aa30ca452cd" +checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" dependencies = [ - "bytes 1.1.0", + "bytes", "futures-core", "futures-sink", "log", - "pin-project-lite 0.2.7", - "tokio 1.12.0", + "pin-project-lite", + "tokio", ] [[package]] @@ -3863,15 +2350,20 @@ dependencies = [ "serde", ] +[[package]] +name = "tower-service" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + [[package]] name = "tracing" version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" dependencies = [ - "cfg-if 1.0.0", - "log", - "pin-project-lite 0.2.7", + "cfg-if", + "pin-project-lite", "tracing-core", ] @@ -3885,63 +2377,10 @@ dependencies = [ ] [[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project 1.0.8", - "tracing", -] - -[[package]] -name = "trust-dns-proto" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cad71a0c0d68ab9941d2fb6e82f8fb2e86d9945b94e1661dd0aaea2b88215a9" -dependencies = [ - "async-trait", - "cfg-if 1.0.0", - "enum-as-inner", - "futures", - "idna", - "lazy_static", - "log", - "rand 0.7.3", - "smallvec", - "thiserror", - "tokio 0.2.25", - "url", -] - -[[package]] -name = "trust-dns-resolver" -version = "0.19.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710f593b371175db53a26d0b38ed2978fafb9e9e8d3868b1acd753ea18df0ceb" -dependencies = [ - "cfg-if 0.1.10", - "futures", - "ipconfig", - "lazy_static", - "log", - "lru-cache", - "resolv-conf", - "smallvec", - "thiserror", - "tokio 0.2.25", - "trust-dns-proto", -] - -[[package]] -name = "twoway" -version = "0.2.2" +name = "try-lock" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c57ffb460d7c24cd6eda43694110189030a3d1dfe418416d9468fd1c1d290b47" -dependencies = [ - "memchr", - "unchecked-index", -] +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" @@ -3949,12 +2388,6 @@ version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "uncased" version = "0.9.6" @@ -3964,21 +2397,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "unchecked-index" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eeba86d422ce181a719445e51872fa30f1f7413b62becb52e95ec91aa262d85c" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.7" @@ -4028,28 +2446,9 @@ dependencies = [ "idna", "matches", "percent-encoding", -] - -[[package]] -name = "uuid" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc5cf98d8186244414c848017f0e2676b3fcb46807f6668a97dfe67359a3c4b7" -dependencies = [ - "getrandom 0.2.3", "serde", ] -[[package]] -name = "value-bag" -version = "1.0.0-alpha.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" -dependencies = [ - "ctor", - "version_check", -] - [[package]] name = "vcpkg" version = "0.2.15" @@ -4063,28 +2462,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" [[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - -[[package]] -name = "walkdir" -version = "2.3.2" +name = "want" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" dependencies = [ - "same-file", - "winapi 0.3.9", - "winapi-util", + "log", + "try-lock", ] -[[package]] -name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" - [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" @@ -4097,7 +2483,7 @@ version = "0.2.78" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "wasm-bindgen-macro", ] @@ -4122,7 +2508,7 @@ version = "0.4.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -4178,58 +2564,34 @@ dependencies = [ ] [[package]] -name = "webpki-roots" -version = "0.21.1" +name = "webpki" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" dependencies = [ - "webpki", + "ring", + "untrusted", ] [[package]] -name = "wepoll-ffi" -version = "0.1.2" +name = "webpki-roots" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" dependencies = [ - "cc", + "webpki 0.21.4", ] [[package]] name = "whoami" -version = "1.1.5" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "483a59fee1a93fec90eb08bc2eb4315ef10f4ebc478b3a5fadc969819cb66117" +checksum = "524b58fa5a20a2fb3014dd6358b70e6579692a56ef6fce928834e488f42f65e8" dependencies = [ "wasm-bindgen", "web-sys", ] -[[package]] -name = "widestring" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" - -[[package]] -name = "win-crypto-ng" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24cf92e98e8f4ade45b5140795415a0f256fd9b69a1919248dcda11ba5d6466c" -dependencies = [ - "cipher", - "doc-comment", - "rand_core 0.5.1", - "winapi 0.3.9", - "zeroize", -] - -[[package]] -name = "winapi" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" - [[package]] name = "winapi" version = "0.3.9" @@ -4240,12 +2602,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -4258,7 +2614,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -4269,21 +2625,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "winreg" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" -dependencies = [ - "winapi 0.3.9", -] - -[[package]] -name = "ws2_32-sys" -version = "0.2.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "winapi", ] [[package]] @@ -4293,22 +2639,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" [[package]] -name = "zeroize" -version = "1.4.2" +name = "zstd" +version = "0.9.0+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf68b08513768deaa790264a7fac27a58cbf2705cfcdc9448362229217d7e970" +checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" dependencies = [ - "zeroize_derive", + "zstd-safe", ] [[package]] -name = "zeroize_derive" -version = "1.2.0" +name = "zstd-safe" +version = "4.1.1+zstd.1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdff2024a851a322b08f179173ae2ba620445aef1e838f0c196820eade4ae0c7" +checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" dependencies = [ - "proc-macro2", - "quote", - "syn", - "synstructure", + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "1.6.1+zstd.1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +dependencies = [ + "cc", + "libc", ] diff --git a/Cargo.toml b/Cargo.toml index ca76772..5985d43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,47 +4,35 @@ version = "0.1.0" authors = [ "Erik Tesar ", ] -edition = "2018" +edition = "2021" license = "AGPL-3.0-or-later" [dependencies] -actix = "0.10" -actix-web = "3" -async-graphql = { version = "2.10", features = ["apollo_tracing", "uuid", "dataloader", "cbor"] } -async-graphql-actix-web = "2.10" -bitflags = "1.3" -log = "0.4" -pretty_env_logger = "0.4" -thiserror = "1" -sqlx = { version = "0.4", features = ["chrono", "ipnetwork", "macros", "migrate", "offline", "postgres", "runtime-actix-rustls", "uuid"] } -serde = { version = "1", features = ["derive"]} -serde_cbor = "0.11" -serde_json = "1.0.66" -uuid = { version = "0.8", features = ["serde", "v4"] } -bytes = { version = "1", features = ["serde"] } -moka = { version = "0.5", features = ["future"] } -chrono = { version = "0.4", features = ["serde"] } -rand = "0.8.4" -hex = "0.4.3" -argon2 = "0.2" -regex = "1.5.4" -lazy_static = "1.4.0" -jsonwebtoken = "8.0.0-beta.2" -anyhow = "1.0.43" -sequoia-openpgp = { version = "1.3", default-features = false} -async-trait = "0.1.51" -actix-web-httpauth = "0.5.1" -futures = "0.3.17" -redis = { version = "0.21.2", features = ["async-std-comp", "aio", "r2d2"] } -r2d2 = "0.8.9" -figment = { version = "0.10.6", features = ["env", "toml"]} -directories = "3" - -[features] -# This is a workaround for https://github.com/rust-lang/cargo/issues/1197 -# On windows disable default features when building and enable the "win" feature -# We won't need this anymore if Cargo supports target feature flags or we have -# a full rust crypto backend (no c/c++ dependencies). -default = ["unix"] -win = ["sequoia-openpgp/crypto-cng"] -unix = ["sequoia-openpgp/crypto-nettle"] +# the web framework to serve endpoints +actix-web = "4.0.0-beta.14" +# for the logger macros +log = "0.4.14" +# an backend to actually output logs +env_logger = "0.9.0" +serde = { version = "1.0.131", features = ["derive"] } +# to proccess raw binary data +bytes = { version = "1.1.0", features = ["serde"] } +# for easy error handling +anyhow = { version = "1.0.51", features = ["std"] } +# for configuration +figment = { version = "0.10.6", features = ["env", "toml"] } +# for openid connect integrations +openidconnect = "2.1.2" +# for hashing of the nonce and state parameter +sha2 = "0.10.0" +# used to encode the hash into base64 so it can be stored as a cookie +base64 = "0.13.0" +# used for redirect url parsing and cookie domain / path +url = { version = "2.2.2", features = ["serde"] } +# for communication with the postgres database +sqlx = { version = "0.5.9", features = ["macros", "migrate", "postgres", "runtime-actix-rustls"]} +# for communication with redis so we can share state between instances +redis = { version = "0.21.4", features = ["tokio-native-tls-comp", "tokio-comp", "connection-manager", "r2d2"] } +serde_json = "1.0.59" +# for an async Mutex +tokio = { version = "1.14.0", features = ["sync"] } \ No newline at end of file diff --git a/other/config.sample b/other/config.sample index 9d923b7..cb38dc4 100644 --- a/other/config.sample +++ b/other/config.sample @@ -1,9 +1,10 @@ -db_uri = "postgresql://my_user@my_password@my.host/my_database" -redis_ui = "redis://my_other_user@other_password@my.host/" -listen = "0.0.0.0:8080" -jwt_secret = "" -server_cert = """ ------BEGIN PGP PRIVATE KEY BLOCK----- -insert my privat key here ------END PGP PRIVATE KEY BLOCK----- -""" +listen = "127.0.0.1:8080" +postgres_uri = "postgres://my_user:my_password@example.com:5432/minkan" +redis_uri = "rediss://redis:redis_password@example.com:6380" + + +[openid_connect] +client_id = "minkan-server" +client_secret = "aaa" +discovery_url = "https://sso.erik-tesar.com/auth/realms/minkan" +redirect_url = "http://localhost:8080/odic/callback" \ No newline at end of file diff --git a/src/ac/mod.rs b/src/ac/mod.rs deleted file mode 100644 index b36b113..0000000 --- a/src/ac/mod.rs +++ /dev/null @@ -1 +0,0 @@ -// pub mod permissions; diff --git a/src/ac/permissions.rs b/src/ac/permissions.rs deleted file mode 100644 index 9c8117f..0000000 --- a/src/ac/permissions.rs +++ /dev/null @@ -1,54 +0,0 @@ -use bitflags::bitflags; - -bitflags! { - struct Flags: u64 { - const MESSAGE_READ = 1 << 0; - const MESSAGE_SEND = 1 << 1; - const MESSAGE_EDIT = 1 << 2; - const MESSAGE_DELETE = 1 << 3; - const MESSAGE_DELETE_OWNED = 1 << 4; - const CHANNEL_CREATE = 1 << 5; - const CHANNEL_EDIT = 1 << 6; - const CHANNEL_DELETE = 1 << 7; - const USER_INVITE = 1 << 8; - const USER_EDIT = 1 << 9; - const USER_DELETE = 1 << 10; - const USER_SUSPEND = 1 << 11; - } -} - -pub enum Permission { - /// Read the messages from a given textchannel - MessageRead, - /// Send a message in a given textchannel - MessageSend, - /// Edit own message after the user has sent it - MessageEdit, - /// Delete another users message - MessageDelete, - /// Delete a message previously sent by the user - MessageDeleteOwned, - /// Create a new channel - ChannelCreate, - /// Edit a channels description, name, etc - ChannelEdit, - /// Delete a channel - ChannelDelete, - /// Create a new useraccount - UserInvite, - /// Edit another user's account - UserEdit, - /// Delete another user's account - UserDelete, - /// Suspend another user's account - UserSuspend, -} - -/// This checks whether a given sum includes a permission -pub fn check_permission(sum: u64, permission: u64) -> bool { - if permission < 64 { - sum & permission != 0 - } else { - false - } -} diff --git a/src/ac/role.rs b/src/ac/role.rs deleted file mode 100644 index 8b13789..0000000 --- a/src/ac/role.rs +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/actors/authenticated_user.rs b/src/actors/authenticated_user.rs deleted file mode 100644 index f2fe1af..0000000 --- a/src/actors/authenticated_user.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::{ - auth::{token::TokenPair, Session}, - certificate::Certificate, - loader::{PrivateCertificateLoader, UsernameLoader}, -}; -use async_graphql::{dataloader::DataLoader, Context, Object}; -use jsonwebtoken::EncodingKey; -use sqlx::{Pool, Postgres}; - -use super::User; - -#[derive(Debug)] -#[repr(transparent)] -/// AuthenticatedUser -/// -/// This object represents the result of an successful authentication. It is DANGEROURS -/// because the methods are able to generate new [``crate::auth::Session``]s. If this -/// ends up in a recursion, it is possible to generate unlimited sessions for an user. -/// -/// Also, if this object is returned, it is possible to obtain the -/// secret key material of a user. -/// -/// **This struct does nothing do validate any credentials** -pub struct AuthenticatedUser(uuid::Uuid); - -#[Object] -impl AuthenticatedUser { - pub async fn id(&self) -> async_graphql::ID { - self.0.into() - } - - pub async fn name(&self, ctx: &Context<'_>) -> String { - ctx.data_unchecked::>() - .load_one(self.0) - .await - .unwrap() - .unwrap() - } - - pub async fn certificate(&self, ctx: &Context<'_>) -> Certificate { - ctx.data_unchecked::>() - .load_one(self.0) - .await - .unwrap() - .unwrap() - } - - /// generates a new session and returns the first ``TokenPair`` - pub async fn token(&self, ctx: &Context<'_>, session_name: Option) -> TokenPair { - let db = ctx.data_unchecked::>(); - let key = ctx.data_unchecked::(); - let session = Session::new(self.0, session_name, db).await.unwrap(); - TokenPair::new(session, key).await - } -} - -impl From for AuthenticatedUser { - /// Use this with ATTENTION. You turn an unauthenticated - /// [``crate::actors::User``] into an [``AuthenticatedUser``] - fn from(user: User) -> Self { - Self(user.id) - } -} diff --git a/src/actors/mod.rs b/src/actors/mod.rs deleted file mode 100644 index 38d8501..0000000 --- a/src/actors/mod.rs +++ /dev/null @@ -1,36 +0,0 @@ -use async_graphql::Interface; - -mod authenticated_user; -mod user; -use crate::certificate::Certificate; -pub use authenticated_user::AuthenticatedUser; -pub use user::User; - -#[derive(Interface, Debug)] -#[graphql( - field(name = "name", type = "String", desc = "The name of the actor"), - field( - name = "certificate", - type = "Certificate", - desc = "The OpenPGP certificate of the ``Actor``" - ) -)] -/// Shared behavior -/// -/// An ``Actor`` is everything that can *act*. -/// An action can be to send a message in a channel or to kick someone. -/// Currently, we only have the ``User`` as an Actor so -/// this interface is primary to allow future non-breaking extensions. -/// -/// # Example -/// -/// Alice can perform *actions* like sending a message, so she's an -/// Actor. -/// -/// In the future, we could introduce a Bot which, like Alice, is able -/// to send messages, kick someone or take any other action. So the bot would -/// be an Actor too. -pub enum Actor { - User(User), - AuthenticatedUser(AuthenticatedUser), -} diff --git a/src/actors/user.rs b/src/actors/user.rs deleted file mode 100644 index 1ba302c..0000000 --- a/src/actors/user.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! User -//! -//! This represents a normal user without any specialization - -use crate::{ - certificate::Certificate, - fallible::{ - CertificateTaken, Error, InvalidMasterPasswordHash, InvalidUsername, NoSuchUser, - UsernameUnavailable, - }, - graphql::Bytes, - loader::{PublicCertificateLoader, UsernameLoader}, -}; -use argon2::{password_hash::SaltString, Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; -use async_graphql::{dataloader::DataLoader, Context, Object}; -use chrono::{DateTime, Utc}; -use lazy_static::lazy_static; -use sequoia_openpgp::{serialize::SerializeInto, Cert}; -use sqlx::{Pool, Postgres}; -use uuid::Uuid; - -use super::AuthenticatedUser; - -#[derive(Debug)] -pub struct User { - pub(super) id: uuid::Uuid, -} - -impl User { - /// Create a new [`User`] - /// This function inserts a new user into the database - pub async fn new( - name: String, - cert: &Cert, - mpw: Bytes, - db: &Pool, - ) -> Result { - // generate salt - let salt = SaltString::generate(&mut rand::rngs::OsRng); - - lazy_static! { - static ref ARGON2: Argon2<'static> = Argon2::default(); - } - - // generate hash of the master password hash - // the result is a PHC string ($argon2id$19$...). it contains the salt - let hash = ARGON2 - .hash_password_simple(&mpw.into_inner(), &salt) - .map_err(|_| { - Error::InvalidMasterPasswordHash(InvalidMasterPasswordHash { - description: "failed to generate hash".to_string(), - hint: None, - }) - })? - .to_string(); - - let fingerprint = cert.fingerprint().to_hex(); - let pub_cert = cert - .clone() - .strip_secret_key_material() - .export_to_vec() - .unwrap(); - let cert_raw = cert.as_tsk().export_to_vec().unwrap(); - - let result = sqlx::query!( - r#" - WITH "user" AS ( - INSERT INTO users (username, hash, enc_cert) - VALUES ($1, $2, $3) - RETURNING user_id AS id - ) - INSERT INTO pub_certs (user_id, cert_fingerprint, pub_cert) - VALUES ( - (SELECT id FROM "user"), $4, $5 - ) RETURNING (SELECT id FROM "user") AS "user_id!: uuid::Uuid" - "#, - name, - hash, - cert_raw, - fingerprint, - pub_cert, - ) - .fetch_one(db) - .await; - - match result { - Ok(record) => Ok(Self { id: record.user_id }), - Err(e) => Err(match e { - sqlx::Error::Database(e) => { - // won't panic because we use postgres - let e = e.downcast::(); - // postgresql error codes: https://www.postgresql.org/docs/current/errcodes-appendix.html - // 23505 = unique violation -> already exists - match (e.code(), e.constraint()) { - ("23505", Some("users_username_key")) => { - Error::UsernameUnavailable(UsernameUnavailable { - description: "another user has the same name".to_string(), - hint: Some("choose a different name".to_string()), - name, - }) - } - ("23505", Some("pub_certs_cert_fingerprint_key")) => { - Error::CertificateTaken(CertificateTaken { - certificate: Box::new(cert.into()), - description: "another user's certificate has the same fingerprint" - .to_string(), - hint: Some( - concat!( - "it is VERY unlikely that this is an accident. ", - "it is way more likely that your client reuses ", - "certificates." - ) - .to_string(), - ), - }) - } - ("23514", _) => Error::InvalidUsername(InvalidUsername { - description: "username violates policy".to_string(), - hint: Some("only a-z, 0-9, _ are allowed".to_string()), - name: name.to_lowercase(), - }), - _ => Error::Unexpected(e.into()), - } - } - e => Error::Unexpected(e.into()), - }), - } - } - - pub async fn authenticate( - self, - mpw: &Bytes, - db: &Pool, - ) -> Result { - lazy_static! { - static ref ARGON2: Argon2<'static> = Argon2::default(); - } - let hash = sqlx::query!( - r#" - SELECT hash FROM users WHERE user_id = $1 - "#, - self.id - ) - .fetch_one(db) - .await - .expect("user not in database") // safe cuz only Users which are known to be in the database are created - .hash; - - let hash = PasswordHash::new(&hash).expect("invalid password hash"); - ARGON2.verify_password(mpw, &hash).map_err(|e| { - Error::InvalidMasterPasswordHash(InvalidMasterPasswordHash { - description: "invalid master password hash".to_string(), - hint: Some(e.to_string()), - }) - })?; - - Ok(self.into()) - } - - pub async fn set_token_expiry( - &self, - time: Option>, - db: &Pool, - ) -> DateTime { - let time = time.unwrap_or_else(Utc::now); - sqlx::query!( - r#" - UPDATE users SET token_expiry = $1 WHERE user_id = $2 - "#, - time, - self.id - ) - .execute(db) - .await - .expect("cannot update token_expiry in database"); - time - } -} - -impl From for User { - fn from(id: Uuid) -> Self { - Self { id } - } -} - -impl User { - // does database io so it really must be async, but TryFrom can't async, so no trait impl - /// Like the [``std::convert::TryFrom``] but with an async fn. - /// This function looks up if there's a user with the ``name`` in the database and gets the uuid. - /// Errors if there's no such user - pub async fn try_from(name: &str, db: &Pool) -> Result { - Ok(sqlx::query!( - r#" - SELECT user_id FROM users WHERE username = $1"#, - name - ) - .fetch_one(db) - .await - .map_err(|_| { - Error::NoSuchUser(NoSuchUser { - description: "cannot find a user with that name".to_string(), - hint: None, - name: name.to_string(), - }) - })? - .user_id - .into()) - } -} - -#[Object] -impl User { - pub async fn id(&self) -> async_graphql::ID { - self.id.into() - } - - pub async fn name(&self, ctx: &Context<'_>) -> String { - ctx.data_unchecked::>() - .load_one(self.id) - .await - .unwrap() - .unwrap() - } - - pub async fn certificate(&self, ctx: &Context<'_>) -> Certificate { - ctx.data_unchecked::>() - .load_one(self.id) - .await - .unwrap() - .unwrap() - } -} diff --git a/src/auth/authentication.rs b/src/auth/authentication.rs deleted file mode 100644 index 4d0e9d6..0000000 --- a/src/auth/authentication.rs +++ /dev/null @@ -1,173 +0,0 @@ -//! Auth*entication* -//! -//! This part deals with authentication. It determines an user's identity -use crate::{ - actors::{AuthenticatedUser, User}, - certificate::Certificate, - fallible::*, - graphql::Bytes, - loader::TokenExpiryLoader, - result_type, tri, -}; - -use super::{ - signup::{ChallengeProof, SignupResult, SignupUserInput}, - token::{RefreshTokenResult, TokenPair}, -}; -use async_graphql::{dataloader::DataLoader, Context, Object, Result}; -use jsonwebtoken::{DecodingKey, EncodingKey}; -use rand::Rng; -use redis::{Client, Commands}; -use sqlx::{PgPool, Pool, Postgres}; - -#[derive(Default)] -pub struct AuthenticationQuery; - -#[derive(Default)] -pub struct AuthenticationMutation; - -result_type!(AuthenticationResult, AuthenticatedUser); - -#[Object] -impl AuthenticationMutation { - /// Signup - /// - /// Create a new account with the values in ``user`` and - /// uses ``proof`` to verify that the user has control over - /// the primary key supplied in ``user``. - async fn signup( - &self, - ctx: &Context<'_>, - user: SignupUserInput, - proof: ChallengeProof, - ) -> SignupResult { - // get the redis pool - let pool = ctx.data_unchecked::>(); - // get a connection from the pool - let mut con = pool.get().unwrap(); - - // 32 bytes in hex = 64 chars - if proof.challenge.len() != 32 { - return Error::InvalidChallenge(InvalidChallenge { - challenge: proof.challenge, - description: "challenge length is invalid".to_string(), - hint: Some( - "a challenge is a 32 byte array" - .to_string(), - ), - }) - .into(); - } - // workaround because ``GETDEL`` is not supported (yet) - // if the key (the challenge) is in the redis db, - // it will return that 1 key got deleted - let count: u8 = con.del(proof.challenge.to_vec()).unwrap(); // this is blocking and therefore bad - if count != 1 { - return Error::InvalidChallenge(InvalidChallenge { - challenge: proof.challenge, - description: "the supplied challenge is not in the active challenge pool" - .to_string(), - hint: Some("a challenge is only valid for two minutes".to_string()), - }) - .into(); - } - - // check if we can parse the certificate and it complies with our policy - let cert = tri!(Certificate::check(&user.certificate.into_inner())); - - // early return if the certificate has no secret parts - if !cert.is_tsk() { - return Error::from(InvalidCertificate::new( - "certificate has no secret parts".to_string(), - )) - .into(); - } - - // verify the challenge - tri!(proof.verify(&cert).await); - - // User into AuthenticatedUser - let user: AuthenticatedUser = - tri!(User::new(user.name, &cert, user.hash, ctx.data_unchecked::()).await) - .into(); - // transform the AuthenticatedUser into SignupResult (result impl from $ok) - user.into() - } - - /// Authenticate - /// - /// If a user wants to access their account, they have to log in. - /// The client supplies the username and master password hash so - /// the server is able to identify the user. - async fn authenticate( - &self, - ctx: &Context<'_>, - username: String, - mpw: Bytes, - ) -> AuthenticationResult { - let db = ctx.data_unchecked::>(); - - tri!( - tri!(User::try_from(&username, db).await) // try to get user from db or early return - .authenticate(&mpw, db) // try to authenticate the user - .await - ) - .into() - } - - /// Refresh token - /// - /// As part of your authentication system we have short lived access tokens. - /// If a access token expires, a long-lived refresh token is used to get - /// a new access token. Because refresh tokens are one time only, when - /// requesting a new access token, you'll also need a new refresh token. - /// We call this a ``TokenPair``. - /// - /// # Security - /// - /// If the server detects that a refresh token is being reused, it will invalid - /// all tokens belonging to the user and the user will effectivly logged out - /// everywhere. This is because it is possible that an attacker got hand on a - /// refresh token and may have stolen a session. However, because the server - /// can't know if the token was first used by the attacker or by the actual - /// user, we must invalid at least that session. - /// - /// # Details - /// - /// The server stores a token kill timestamp. This timestamp tells the server - /// which keys to accept or to reject. If the timestamp of the kill timestamp - /// is bigger than the timestamp the token was issued (``iat`` field in the JWT), - /// the token is rejected.\ - /// The server will also store a list of used refresh tokens. - async fn refresh_token(&self, ctx: &Context<'_>, token: String) -> RefreshTokenResult { - let keys = ( - ctx.data_unchecked::(), - ctx.data_unchecked::(), - ); - let db = ctx.data_unchecked::>(); - let loader = ctx.data_unchecked::>(); - tri!(TokenPair::refresh(token, keys, db, loader).await).into() - } -} - -#[Object] -impl AuthenticationQuery { - /// Request a challenge which is used in the ``signup`` mutation to proof the control - /// over the primary key of a pgp certificate. A challenge is valid for two minutes. - async fn challenge(&self, ctx: &Context<'_>) -> Result { - // generate 32 random bytes. should be a CSPRNG - let challenge: [u8; 32] = rand::thread_rng().gen(); - - // get the redis pool from the context - let pool = ctx.data_unchecked::>(); - // get a connection - // TODO: this is not async. Consider bb8 when we can use tokio 1.0 - // currently blocked by actix-web (will be when actix-web 4 released) - let mut con = pool.get().unwrap(); - // encode the challenge to a hex string - // save it in the redis database for 120 seconds - let _: () = con.set_ex(challenge.to_vec(), true, 120)?; - - Ok(bytes::Bytes::from(challenge.to_vec()).into()) - } -} diff --git a/src/auth/mod.rs b/src/auth/mod.rs deleted file mode 100644 index b5ab2e7..0000000 --- a/src/auth/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -//! Auth*entication* and auth*orization* queries -use async_graphql::MergedObject; -pub mod authentication; -mod session; -pub mod signup; -pub mod token; -pub use session::Session; - -#[derive(MergedObject, Default)] -pub struct AuthQueries(pub authentication::AuthenticationQuery); - -#[derive(MergedObject, Default)] -pub struct AuthMutations(pub authentication::AuthenticationMutation); diff --git a/src/auth/session.rs b/src/auth/session.rs deleted file mode 100644 index 4674feb..0000000 --- a/src/auth/session.rs +++ /dev/null @@ -1,85 +0,0 @@ -use async_graphql::{Object, ID}; -use sqlx::{Pool, Postgres}; -use uuid::Uuid; - -use crate::actors::{Actor, User}; - -use super::token::Claims; - -#[derive(Debug)] -#[non_exhaustive] -pub struct Session { - /// The user this session belongs to - pub user_id: Uuid, - /// the unique identifier of this session - pub session_id: Uuid, - /// a name to easier identify this session - pub session_name: Option, -} - -impl Session { - pub async fn new( - user_id: Uuid, - session_name: Option, - db: &Pool, - ) -> Result { - // insert the session and let the database generate a uuid - let session_id = sqlx::query!( - r#" - INSERT INTO session_info ( - user_id, - session_name - ) VALUES ($1, $2) - RETURNING session_id AS "id!: Uuid" - "#, - user_id, - session_name - ) - .fetch_one(db) - .await? - .id; - - Ok(Self { - session_id, - session_name, - user_id, - }) - } -} - -impl From for Session { - /// Constructs a [``Session``] struct from [``Claims``]. - /// Note that the session_name will always be None, - /// even if there's a name stored in the database - /// in this case to avoid database I/O - fn from(claims: Claims) -> Self { - Self { - session_id: claims.sid, - session_name: None, - user_id: claims.sub, - } - } -} - -#[Object] -/// Session -/// -/// Keeps information about the time frame the client can use a -/// ``TokenPair`` to authenticate -impl Session { - /// the ``Actor`` this session belongs to. - /// This will never be an ``AuthenticatedUser``. - pub async fn actor(&self) -> Actor { - Actor::User(User::from(self.user_id)) - } - - /// the unique identifier of the session - pub async fn id(&self) -> ID { - self.user_id.into() - } - - /// the optional name of the session to easier identify the session - pub async fn name(&self) -> Option { - self.session_name.clone() - } -} diff --git a/src/auth/signup.rs b/src/auth/signup.rs deleted file mode 100644 index 4886421..0000000 --- a/src/auth/signup.rs +++ /dev/null @@ -1,60 +0,0 @@ -//! Signup -//! -//! This module keeps models related to the ``signup`` mutation. - -use crate::fallible::{Error, InvalidChallenge, InvalidSignature}; -use crate::graphql::Bytes; -use crate::result_type; -use async_graphql::InputObject; -use sequoia_openpgp::packet::Signature; -use sequoia_openpgp::parse::Parse; -use sequoia_openpgp::Cert; - -result_type!(SignupResult, crate::actors::AuthenticatedUser); - -#[derive(InputObject)] -pub struct SignupUserInput { - /// The name, the user would like to use. - /// The user needs this name to login and for - /// other users so they can find them. - pub name: String, - /// The ``master password hash`` - pub hash: Bytes, - /// The PGP certificate the user'd like to use with encrypted - /// secret parts.\ - /// Note: the certificate has to be unique to this user. - pub certificate: Bytes, -} - -#[derive(InputObject)] -pub struct ChallengeProof { - /// The challenge, the client obtained from the ``challenge`` query. - /// This will be 32 byte. - pub challenge: Bytes, - /// A signature of the ``challenge`` made with the primary key of the user - pub signature: Bytes, -} - -impl ChallengeProof { - /// verifies that the challenge's signature is made by the ``signer`` - // TODO: prio: add test for this - // TODO: mid-prio: benchmark to see if it's blocking too long - pub async fn verify(&self, signer: &Cert) -> Result<(), Error> { - let mut signature = Signature::from_bytes(&self.signature.as_ref()).map_err(|_| { - Error::InvalidSignature(InvalidSignature { - description: "failed to parse signature".to_string(), - hint: None, - }) - })?; - - signature - .verify_message(signer.primary_key().key(), &self.challenge[..]) - .map_err(|e| { - Error::InvalidChallenge(InvalidChallenge { - challenge: self.challenge.clone(), - description: "cannot verify signature".to_string(), - hint: Some(e.to_string()), - }) - }) - } -} diff --git a/src/auth/token.rs b/src/auth/token.rs deleted file mode 100644 index 05723cd..0000000 --- a/src/auth/token.rs +++ /dev/null @@ -1,187 +0,0 @@ -use super::Session; -use crate::{ - actors::User, - fallible::{Error, ExpiredRefreshToken, InvalidRefreshToken, InvalidSignature}, - loader::TokenExpiryLoader, - result_type, -}; -use async_graphql::{dataloader::DataLoader, SimpleObject}; -use chrono::{DateTime, Duration, Utc}; -use jsonwebtoken::{ - decode, encode, errors::ErrorKind, Algorithm, DecodingKey, EncodingKey, Header, Validation, -}; -use lazy_static::lazy_static; -use serde::{Deserialize, Serialize}; -use sqlx::{Pool, Postgres}; -use uuid::Uuid; - -result_type!(RefreshTokenResult, TokenPair); - -#[derive(Debug, Serialize, Deserialize)] -#[non_exhaustive] -/// Claims -/// -/// Represents the different field in the JWT -pub struct Claims { - /// expires at unix timestamp - pub exp: i64, - /// issued at unix timestamp - pub iat: i64, - /// the user this session belongs to - pub sub: Uuid, - /// not valid before unix timestamp - pub nbf: i64, - /// the id of this token (used for deny_list) - pub jti: Uuid, - /// the session id - pub sid: Uuid, - /// if its a refresh token or not - pub rft: bool, -} - -#[derive(SimpleObject)] -/// TokenPair -/// -/// Contains a access token and the refresh token to request the next ``TokenPair`` -#[non_exhaustive] -pub struct TokenPair { - /// The token that is used for authentication in the [``Authorization`` header][1]. - /// The format is ``Authorization: Bearer ``. - /// - /// [1]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization - access_token: String, - /// The token used as ``token`` in the ``refreshToken`` mutation - refresh_token: String, - - /// the corresponding [``Session``] object - session: Session, -} - -impl TokenPair { - /// Generate a new TokenPair from a [``Session``] - /// - /// # Panics - /// - /// panics if the [``encode``] method returns [``Err``]. Should only be the case, if the key is malformed - // TODO: mid-prio: benchmark to see if this takes too long and blocks - pub async fn new(session: Session, key: &EncodingKey) -> Self { - let now = Utc::now(); - let future = (now + Duration::hours(12)).timestamp(); - let now = now.timestamp(); - - let header = Header::new(Algorithm::EdDSA); - - let claims = Claims { - exp: future, - iat: now, - jti: uuid::Uuid::new_v4(), - sid: session.session_id, - nbf: now, - rft: false, - sub: session.user_id, - }; - - let access_token = encode(&header, &claims, key).expect("cannot encode access token"); - - let claims = Claims { - exp: future, - iat: now, - jti: uuid::Uuid::new_v4(), - sid: session.session_id, - nbf: now, - rft: true, - sub: session.user_id, - }; - - let refresh_token = encode(&header, &claims, key).expect("cannot encode refresh token"); - - Self { - access_token, - refresh_token, - session, - } - } - - pub async fn refresh( - token: String, - keys: (&EncodingKey, &DecodingKey), - db: &Pool, - loader: &DataLoader, - ) -> Result { - lazy_static! { - static ref VALIDATION: Validation = Validation::new(jsonwebtoken::Algorithm::HS256); - } - - let token = decode::(&token, keys.1, &VALIDATION).map_err(|e| match e.kind() { - ErrorKind::InvalidSignature => Error::InvalidSignature(InvalidSignature { - description: "jwt has an invalid signature".to_string(), - hint: None, - }), - ErrorKind::ExpiredSignature => Error::ExpiredRefreshToken(ExpiredRefreshToken { - description: "refresh token is expired".to_string(), - hint: Some( - concat!( - "if you have client-side checks ", - "for expiration to avoid ", - "unnecessary requests, make sure ", - "that your local time is correct" - ) - .to_string(), - ), - }), - _ => Error::InvalidRefreshToken(InvalidRefreshToken { - description: "not a valid jwt token".to_string(), - hint: None, - }), - })?; - - if !token.claims.rft { - return Err(Error::InvalidRefreshToken(InvalidRefreshToken { - description: "not a refresh token".to_string(), - hint: Some("check the ``rft`` claim".to_string()), - })); - } - - let token_expiry: DateTime = loader.load_one(token.claims.sub).await.unwrap().unwrap(); - - if token_expiry.timestamp() > token.claims.iat { - return Err(Error::ExpiredRefreshToken(ExpiredRefreshToken { - description: "user's token expiry is higher than iat".to_string(), - hint: None, - })); - } - - if sqlx::query!( - r#" - SELECT exists(SELECT 1 FROM denied_tokens WHERE token_id = $1) AS "exists!" - "#, - token.claims.jti - ) - .fetch_one(db) - .await - .map_err(|_| Error::Unexpected("database error checking denied tokens".into()))? - .exists - { - User::from(token.claims.sub) - .set_token_expiry(None, db) - .await; - return Err(Error::ExpiredRefreshToken(ExpiredRefreshToken { - description: "refresh token is denied".to_string(), - hint: None, - })); - } - - sqlx::query!( - r#" - INSERT INTO denied_tokens (token_id) - VALUES ($1) - "#, - token.claims.jti, - ) - .execute(db) - .await - .map_err(|_| Error::Unexpected("cannot insert into denied tokens".into()))?; - - Ok(Self::new(token.claims.into(), keys.0).await) - } -} diff --git a/src/certificate/mod.rs b/src/certificate/mod.rs deleted file mode 100644 index 17e6264..0000000 --- a/src/certificate/mod.rs +++ /dev/null @@ -1,146 +0,0 @@ -//! OpenPGP certificates & friends - -use async_graphql::{dataloader::DataLoader, Context, Object}; -use sequoia_openpgp::{parse::Parse, types::KeyFlags, Cert, Fingerprint}; - -mod policy; -pub use policy::*; - -use crate::{ - fallible::{Error, InvalidCertificate}, - graphql::Bytes, - loader::PrivateCertificateBodyLoader, -}; -/// An OpenPGP certificate which MAY include secret key material -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Certificate { - /// the fingerprint of the certificate so it can be found in the database - pub fingerprint: Fingerprint, - /// used to determine if the object should allow the access to secret key - /// material - pub secret: bool, -} - -#[Object] -impl Certificate { - /// Returns the fingerprint of the certificate - async fn fingerprint(&self) -> String { - self.fingerprint.to_hex() - } - - /// Loads the body from the database and returns the OpenPGP certificate - async fn body(&self, ctx: &Context<'_>) -> Bytes { - ctx.data_unchecked::>() - .load_one(self.clone()) - .await - .unwrap() - .unwrap() - } - - /// Returns true if the ``body`` will include encrypted secret key material - async fn has_secret(&self) -> &bool { - &self.secret - } -} - -/// Loads the fingerprint from the given [`Cert`] -impl From<&Cert> for Certificate { - fn from(cert: &Cert) -> Self { - Self { - fingerprint: cert.fingerprint(), - secret: cert.is_tsk(), - } - } -} - -impl Certificate { - /// Checks if the provided [`bytes::Bytes`] are a valid openpgp certificate - /// and if it passes our custom [`CompliantPolicy`] - pub fn check(value: &bytes::Bytes) -> Result { - static POLICY: CompliantPolicy = CompliantPolicy::new(); - let cert = Cert::from_bytes(value).map_err(|_| { - Error::from(InvalidCertificate::new( - "cannot parse certificate".to_string(), - )) - })?; - let v_cert = cert.with_policy(&POLICY, None).map_err(|e| { - Error::from(InvalidCertificate { - description: "certificate violates policy".to_string(), - hint: Some(e.to_string()), - }) - })?; - - let signing = KeyFlags::empty().set_signing(); - let authentication = KeyFlags::empty().set_authentication(); - let encryption = KeyFlags::empty() - .set_transport_encryption() - .set_storage_encryption(); - let certification = KeyFlags::empty().set_certification(); - - // check that there's exactly one key for each operation - - if v_cert.keys().key_flags(signing).count() != 1 { - return Err( - InvalidCertificate::new("no or more than one key for signing".to_string()).into(), - ); - } - - if v_cert.keys().key_flags(authentication).count() != 1 { - return Err(InvalidCertificate::new( - "no or more than one key for authentication".to_string(), - ) - .into()); - } - - // keys with `transport` or `storage` encryption key flag - let mut enc_keys = v_cert.keys().key_flags(encryption); - - if let Some(key) = enc_keys.next() { - if enc_keys.next().is_some() { - return Err(InvalidCertificate { - description: "found more than one encryption key".to_string(), - hint: None, - } - .into()); - } - - // we only accept keys that are both for transport and storage encryption - if !(key.for_transport_encryption() && key.for_storage_encryption()) { - return Err(InvalidCertificate { - description: "key not for both transport and storage encryption".to_string(), - hint: None, - } - .into()); - } - } else { - return Err(InvalidCertificate { - description: "found no key for encryption".to_string(), - hint: None, - } - .into()); - } - - if v_cert.keys().key_flags(certification).count() != 1 { - return Err(InvalidCertificate::new( - "no or more than one key for certification".to_string(), - ) - .into()); - } - - Ok(cert) - } - - pub fn from_public(fingerprint: Fingerprint) -> Self { - Self { - fingerprint, - secret: false, - } - } - - pub fn from_private(fingerprint: Fingerprint) -> Self { - Self { - fingerprint, - secret: true, - } - } -} diff --git a/src/certificate/policy.rs b/src/certificate/policy.rs deleted file mode 100644 index 6bd79d3..0000000 --- a/src/certificate/policy.rs +++ /dev/null @@ -1,97 +0,0 @@ -use sequoia_openpgp::{ - crypto::mpi::PublicKey, - policy::{Policy, StandardPolicy}, - types::Curve, - Packet, -}; - -#[derive(Debug)] -pub struct CompliantPolicy<'a>(StandardPolicy<'a>); - -impl CompliantPolicy<'static> { - pub const fn new() -> Self { - Self(StandardPolicy::new()) - } -} - -macro_rules! disallow_unknown_and_private_variants { - ($e:path, $a:ident $(,)?) => { - use $e as base; - match $a { - base::Private(_) => anyhow::bail!("private variants are not allowed."), - base::Unknown(_) => anyhow::bail!("unknown variants are not allowed."), - _ => (), - }; - }; -} - -impl<'a> Policy for CompliantPolicy<'a> { - fn key( - &self, - ka: &sequoia_openpgp::cert::prelude::ValidErasedKeyAmalgamation< - sequoia_openpgp::packet::key::PublicParts, - >, - ) -> sequoia_openpgp::Result<()> { - if ka.key_expiration_time().is_some() { - anyhow::bail!("only keys without an expiration time are supported."); - } - match ka.has_unencrypted_secret() { - true => anyhow::bail!("found unencypted secret."), - false => (), - } - - match ka.mpis() { - PublicKey::EdDSA { curve: _, q: _ } => { - // EdDSA is only used with curve 25519 - self.0.key(ka) - } - PublicKey::ECDH { - curve, - hash: _, - q: _, - sym: _, - } => match curve { - Curve::Cv25519 => self.0.key(ka), // fallback to the standard policy to check other parts of the key - _ => anyhow::bail!("only ECDH with curve 25519 is supported."), - }, - _ => anyhow::bail!("only curve 25519 ciphersuites are supported."), - } - } - fn signature( - &self, - sig: &sequoia_openpgp::packet::Signature, - sec: sequoia_openpgp::policy::HashAlgoSecurity, - ) -> sequoia_openpgp::Result<()> { - if let sequoia_openpgp::types::SignatureType::Unknown(_) = sig.typ() { - anyhow::bail!("unknown variants are not allowed."); - } - self.0.signature(sig, sec) - } - - fn symmetric_algorithm( - &self, - algo: sequoia_openpgp::types::SymmetricAlgorithm, - ) -> sequoia_openpgp::Result<()> { - disallow_unknown_and_private_variants!(sequoia_openpgp::types::SymmetricAlgorithm, algo); - self.0.symmetric_algorithm(algo) - } - - fn aead_algorithm( - &self, - algo: sequoia_openpgp::types::AEADAlgorithm, - ) -> sequoia_openpgp::Result<()> { - disallow_unknown_and_private_variants!(sequoia_openpgp::types::AEADAlgorithm, algo); - self.0.aead_algorithm(algo) - } - - fn packet(&self, packet: &sequoia_openpgp::Packet) -> sequoia_openpgp::Result<()> { - match packet { - Packet::Trust(_) => { - anyhow::bail!("trust packets are implementation-defined and are not allowed") - } - Packet::Unknown(_) => anyhow::bail!("unknown packets are not allowed"), - _ => (), - } - self.0.packet(packet) - } -} diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..7cb09b2 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,102 @@ +use std::{fs::write, path::PathBuf}; + +use figment::{ + providers::{Env, Format, Toml}, + Figment, +}; +use openidconnect::{ + core::{CoreClient, CoreProviderMetadata}, + reqwest::async_http_client, + ClientId, ClientSecret, IssuerUrl, RedirectUrl, +}; +use serde::Deserialize; +use url::Url; + +#[derive(Deserialize, Clone)] +pub struct Config { + /// Configuration for openid connect + pub openid_connect: OidcConfig, + /// the address the server should bind to + pub listen: String, + /// The uri to the postgres database + pub postgres_uri: String, + /// The uri to the redis cache + pub redis_uri: String, +} + +#[derive(Deserialize, Clone)] +pub struct OidcConfig { + /// The id of the client used for operations like a [Authorization Request][1] + /// + /// [1]: https://openid.net/specs/openid-connect-core-1_0.html#AuthRequest + pub client_id: String, + /// The secret for signing operations as per [section 10.1][1] + /// + /// [1]: https://openid.net/specs/openid-connect-core-1_0.html#Signing + pub client_secret: String, + /// Used for [open id connect discovery][1] + /// + /// [1]: https://openid.net/specs/openid-connect-discovery-1_0.html + pub discovery_url: Url, + /// The url the User-Agent should be redirected to after an authentication + pub redirect_url: Url, +} + +impl OidcConfig { + /// Performs a request to the openid connect discovery endpoint and returns + /// a [`CoreClient`] + pub async fn load_client(self) -> anyhow::Result { + let issuer_url = IssuerUrl::from_url(self.discovery_url); + + let redirect_url = RedirectUrl::from_url(self.redirect_url); + + // perform request to the openid connect endpoint + let meta = CoreProviderMetadata::discover_async(issuer_url, async_http_client).await?; + + let client_id = ClientId::new(self.client_id); + let client_secret = ClientSecret::new(self.client_secret); + let client = CoreClient::from_provider_metadata(meta, client_id, Some(client_secret)) + .set_redirect_uri(redirect_url); + Ok(client) + } +} +impl Config { + /// Load the configuration + /// + /// The default path is a file called `config.toml` in $PWD/config.toml + pub fn load() -> anyhow::Result { + // either read the path for the config from the env _CONFIG + // or use the default path relativ to the executable + let path: PathBuf = match std::env::var(concat!(env!("CARGO_CRATE_NAME"), "_CONFIG")) { + Ok(path) => path.into(), + Err(e) => { + debug!("Cannot read env var for config path: {}", e); + std::env::current_dir()?.join("config.toml") + } + }; + + // write the sample config to the file only if it does not exist + if !path.exists() { + info!("Creating config with default options at {}", path.display()); + write(&path, include_str!("../other/config.sample"))?; + } + + info!("Reading config from {}", path.display()); + Ok(Figment::new() + // first read the config file + .merge(Toml::file(path)) + // and then let the env overwrite options + .merge(Env::prefixed(env!("CARGO_CRATE_NAME"))) + .extract()?) + } +} + +#[test] +fn test_parse_default_config() { + use figment::providers::{Data, Toml}; + // ensure that the default config is valid and can be parsed + let _: Config = Figment::new() + .merge(Data::::string(include_str!("../other/config.sample"))) + .extract() + .expect("default config is malformed"); +} diff --git a/src/config/mod.rs b/src/config/mod.rs deleted file mode 100644 index f0d4026..0000000 --- a/src/config/mod.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::{fs::File, io::Write, net::SocketAddr, str::FromStr}; - -use directories::ProjectDirs; -use figment::{ - providers::{Env, Format, Toml}, - Figment, -}; - -use jsonwebtoken::{DecodingKey, EncodingKey}; -use log::info; -use sequoia_openpgp::Cert; -use serde::{Deserialize, Deserializer}; - -#[derive(Deserialize, Clone)] -pub struct Config { - pub db_uri: String, - pub redis_uri: String, - pub listen: SocketAddr, - #[serde(deserialize_with = "deserialize_jwt_secret")] - pub jwt_secret: (EncodingKey, DecodingKey), - #[serde(deserialize_with = "deserialize_cert")] - pub server_cert: Cert, -} - -impl Config { - pub fn new() -> Self { - let project_dir = ProjectDirs::from("rs", "minkan", env!("CARGO_CRATE_NAME")) - .expect("cannot build project dir path"); - - let config_path = project_dir.config_dir(); - - // create config dir if not exist - if !config_path.exists() { - info!("creating config file at {}", config_path.display()); - let mut file = File::create(config_path).expect("cannot create file"); // blocking but we cant use tokio::fs because actix-web 4 is not released - file.write_all(include_bytes!("../../other/config.sample")) // include sample config - .expect("cannot write to config file") - } - - info!("parsing config file at {}", config_path.display()); - let config: Self = Figment::new() - .merge(Toml::file(config_path)) - .merge(Env::prefixed(concat!(env!("CARGO_CRATE_NAME"), "_"))) - .extract() - .unwrap(); - config - } -} - -// i really wanna use the ec secret from the server's certificate tho. but imo does not make no sense unless the key is signed -fn deserialize_jwt_secret<'de, D>(secret: D) -> Result<(EncodingKey, DecodingKey), D::Error> -where - D: Deserializer<'de>, -{ - let secret = String::deserialize(secret)?; - let encoding_key = EncodingKey::from_secret(secret.as_bytes()); - let decoding_key: DecodingKey = DecodingKey::from_secret(secret.as_bytes()); - Ok((encoding_key, decoding_key)) -} - -fn deserialize_cert<'de, D>(cert: D) -> Result -where - D: Deserializer<'de>, -{ - let armor = String::deserialize(cert)?; // deserialize the armor string - let cert = Cert::from_str(&armor).map_err(::custom)?; - Ok(cert) -} diff --git a/src/fallible/errors.rs b/src/fallible/errors.rs deleted file mode 100644 index fb3066a..0000000 --- a/src/fallible/errors.rs +++ /dev/null @@ -1,244 +0,0 @@ -use crate::actors::Actor; -use crate::certificate::Certificate; -use crate::graphql::Bytes; -use crate::error_type; -use chrono::{DateTime, Utc}; - -use async_graphql::Interface; - -#[derive(Interface, Debug)] -#[graphql( - field(name = "description", type = "String", desc="\ -A short description what went wrong\\ -Note: This description is only for the developer. -An application should match ``__typename`` and display -a message based on that." -), - field(name = "hint", type = "&Option", desc="\ -A hint for the developer what they could do to prevent this error" -) // only &Option slice works? -)] -pub enum Error { - UsernameUnavailable(UsernameUnavailable), - InvalidUsername(InvalidUsername), - NoSuchUser(NoSuchUser), - CertificateTaken(CertificateTaken), - InvalidCertificate(InvalidCertificate), - InvalidCertificateFingerprint(InvalidCertificateFingerprint), - UnknownCertificate(UnknownCertificate), - InvalidSignature(InvalidSignature), - InvalidMasterPasswordHash(InvalidMasterPasswordHash), - InvalidChallenge(InvalidChallenge), - ExpiredRefreshToken(ExpiredRefreshToken), - InvalidRefreshToken(InvalidRefreshToken), - UnexpectedSigner(UnexpectedSigner), - Unexpected(Unexpected), -} - -error_type! { - /// UsernameUnavailable - /// - /// The supplied username is unavailable. - /// This error usually occurs when another user has the same - /// name. However, it could also occur because the name violates - /// the name policy. - struct UsernameUnavailable { - /// The name that was given in the input object - name: String, - } -} - -error_type! { - /// InvalidUsername - /// - /// The supplied username is invalid. - /// This error occurs mostly if the username contains - /// invalid characters or otherwise does not meet the - /// criteria. - /// - /// # Criteria - /// - /// To be valid, a username must be between 3-16 chars long, - /// and only consist of letters, numbers and underscores. - /// Regex: ``^[a-z0-9_]{3,16}$`` - struct InvalidUsername { - /// The name that was given in the input object - name: String, - } -} - -error_type! { - /// NoSuchUser - /// - /// The server didn't find a user with that ``name`` - struct NoSuchUser { - /// The name that was searched for - name: String, - } -} -error_type! { - /// CertificateTaken - /// - /// This error means that another user's PGP certificate has the same fingerprint. - /// The chance that this will happen by accident is incredible low. It is way more - /// likely that the client has a bug and sent the same certificate twice. - struct CertificateTaken { - /// The certificate that was sent in the input - certificate: Box, - } -} - -error_type!( - /// InvalidCertificate - /// - /// The server failed to parse the certificate. - /// The client should check how it encodes the certificate. - InvalidCertificate -); - -error_type!( - /// InvalidCertificateFingerprint - /// - /// The fingerprint that was sent is invalid. That means, it is not a valid - /// hex string. - InvalidCertificateFingerprint -); - -error_type! { - /// UnknownCertificate - /// - /// The server does not know a certificate with the ``fingerprint``. - struct UnknownCertificate { - /// The given fingerprint - fingerprint: String, - } -} - -error_type!( - /// InvalidSignature - /// - /// The server either failed to parse the signature or parsed the signature - /// successful but failed to verify the signature. In the latter case, the - /// server would probably respond with ``UnexpectedSigner`` instead. - InvalidSignature -); - -error_type! { - /// UnknownUser - /// - /// The server can't find a ``User`` with supplied name - struct UnknownUser { - /// The ``name`` field contains the name given in the input object - name: String, - } -} - -error_type!( - /// InvalidMasterPasswordHash - /// - /// The hash sent is not valid. - /// - /// # Details - /// - /// The client uses the username and the cleartext password to generate a hash called - /// the ``master key``. It generates that hash by taking the username as a salt and - /// the password as the payload and running it through a PBKDF2-SHA256 function - /// with ``100,000`` iterations. The output is called ``master key``.\ - /// The master key is then sent through another PBKDF2-SHA256 function with ``1`` - /// interation. This time, the salt is the cleartext password and the payload - /// is the ``master key``. The output is called ``master password hash``.\ - /// The ``master password hash`` is sent to the server. The server stored a argon2id - /// hash of that ``master password hash`` and so hashes the ``master password hash`` - /// again and compares these two hashes.\ - /// If you want to read further, please refer to the [bitwarden site][1] which you can - /// use as a guide. - /// - /// [1]: https://bitwarden.com/help/article/bitwarden-security-white-paper/#overview-of-the-master-password-hashing-key-derivation-and-encryption-process - InvalidMasterPasswordHash -); -error_type! { - /// UserSuspended - /// - /// The user is not able to perform any actions because they are suspended.\ - /// A user might get suspended because they violated the rules. - struct UserSuspended { - /// The optional date and time since the user is suspended in utc - since: Option>, - /// The optional reason for the suspension - reason: Option, - - } -} -error_type! { - /// InvalidChallenge - /// - /// The challenge provided by the client is invalid.\ - /// Note: if the challenge's signature is also invalid, - /// another ``InvalidSignature`` error could be attached. - struct InvalidChallenge { - /// The challenge provided in the input object - challenge: Bytes, - } -} -error_type!( - /// ExpiredRefreshToken - /// - /// The [``exp``][1] field in the [``JWT``][2] indicates that the token is expired. - /// The server won't allow this token to request a new ``TokenPair``.\ - /// The client could check the [``exp``][1] field by itself and see - /// that the token is expired. This would prevent an unneccessary request.\ - /// Note: The client has to authenticate again with the ``master password hash``. - /// This requires the password from the end user. - /// - /// [1]: https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4 - /// [2]: https://jwt.io/ - ExpiredRefreshToken -); -error_type!( - /// InvalidRefreshToken - /// - /// The token is invalid. The server might provide additional information - /// in the ``description`` field. - /// - /// # Details - /// - /// If the server detects that a refresh token is being reused, the user's - /// token kill timestamp[1] will be set to the current time. This invalids - /// all access and refresh tokens.\ - /// This approach is based on ``automatic reuse detection``. You can read more - /// about why it is deployed under - /// [``Refresh Token Automatic Reuse Detection`` at Auth0][1]. - /// - /// [1]: https://auth0.com/blog/refresh-tokens-what-are-they-and-when-to-use-them/#Refresh-Token-Automatic-Reuse-Detection - InvalidRefreshToken -); -error_type! { - /// UnexpectedSigner - /// - /// The server could verify signature but detected that the signature - /// is not made by the expected signer. - struct UnexpectedSigner { - /// If the server can figure out the expected signer, - /// this field will be set - expected: Option, - /// If the server can figure out the actually signer, - /// this field will contain the signer - got: Option, - } -} - -error_type! { - /// Unexpected - /// - /// An unexpected error. Probably something internal like a offline database - Unexpected -} - -impl From for Unexpected { - fn from(error: T) -> Self { - Self { - description: error.to_string(), - hint: None, - } - } -} diff --git a/src/fallible/mod.rs b/src/fallible/mod.rs deleted file mode 100644 index 0907923..0000000 --- a/src/fallible/mod.rs +++ /dev/null @@ -1,221 +0,0 @@ -//! This module keeps the different result types. These are needed, because GraphQL does not have generics, -//! so we cannot build something like -//! -//! ``` -//! struct Result { -//! ok: T, -//! err: E, -//! } -//! ``` -//! -//! Neither can we use enums with inner generics like [``std::result::Result``] does. -//! -//! We do it this way (instead of using [``async_graphql::Result``]) because these errors are not typed. -//! This errors are for operations that *can* fail because of things, the client does not know. For -//! example, then a client tries to register, it can't know if a username is available or not. - -/// result_type macro -/// -/// This macro generates a struct which can be used as a result to have typed errors in GraphQL. -/// It automatically derives [``async_graphql::SimpleObject``]. It will create a struct with two -/// fields: a field ``ok`` with an ``Option<$ok>`` on it and a field ``err`` with a ``Option<$err>``. -/// The intention is that on success, the ``ok`` field is Some($ok) and ``err`` is ``None``. -/// On failure, the ``ok`` field is None and the ``err`` field contains a ``Some($err)`` with the error. -/// -/// # Example -/// -/// ```rust -/// // This -/// result_type(SignupResult, String, String); // error shouldn't be a String in actual code -/// // will expand to -/// /* -/// pub struct SignupResult { -/// ok: String, -/// err: String, -/// } -/// */ -/// -/// // -- Default impl, From<$err> and new($ok) are generated too -- -/// -/// let some_result = SignupResult::new("That's okay!".to_string()); -/// assert!(some_result.ok.is_some()); -/// let value = some_result.ok.unwrap(); -/// assert_eq!(value, "That's okay!".to_string()); -/// ``` -mod errors; - -pub use errors::*; - -#[macro_export] -macro_rules! result_type { - ( - $name:ident, - $ok:ty, - $err:ty $(,)? - ) => { - #[derive(async_graphql::SimpleObject)] - /// Result type - /// Every result type is built the same way - /// it has a field ``ok`` which has some value on success - /// and the ``err`` field which is the ``Error`` interface.\ - /// The rule is: if there's an error, ``ok`` is null, ``err`` is some, - /// if there is no error and the operation succeeds, ``err`` is none and - /// ``ok`` is some. - /// - /// # Details - /// - /// We use this way instead of the ``errors`` field defined by the graphql - /// schema, because these errors are not typed. With our way, you know - /// exactly which errors could occur and they all implement the ``Error`` - /// interface so you can always be future proof. - /// - /// We'd really like to have only a single ``Result`` type, but for that - /// we would need a concept like generics. GraphQL, however, does not - /// have generics (yet). A union of all possible types on ``ok`` would - /// be pretty ugly too.\ - /// Usually, each query/mutation returning a xResult should specify which - /// errors are common / expected to occur. - pub struct $name { - pub ok: Option<$ok>, - pub err: Option<$err>, - } - - impl Default for $name { - fn default() -> Self { - Self { - ok: Option::default(), - err: Option::default(), - } - } - } - - #[allow(dead_code)] - impl $name { - pub fn new(value: $ok) -> Self { - Self { - ok: Some(value), - err: None, - } - } - } - - impl From<$ok> for $name { - fn from(ok: $ok) -> Self { - Self { - ok: Some(ok), - err: None, - } - } - } - - impl From<$err> for $name { - fn from(err: $err) -> Self { - Self { - ok: None, - err: Some(err), - } - } - } - - impl From> for $name { - fn from(val: Result<$ok, $err>) -> Self { - Self::from($crate::tri!(val)) - } - } - }; - ( - $name:ident, - $ok:ty $(,)? - ) => { - $crate::result_type!($name, $ok, $crate::fallible::Error); - }; -} - -/// error type macro -/// -/// This macro is used to avoid repeating error types. -/// -/// **Note**: Be sure to register this type in the [``crate::fallible::Error``] interface too. -/// -/// # Example -/// -/// ```rust -/// error_type { -/// struct SomeError { -/// extra_field: String -/// } -/// } -/// ``` -/// -/// This has only the default fields -/// ```rust -/// error_type { -/// struct OtherError; -/// } -/// ``` -#[macro_export] -macro_rules! error_type { - ( - $(#[$attr:meta])* - struct $name:ident { - $( - $(#[$inner_attr:meta])* - $field:ident: $field_type:ty, - )* - } $(,)? - ) => { - $(#[$attr])* - #[derive(async_graphql::SimpleObject, Debug)] - pub struct $name { - - pub description: String, - pub hint: Option, - $( - $(#[$inner_attr])* - pub $field: $field_type, - )* - } - - impl $name { - #[allow(unused)] - pub fn new (description: String, $($field: $field_type),*) -> Self { - Self { - description, - hint: None, - $($field),* - } - } - } - }; - ( - $(#[$attr:meta])* - struct $name:ident$(;)? - ) => { - $crate::error_type!($(#[$attr])* struct $name {}); - }; - - ( - $(#[$attr:meta])* - $name:ident - ) => { - crate::error_type!( - $(#[$attr])* - struct $name - ); - }; -} - -/// try_return -/// -/// basically a copy of the ``try!`` macro, because we can't use ``?`` for early return -#[macro_export] -macro_rules! tri { - ( - $expr:expr $(,)? - ) => { - match $expr { - Ok(val) => val, - Err(err) => return err.into(), - } - }; -} diff --git a/src/graphql/bytes.rs b/src/graphql/bytes.rs deleted file mode 100644 index 7c5d911..0000000 --- a/src/graphql/bytes.rs +++ /dev/null @@ -1,36 +0,0 @@ -use async_graphql::scalar; -use serde::{Deserialize, Serialize}; -use std::ops::{Deref, DerefMut}; - -#[derive(Serialize, Deserialize, Clone, Debug)] -#[repr(transparent)] -/// Bytes -/// -/// A wrapper struct around [``bytes::Bytes``] -pub struct Bytes(bytes::Bytes); - -impl Deref for Bytes { - type Target = bytes::Bytes; - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DerefMut for Bytes { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } -} - -impl Bytes { - pub fn into_inner(self) -> bytes::Bytes { - self.0 - } -} - -impl From for Bytes { - fn from(value: bytes::Bytes) -> Self { - Self(value) - } -} -scalar!(Bytes, "Bytes", "A custom scalar that encodes bytes"); diff --git a/src/graphql/mod.rs b/src/graphql/mod.rs deleted file mode 100644 index a7902fc..0000000 --- a/src/graphql/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -use async_graphql::{EmptySubscription, MergedObject, Schema}; - -mod bytes; -mod node; - -pub use self::bytes::Bytes; -pub use node::Node; - -use crate::{ - auth::{AuthMutations, AuthQueries}, - trust::{TrustMutations, TrustQueries}, -}; - -pub type GraphQLSchema = Schema; - -#[derive(MergedObject, Default)] -pub struct Queries(AuthQueries, TrustQueries); - -#[derive(MergedObject, Default)] -pub struct Mutations(AuthMutations, TrustMutations); diff --git a/src/graphql/node.rs b/src/graphql/node.rs deleted file mode 100644 index 5a28a81..0000000 --- a/src/graphql/node.rs +++ /dev/null @@ -1,16 +0,0 @@ -use async_graphql::{Interface, ID}; - -use crate::{actors::User, auth::Session}; - -#[derive(Interface)] -#[graphql(field(name = "id", type = "ID"))] -/// Node -/// -/// A node is an interface that all objects with an ID implement. -/// It is used for [global object identification][1]. -/// -/// [1]: https://graphql.org/learn/global-object-identification/ -pub enum Node { - User(User), - Session(Session), -} diff --git a/src/guards/authentication_guard.rs b/src/guards/authentication_guard.rs deleted file mode 100644 index 89ebfca..0000000 --- a/src/guards/authentication_guard.rs +++ /dev/null @@ -1,79 +0,0 @@ -use actix_web::{http::header::Header, HttpRequest}; -use actix_web_httpauth::headers::authorization::{Authorization, Bearer}; -use async_graphql::{guard::Guard, Context, Request}; -use async_trait::async_trait; -use jsonwebtoken::{decode, Algorithm, DecodingKey, Validation}; -use lazy_static::lazy_static; -use moka::future::Cache; -use sqlx::{Pool, Postgres}; -use uuid::Uuid; - -use crate::auth::token::Claims; - -/// AuthenticationGuard -/// -/// makes sure that there is a valid JWT in the request. -/// [``crate::auth::token::Claims``] can be safely -/// recieved via [``Context``] -pub struct AuthenticationGuard; - -#[async_trait] -impl Guard for AuthenticationGuard { - async fn check(&self, ctx: &Context<'_>) -> async_graphql::Result<()> { - match ctx.data::() { - Ok(_) => Ok(()), - Err(_) => Err("not authenticated".into()), - } - } -} - -impl AuthenticationGuard { - /// Tries to parse and validate a JWT - /// Looks the token expiry up in the cache or loads it from the database - pub async fn parse( - req: Request, - http_request: &HttpRequest, - key: &DecodingKey, - tec: &Cache, - db: &Pool, - ) -> Request { - let token = Authorization::::parse(http_request); - if let Ok(token) = token { - lazy_static! { - static ref VALIDATION: Validation = Validation::new(Algorithm::HS256); - } - if let Ok(token) = decode::(token.as_ref().token(), key, &VALIDATION) { - // early return because refresh tokens are not authentication tokens - if token.claims.rft { - return req; - } - - let db = db.clone(); // #12 - let user_id = token.claims.sub; // needed because of #12 and on success, we move ownership into the request's context - let token_expiry = tec - .get_or_insert_with(token.claims.sub, async move { - sqlx::query!( - r#" - SELECT token_expiry FROM users WHERE user_id = $1 - "#, - user_id, - ) - .fetch_one(&db) - .await - .unwrap() - .token_expiry - .timestamp() - }) - .await; - - // if the token was issued before the user's token expiry (kill switch) - // the token expiry is checked while decoding - if token.claims.iat > token_expiry { - return req.data(token.claims); - } - } - } - - req - } -} diff --git a/src/guards/mod.rs b/src/guards/mod.rs deleted file mode 100644 index 508ad5a..0000000 --- a/src/guards/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -mod authentication_guard; - -pub use authentication_guard::*; diff --git a/src/loader/cert_loader.rs b/src/loader/cert_loader.rs deleted file mode 100644 index 9996fec..0000000 --- a/src/loader/cert_loader.rs +++ /dev/null @@ -1,139 +0,0 @@ -use std::{collections::HashMap, sync::Arc}; - -use crate::{basic_loader, certificate::Certificate, graphql::Bytes, loader_struct}; -use async_graphql::dataloader::Loader; -use async_trait::async_trait; -use futures::TryStreamExt; -use sequoia_openpgp::Fingerprint; -use uuid::Uuid; - -loader_struct!(PublicCertificateLoader); - -#[async_trait] -impl Loader for PublicCertificateLoader { - type Value = Certificate; - type Error = Arc; - async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { - Ok(sqlx::query!( - r#" - SELECT user_id, fingerprint FROM certificates WHERE user_id = ANY($1) - "#, - keys, - ) - .fetch(&self.pool) - .map_ok(|record| { - ( - record.user_id, - Certificate::from_public( - Fingerprint::from_hex(&record.fingerprint) - .expect("invalid certificate fingerprint in database"), - ), - ) - }) - .try_collect() - .await?) - } -} - -loader_struct!(PrivateCertificateLoader); - -#[async_trait] -impl Loader for PrivateCertificateLoader { - type Value = Certificate; - type Error = Arc; - async fn load(&self, keys: &[Uuid]) -> Result, Self::Error> { - Ok(sqlx::query!( - r#" - SELECT user_id, fingerprint FROM certificates WHERE user_id = ANY($1) - "#, - keys, - ) - .fetch(&self.pool) - .map_ok(|record| { - ( - record.user_id, - Certificate::from_private( - Fingerprint::from_hex(&record.fingerprint) - .expect("invalid certificate fingerprint in database"), - ), - ) - }) - .try_collect() - .await?) - } -} - -basic_loader!( - UserIDLoaderByFingerprint, - String, - uuid::Uuid, - "SELECT fingerprint AS ka, user_id AS val FROM certificates WHERE fingerprint = ANY($1)" -); - -loader_struct!(PrivateCertificateBodyLoader); - -#[async_trait] -impl Loader for PrivateCertificateBodyLoader { - type Value = Bytes; - type Error = Arc; - async fn load( - &self, - keys: &[Certificate], - ) -> Result, Self::Error> { - let fingerprints: Vec<_> = keys.iter().map(|c| c.fingerprint.to_hex()).collect(); - Ok(sqlx::query!( - r#" - SELECT body, fingerprint FROM certificates - WHERE fingerprint = ANY($1) - "#, - &fingerprints - ) - .fetch(&self.pool) - .map_ok(|record| { - ( - Certificate { - fingerprint: Fingerprint::from_hex(&record.fingerprint) - .expect("invalid certificate fingerprint in database"), - secret: true, - }, - Bytes::from(bytes::Bytes::from(record.body)), - ) - }) - .try_collect() - .await?) - } -} - -loader_struct!(PublicCertificateBodyLoader); - -#[async_trait] -impl Loader for PublicCertificateBodyLoader { - type Value = Bytes; - type Error = Arc; - async fn load( - &self, - keys: &[Certificate], - ) -> Result, Self::Error> { - let fingerprints: Vec<_> = keys.iter().map(|c| c.fingerprint.to_hex()).collect(); - Ok(sqlx::query!( - r#" - SELECT body, fingerprint FROM certificates - WHERE fingerprint = ANY($1) - "#, - &fingerprints - ) - .fetch(&self.pool) - .map_ok(|record| { - ( - Certificate { - fingerprint: Fingerprint::from_hex(&record.fingerprint) - .expect("invalid certificate fingerprint in database"), - secret: false, - }, - Bytes::from(bytes::Bytes::from(record.body)), - ) - }) - .try_collect() - .await?) - } -} diff --git a/src/loader/certification_loader.rs b/src/loader/certification_loader.rs deleted file mode 100644 index ab9a314..0000000 --- a/src/loader/certification_loader.rs +++ /dev/null @@ -1,60 +0,0 @@ -use futures::stream::TryStreamExt; -use sequoia_openpgp::Fingerprint; -use std::{collections::HashMap, sync::Arc}; - -use async_graphql::dataloader::Loader; -use async_trait::async_trait; - -use crate::{ - certificate::Certificate, graphql::Bytes, loader_struct, trust::certification::Certification, -}; - -loader_struct!(CertificationBodyLoader); - -#[async_trait] -impl Loader for CertificationBodyLoader { - type Value = Bytes; - type Error = Arc; - - /// Loads the openpgp signature packet from the database for a [``Certification``]. - async fn load( - &self, - keys: &[Certification], - ) -> Result, Self::Error> { - // transform the fields of certification to a Vec, Vec so we can use it - // with sqlx - let (c, t): (Vec<_>, Vec<_>) = keys - .iter() - .map(|c| { - ( - c.certifier.fingerprint.to_hex(), - c.target.fingerprint.to_hex(), - ) - }) - .unzip(); - Ok(sqlx::query!( - r#" - SELECT certifier.fingerprint AS certifier, target.fingerprint AS target, certifications.body - FROM certifications - INNER JOIN certificates certifier ON (certifications.certifier_cert = certifier.fingerprint) - INNER JOIN certificates target ON (certifications.target_cert = target.fingerprint) - WHERE target_cert = ANY($1) - AND certifier_cert = ANY($2) - "#, - &c, - &t, - ) - .fetch(&self.pool) - .map_ok(|record| { - ( - Certification { - certifier: Certificate::from_public(Fingerprint::from_hex(&record.certifier).expect("invalid cert fingerprint in database")), - target: Certificate::from_public(Fingerprint::from_hex(&record.target).expect("invalid cert fingerprint in database")), - }, - bytes::Bytes::from(record.body).into(), - ) - }) - .try_collect() - .await?) - } -} diff --git a/src/loader/mod.rs b/src/loader/mod.rs deleted file mode 100644 index 9decbef..0000000 --- a/src/loader/mod.rs +++ /dev/null @@ -1,67 +0,0 @@ -mod cert_loader; -mod certification_loader; -mod user_loader; - -pub use cert_loader::*; -pub use certification_loader::*; -pub use user_loader::*; - -/// loader_struct macro -/// -/// Takes the name of the struct to create. Generates a struct with a field ``pool`` and a ``new`` implementation. -/// It is primarily used in the [``crate::basic_loader``] macro. -#[macro_export] -macro_rules! loader_struct { - ($name:ident) => { - pub struct $name { - pool: sqlx::Pool, - } - - impl $name { - pub fn new(pool: sqlx::Pool) -> Self { - Self { pool } - } - } - }; -} - -/// basic_loader macro -/// -/// Takes the name of the loader, the key type, the value type and the sql query. -/// **Note**: The sql query has to return the key as ``ka`` and the value as ``val``. -/// -/// # Example -/// -/// ```rust -/// crate::basic_loader!( -/// UsernameLoader, -/// uuid::Uuid, -/// String, -/// "SELECT user_id AS ka, username AS val FROM users WHERE user_id = ANY($1)" -/// ); -/// ``` - -#[macro_export] -macro_rules! basic_loader { - ($name:ident, $key:ty, $val:ty, $query:literal) => { - $crate::loader_struct!($name); - - #[async_trait::async_trait] - impl async_graphql::dataloader::Loader<$key> for $name { - type Value = $val; - type Error = std::sync::Arc; - - async fn load( - &self, - keys: &[$key], - ) -> Result, Self::Error> { - use futures::stream::TryStreamExt; - Ok(sqlx::query!($query, keys) - .fetch(&self.pool) - .map_ok(|record| (record.ka, record.val)) - .try_collect() - .await?) - } - } - }; -} diff --git a/src/loader/user_loader.rs b/src/loader/user_loader.rs deleted file mode 100644 index 6a183f5..0000000 --- a/src/loader/user_loader.rs +++ /dev/null @@ -1,8 +0,0 @@ -use crate::basic_loader; - -basic_loader!( - UsernameLoader, - uuid::Uuid, - String, - r#"SELECT "id" AS ka, username AS val FROM users WHERE "id" = ANY($1)"# -); diff --git a/src/main.rs b/src/main.rs index 12fed7e..0792e27 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,151 +1,49 @@ -use actix_web::body::Body; +#![doc = include_str!("../README.md")] +#![warn(missing_docs)] +#![deny(rustdoc::broken_intra_doc_links)] +use actix_web::{middleware::Logger, web, App, HttpServer}; +use config::Config; +use redis::aio::ConnectionManager; +use sqlx::{migrate, PgPool}; +use tokio::sync::Mutex; + +#[macro_use] +extern crate log; -use actix_web::web::Bytes; -use actix_web::{guard, web, App, HttpRequest, HttpResponse, HttpServer, Result}; -use actix_web::{post, HttpMessage}; - -use async_graphql::dataloader::DataLoader; -use async_graphql::extensions::ApolloTracing; -use async_graphql::http::{playground_source, GraphQLPlaygroundConfig}; -use async_graphql::EmptySubscription; -use async_graphql_actix_web::Request; - -use graphql::GraphQLSchema; - -use guards::AuthenticationGuard; -use jsonwebtoken::DecodingKey; -use log::info; -use moka::future::{Cache, CacheBuilder}; -use redis::Client; -use sqlx::{migrate, PgPool, Pool, Postgres}; - -use std::time::Duration; - -use crate::config::Config; -use crate::graphql::{Mutations, Queries}; -use crate::loader::*; - -const GRAPHQL_ENDPOINT: &str = "/graphql"; -const GRAPHQL_PLAYGROUND_ENDPOINT: &str = "/playground"; - -mod ac; -mod actors; -mod auth; -mod certificate; mod config; -mod fallible; -mod graphql; -mod guards; -mod loader; -mod trust; - -#[post("/graphql")] -async fn execute_graphql( - key: web::Data, - token_expiry_cache: web::Data>, - db: web::Data>, - schema: web::Data, - req: Request, - http_request: HttpRequest, -) -> HttpResponse { - let req = req.into_inner(); - let req = - AuthenticationGuard::parse(req, &http_request, key.as_ref(), &token_expiry_cache, &db) - .await; - let response = &schema.execute(req).await; - let content_type = http_request.content_type(); - match content_type { - "application/json" => HttpResponse::Ok() - .content_type("application/json") - .body(serde_json::to_string(&response).unwrap()), - _ => HttpResponse::Ok().body(Body::Bytes(Bytes::from( - serde_cbor::to_vec(&response).unwrap(), - ))), - } -} - -async fn getsdl(schema: web::Data) -> HttpResponse { - HttpResponse::Ok().body(Body::from(schema.sdl())) -} - -async fn playground() -> Result { - Ok(HttpResponse::Ok() - .content_type("text/html; charset=utf-8") - .body(playground_source(GraphQLPlaygroundConfig::new( - GRAPHQL_ENDPOINT, - )))) -} +mod oidc; #[actix_web::main] -async fn main() -> std::io::Result<()> { - pretty_env_logger::init(); - // Load config - - let config = Config::new(); - - // Connect to db - info!("Connecting to the database"); - let db: PgPool = PgPool::connect(&config.db_uri) - .await - .unwrap_or_else(|e| panic!("Can't connect to database: {}", e)); - info!("Running database migrations..."); - migrate!("./migrations/") - .run(&db) - .await - .expect("couldn't run database migrations"); - - let client = - redis::Client::open(config.redis_uri.clone()).expect("can't connect to redis server"); - - let pool: r2d2::Pool = r2d2::Pool::builder().build(client).unwrap(); - - let token_expiry_cache: Cache = CacheBuilder::new(100_000) - .time_to_live(Duration::from_secs(60)) - .build(); - - let decoding_key = config.jwt_secret.1.clone(); - // build the graphql schema - let schema = GraphQLSchema::build(Queries::default(), Mutations::default(), EmptySubscription) - // https://github.com/async-graphql/async-graphql/issues/595#issuecomment-892321221 - .register_type::() - .register_type::() - .extension(ApolloTracing) - .data(config.clone()) - .data(DataLoader::new(PublicCertificateLoader::new(db.clone()))) - .data(DataLoader::new(PrivateCertificateLoader::new(db.clone()))) - .data(DataLoader::new(UserIDLoaderByFingerprint::new(db.clone()))) - .data(DataLoader::new(PrivateCertificateBodyLoader::new( - db.clone(), - ))) - .data(DataLoader::new(PublicCertificateBodyLoader::new( - db.clone(), - ))) - .data(DataLoader::new(CertificationBodyLoader::new(db.clone()))) - .data(DataLoader::new(TokenExpiryLoader::new(db.clone()))) - .data(DataLoader::new(UsernameLoader::new(db.clone()))) - .data(db.clone()) - .data(pool) - .data(config.jwt_secret.0.clone()) - .data(decoding_key.clone()) - .data(config.server_cert.clone()) - .finish(); - - info!("Starting http server on {}", config.listen); - HttpServer::new(move || { +/// The entry point into the application +async fn main() -> anyhow::Result<()> { + // enable logging + env_logger::init(); + + let config = Config::load()?; + + // connect to the database + info!("Connecting to the postgres database"); + let db: PgPool = PgPool::connect(&config.postgres_uri).await?; + info!("Running database migrations"); + migrate!("./migrations/").run(&db).await?; + + // create the redis client + let redis = redis::Client::open(&*config.redis_uri)?; + let redis = ConnectionManager::new(redis).await?; + + // start the http server + info!("Starting server at {}", &config.listen); + let listen = config.listen.clone(); + Ok(HttpServer::new(move || { App::new() - .data(schema.clone()) - .data(decoding_key.clone()) - .data(token_expiry_cache.clone()) - .data(db.clone()) - .service(execute_graphql) - .route("/graphql/sdl", web::get().to(getsdl)) - .service( - web::resource(GRAPHQL_PLAYGROUND_ENDPOINT) - .guard(guard::Get()) - .to(playground), - ) + .wrap(Logger::default()) + // register endpoints + .service(web::scope("/oidc").service(oidc::login_redirect)) + .app_data(web::Data::new(config.clone())) + .app_data(web::Data::new(Mutex::new(redis.clone()))) + .app_data(web::Data::new(db.clone())) }) - .bind(config.listen)? + .bind(listen)? .run() - .await + .await?) } diff --git a/src/oidc.rs b/src/oidc.rs new file mode 100644 index 0000000..3b9910d --- /dev/null +++ b/src/oidc.rs @@ -0,0 +1,135 @@ +//! This module handles authentication with the openid connect provider + +use crate::config::Config; +use actix_web::{ + cookie::{Cookie, SameSite}, + error::{InternalError, UrlGenerationError}, + get, + http::StatusCode, + web::Data, + HttpResponse, +}; +use openidconnect::{ + core::CoreAuthenticationFlow, CsrfToken, Nonce, PkceCodeChallenge, PkceCodeVerifier, +}; +use redis::{aio::ConnectionManager, AsyncCommands}; +use serde::{Deserialize, Serialize}; +use sha2::{Digest, Sha256}; +use tokio::sync::Mutex; + +#[derive(Serialize, Deserialize)] +/// Struct used to serialize and deserialize a state mapped to a nonce and pkce +struct StateStore { + nonce: Nonce, + pkce_verifier: PkceCodeVerifier, +} + +#[get("/login")] +/// Redirects the User-Agent (browser) to the openid connect identity provider +/// for authentication +async fn login_redirect( + config: Data, + redis: Data>, +) -> actix_web::Result { + // recieve the client + let client = config + .openid_connect + .clone() + .load_client() + .await + .map_err(|e| { + InternalError::new( + format!( + "cannot recieve openid connect identity provider client: {}", + e + ), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); + + let (auth_url, state, nonce) = client + .authorize_url( + CoreAuthenticationFlow::AuthorizationCode, + CsrfToken::new_random, + Nonce::new_random, + ) + .set_pkce_challenge(pkce_challenge) + .url(); + + // hash the nonce and state + // they are returned as httpOnly cookies so javascript cannot steal them + // after a succesful login, the hashes are compared to the state returned + // from the identity provider and the nonce is compared with the nonce in + // the token + let nonce_hash = base64::encode(Sha256::digest(nonce.secret())); + let state_hash = base64::encode(Sha256::digest(state.secret())); + + let redis_state = serde_json::to_string(&StateStore { + nonce, + pkce_verifier, + })?; + + // get the ConnectionManager + let mut redis = redis.lock().await; + // the state is connected with the pkce_verifier to request the id token + // the nonce is used to bind a token to a state + let _: () = redis + // expires in 5 minutes + .set_ex(state.secret(), redis_state, 60 * 5) + .await + .map_err(|e| { + InternalError::new( + format!("cannot store in redis cache: {}", e), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + // the host used as base for the cookie `Domain` attribute + let host: &str = config + .openid_connect + .redirect_url + .host_str() + .ok_or(UrlGenerationError::ParseError(url::ParseError::EmptyHost))?; + + /// prevents code duplication for state and nonce cookie + fn cookie_secure<'a>( + name: &'a str, + value: &'a str, + host: &'a str, + path: &'a str, + ) -> Cookie<'a> { + Cookie::build(name, value) + // because only the redirect_url must be able to read these cookies + // the domain as well as the path can be set to exactly that + .domain(host) + .path(path) + // from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict : + // > Cookies will only be sent in a first-party context and not be + // > sent along with requests initiated by third party websites. + // Because the redirect to the callback url is made by a third party + // website (the identity provider), we cannot use SameSite::Secure + // instead, we use SameSite::Lax: + // > Cookies are not sent on normal cross-site subrequests (for + // > example to load images or frames into a third party site), but + // > are sent when a **user is navigating to the origin site** + // > (i.e., when following a link). + .same_site(SameSite::Lax) + .secure(true) + // the cookie does not need to be accessible for javascript + .http_only(true) + .finish() + } + + // the `Path` attribute for the cookie + let path = config.openid_connect.redirect_url.path(); + let nonce = cookie_secure("oidc_nonce", &nonce_hash, host, path); + let state = cookie_secure("oidc_state", &state_hash, host, path); + // create the cookies + Ok(HttpResponse::Found() + .insert_header(("Location", auth_url.as_str())) + .cookie(nonce) + .cookie(state) + .finish()) +} diff --git a/src/trust/certification.rs b/src/trust/certification.rs deleted file mode 100644 index 0021e9d..0000000 --- a/src/trust/certification.rs +++ /dev/null @@ -1,202 +0,0 @@ -use async_graphql::{dataloader::DataLoader, guard::Guard, Context, Object}; -use sequoia_openpgp::{ - packet::Signature, parse::Parse, serialize::MarshalInto, types::SignatureType, Cert, - Fingerprint, -}; -use sqlx::{PgPool, Pool, Postgres}; - -use crate::{ - auth::token::Claims, - certificate::Certificate, - fallible::{Error, InvalidCertificateFingerprint, InvalidSignature, UnknownCertificate}, - graphql::Bytes, - loader::{CertificationBodyLoader, PublicCertificateBodyLoader, PublicCertificateLoader}, - result_type, tri, -}; - -#[derive(Clone, PartialEq, Eq, Hash)] -pub struct Certification { - pub certifier: Certificate, - pub target: Certificate, -} - -// TODO: add result type here -impl Certification { - // cant use TryFrom cuz async :( - /// Tries to verify a [``Certification``] and inserts it into the database if valid - async fn try_from( - signer: &Cert, - target: &Cert, - certification: Bytes, - db: &Pool, - ) -> Result { - let mut signature = Signature::from_bytes(&*certification) - .map_err(|_| InvalidSignature::new("cannot parse signature".to_string()))?; - - // there are 4 types for certifications in openpgp - // implementations don't differ and so don't we - // NOTE: this check is actually not needed because ``verify_user_id_binding`` does exactly that too. - if !matches!( - signature.typ(), - SignatureType::GenericCertification - | SignatureType::PersonaCertification - | SignatureType::CasualCertification - | SignatureType::PositiveCertification - ) { - return Err(InvalidSignature { - description: "not a valid signature type".to_string(), - hint: Some( - concat!( - "expected 0x10-0x13 as defined in ", - "" - ) - .to_string(), - ), - } - .into()); - } - - // since a signature should only be ussed by one user, there is only one issuer - if signature.issuers().count() != 1 { - return Err(InvalidSignature::new("expected one issuer".to_string()).into()); - } - - // checks signature and signature type - match signature.verify_userid_binding( - signer.primary_key().key(), - target.primary_key().key(), - &target - .userids() - .next() - .expect("certs in database should have exactly one userid"), - ) { - Ok(_) => { - sqlx::query!( - r#" - INSERT INTO certifications ( - certifier_cert, - target_cert, - certification - ) VALUES ($1, $2, $3) - "#, - signer.fingerprint().to_hex(), - target.fingerprint().to_hex(), - signature.export_to_vec().unwrap(), - ) - .execute(db) - .await - .expect("failed to insert certification in database"); - Ok(Certification { - certifier: signer.into(), - target: target.into(), - }) - } - Err(e) => Err(InvalidSignature { - description: "invalid signature".to_string(), - hint: Some(e.to_string()), - } - .into()), - } - } -} - -#[Object] -impl Certification { - /// The creator of the certification - async fn certifier(&self) -> &Certificate { - &self.certifier - } - - /// The certified ``PublicCertificate`` - async fn target(&self) -> &Certificate { - &self.target - } - - /// The actual openpgp signature packet - async fn body(&self, ctx: &Context<'_>) -> Bytes { - ctx.data_unchecked::>() - .load_one(self.clone()) - .await - .unwrap() - .unwrap() - } -} - -#[derive(Default)] -pub struct CertificationMutations; - -#[derive(Default)] -pub struct CertificationQueries; - -result_type!(PublishCertificationResult, Certification); - -#[Object] -impl CertificationMutations { - #[graphql(guard(crate::guards::AuthenticationGuard()))] - /// Publish a certification - /// - /// A user may upload certifications for other certificates. - /// Other users can then query for certifications and don't - /// have to trust the server that it's actually the correct - /// openpgp identity for a user.\ - /// ``target`` is the ``fingerprint`` of the user's certificate - /// the certification is for.\ - /// ``certification`` is a single openpgp signature packet - /// of one of the certification types (0x10-0x13). - /// Note that attestations are not supported. Also, you can - /// only upload signatures made by the current authenticated - /// user. - async fn publish_certification( - &self, - ctx: &Context<'_>, - target: String, - certification: Bytes, - ) -> PublishCertificationResult { - // won't panic, because it is guarded by the AuthenticationGuard - let claims = ctx.data_unchecked::(); - let target = target.to_uppercase(); - - let t_figerprint = tri!(Fingerprint::from_hex(&target).map_err(|_| Error::from( - InvalidCertificateFingerprint::new("cannot parse fingerprint".to_string()) - ))); - - let t_cert = Certificate::from_public(t_figerprint); - let cert_loader = ctx.data_unchecked::>(); - - // the cert body of the target - let t_cert = tri!(cert_loader - .load_one(t_cert) - .await - .unwrap() - .ok_or_else(|| Error::from(UnknownCertificate::new( - "cannot find a certificate with that fingerprint".to_string(), - target, - )))); - - let c_cert = ctx - .data_unchecked::>() - .load_one(claims.sub) - .await - .unwrap() - .unwrap(); - - // the cert body of the certifier - let c_cert = cert_loader.load_one(c_cert).await.unwrap().unwrap(); - - let target = - Cert::from_bytes(&t_cert.into_inner()).expect("invalid certificate in database"); - let signer = - Cert::from_bytes(&c_cert.into_inner()).expect("invalid certificate in database"); - - tri!( - Certification::try_from( - &signer, - &target, - certification, - ctx.data_unchecked::(), - ) - .await - ) - .into() - } -} diff --git a/src/trust/mod.rs b/src/trust/mod.rs deleted file mode 100644 index efdc909..0000000 --- a/src/trust/mod.rs +++ /dev/null @@ -1,16 +0,0 @@ -/// Trust -/// -/// This modules handles parts for trust on users. -/// This primarily includes publication/search of PGP -/// certificates/identities -use async_graphql::MergedObject; - -use self::certification::CertificationMutations; - -pub mod certification; - -#[derive(Default, MergedObject)] -pub struct TrustMutations(pub CertificationMutations); - -#[derive(Default, MergedObject)] -pub struct TrustQueries(); From 07c4943e6cba3231e552e63f5eb706e228072786 Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Sat, 18 Dec 2021 19:43:55 +0100 Subject: [PATCH 5/7] feat: implement authentication with openid connect --- Cargo.lock | 1 + Cargo.toml | 1 + other/config.sample | 4 +- src/config.rs | 11 ++ src/main.rs | 6 +- src/oidc.rs | 278 +++++++++++++++++++++++++++++++++++--------- 6 files changed, 247 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 094cfa4..ab0658a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1145,6 +1145,7 @@ dependencies = [ "env_logger", "figment", "log", + "oauth2", "openidconnect", "redis", "serde", diff --git a/Cargo.toml b/Cargo.toml index 5985d43..8e562b9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,7 @@ anyhow = { version = "1.0.51", features = ["std"] } figment = { version = "0.10.6", features = ["env", "toml"] } # for openid connect integrations openidconnect = "2.1.2" +oauth2 = "4.1.0" # for hashing of the nonce and state parameter sha2 = "0.10.0" # used to encode the hash into base64 so it can be stored as a cookie diff --git a/other/config.sample b/other/config.sample index cb38dc4..8357a37 100644 --- a/other/config.sample +++ b/other/config.sample @@ -7,4 +7,6 @@ redis_uri = "rediss://redis:redis_password@example.com:6380" client_id = "minkan-server" client_secret = "aaa" discovery_url = "https://sso.erik-tesar.com/auth/realms/minkan" -redirect_url = "http://localhost:8080/odic/callback" \ No newline at end of file +redirect_url = "http://localhost:8080/odic/callback" +app_redirect_error = "https://localhost:8080/#/oidc/err" +app_redirect_success = "https://localhost:8080/#/oidc/ok" \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 7cb09b2..11d826a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -40,6 +40,17 @@ pub struct OidcConfig { pub discovery_url: Url, /// The url the User-Agent should be redirected to after an authentication pub redirect_url: Url, + /// The url the server redirects to if the openid connect provider returned + /// an error. The server will append the `error`, `error_description` and + /// `error_uri` as recieved by the openid connect provider. This way, the + /// application (frontend) can provide a nice UI + pub app_redirect_error: Url, + /// The url the server redirects to if the authentication with the openid + /// connect provider was successful. The server WILL NOT include any token + /// or informations from the openid connect identity provider. Instead, the + /// server will set an `httpOnly` cookie with the access token which will + /// be used to authenticate against the server (e.g. the GraphQL API). + pub app_redirect_success: Url, } impl OidcConfig { diff --git a/src/main.rs b/src/main.rs index 0792e27..66fc9ca 100644 --- a/src/main.rs +++ b/src/main.rs @@ -38,7 +38,11 @@ async fn main() -> anyhow::Result<()> { App::new() .wrap(Logger::default()) // register endpoints - .service(web::scope("/oidc").service(oidc::login_redirect)) + .service( + web::scope("/oidc") + .service(oidc::login_redirect) + .service(oidc::login_callback), + ) .app_data(web::Data::new(config.clone())) .app_data(web::Data::new(Mutex::new(redis.clone()))) .app_data(web::Data::new(db.clone())) diff --git a/src/oidc.rs b/src/oidc.rs index 3b9910d..14392f6 100644 --- a/src/oidc.rs +++ b/src/oidc.rs @@ -2,16 +2,24 @@ use crate::config::Config; use actix_web::{ - cookie::{Cookie, SameSite}, + cookie::{Cookie, CookieBuilder, SameSite}, error::{InternalError, UrlGenerationError}, get, http::StatusCode, - web::Data, - HttpResponse, + web::{Data, Query}, + Either, HttpRequest, HttpResponse, +}; + +use oauth2::{ + basic::{BasicErrorResponse, BasicErrorResponseType}, + RequestTokenError, }; use openidconnect::{ - core::CoreAuthenticationFlow, CsrfToken, Nonce, PkceCodeChallenge, PkceCodeVerifier, + core::{CoreAuthenticationFlow, CoreClient}, + reqwest::async_http_client, + AuthorizationCode, CsrfToken, Nonce, PkceCodeChallenge, PkceCodeVerifier, TokenResponse, }; + use redis::{aio::ConnectionManager, AsyncCommands}; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha256}; @@ -31,8 +39,20 @@ async fn login_redirect( config: Data, redis: Data>, ) -> actix_web::Result { + // afaik is the implemenation of this wrong. Then using + // `Client::authorize_url` (see below), it passes the plain `CsrfToken` + // directly into the `state` parameter in the url. But it should provide + // a hash (e.g. a sha256 hash) of the csrf token instead. The original + // value should be stored in a httpOnly cookie + // + // however, we still use the random function to generate a random string + let state = CsrfToken::new_random(); + // the hashed state is send in the authorization request uri as `state` + // parameter + let state_hash = base64::encode_config(Sha256::digest(state.secret()), base64::URL_SAFE_NO_PAD); + // recieve the client - let client = config + let client: CoreClient = config .openid_connect .clone() .load_client() @@ -49,23 +69,15 @@ async fn login_redirect( let (pkce_challenge, pkce_verifier) = PkceCodeChallenge::new_random_sha256(); - let (auth_url, state, nonce) = client + let (auth_url, _, nonce) = client .authorize_url( CoreAuthenticationFlow::AuthorizationCode, - CsrfToken::new_random, + || CsrfToken::new(state_hash), Nonce::new_random, ) .set_pkce_challenge(pkce_challenge) .url(); - // hash the nonce and state - // they are returned as httpOnly cookies so javascript cannot steal them - // after a succesful login, the hashes are compared to the state returned - // from the identity provider and the nonce is compared with the nonce in - // the token - let nonce_hash = base64::encode(Sha256::digest(nonce.secret())); - let state_hash = base64::encode(Sha256::digest(state.secret())); - let redis_state = serde_json::to_string(&StateStore { nonce, pkce_verifier, @@ -75,9 +87,15 @@ async fn login_redirect( let mut redis = redis.lock().await; // the state is connected with the pkce_verifier to request the id token // the nonce is used to bind a token to a state - let _: () = redis + redis // expires in 5 minutes - .set_ex(state.secret(), redis_state, 60 * 5) + .set_ex( + // prefix it so we have something similar to sql tables + // this input is trusted because it is generated by the server + format!("oidc:state:{}", state.secret()), + redis_state, + 60 * 5, + ) .await .map_err(|e| { InternalError::new( @@ -93,43 +111,199 @@ async fn login_redirect( .host_str() .ok_or(UrlGenerationError::ParseError(url::ParseError::EmptyHost))?; - /// prevents code duplication for state and nonce cookie - fn cookie_secure<'a>( - name: &'a str, - value: &'a str, - host: &'a str, - path: &'a str, - ) -> Cookie<'a> { - Cookie::build(name, value) - // because only the redirect_url must be able to read these cookies - // the domain as well as the path can be set to exactly that - .domain(host) - .path(path) - // from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict : - // > Cookies will only be sent in a first-party context and not be - // > sent along with requests initiated by third party websites. - // Because the redirect to the callback url is made by a third party - // website (the identity provider), we cannot use SameSite::Secure - // instead, we use SameSite::Lax: - // > Cookies are not sent on normal cross-site subrequests (for - // > example to load images or frames into a third party site), but - // > are sent when a **user is navigating to the origin site** - // > (i.e., when following a link). - .same_site(SameSite::Lax) - .secure(true) - // the cookie does not need to be accessible for javascript - .http_only(true) - .finish() - } - - // the `Path` attribute for the cookie - let path = config.openid_connect.redirect_url.path(); - let nonce = cookie_secure("oidc_nonce", &nonce_hash, host, path); - let state = cookie_secure("oidc_state", &state_hash, host, path); - // create the cookies + // build the state cookie + let state = Cookie::build("oidc_state", state.secret()) + // because only the redirect_url must be able to read these cookies, + // the domain as well as the path can be set to exactly that + .domain(host) + .path(config.openid_connect.redirect_url.path()) + // from https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie/SameSite#strict : + // > Cookies will only be sent in a first-party context and not be + // > sent along with requests initiated by third party websites. + // Because the redirect to the callback url is made by a third party + // website (the identity provider), we cannot use SameSite::Secure + // instead, we use SameSite::Lax: + // > Cookies are not sent on normal cross-site subrequests (for + // > example to load images or frames into a third party site), but + // > are sent when a **user is navigating to the origin site** + // > (i.e., when following a link). + .same_site(SameSite::Lax) + .secure(true) + // the cookie does not need to be accessible for javascript and really + // shouldn't because of XSS attacks + .http_only(true) + .finish(); + Ok(HttpResponse::Found() .insert_header(("Location", auth_url.as_str())) - .cookie(nonce) .cookie(state) .finish()) } + +#[derive(Deserialize)] +struct LoginCallbackInfo { + /// State hash provided from [`login_redirect`] + state: String, + /// code from the openid connect provider used to request the access, + /// refresh and id token + code: AuthorizationCode, +} + +#[get("/callback")] +async fn login_callback( + redis: Data>, + config: Data, + oidc_response: Either, Query>, + req: HttpRequest, +) -> actix_web::Result { + let mut redis = redis.lock().await; + + // the `oidc_state` cookie set in [`login_redirect`] + let state = req + .cookie("oidc_state") + .ok_or_else(|| InternalError::new("Missing state cookie", StatusCode::BAD_REQUEST))?; + + let mut response = HttpResponse::Found(); + // delete the state since they are one time use only no matter if + // the request was successful or not + response.del_cookie(&state); + + match oidc_response { + Either::Left(info) => { + let expected_state_hash = + base64::encode_config(Sha256::digest(&state.value()), base64::URL_SAFE_NO_PAD); + + // if the state's hash in the uri does not match the state in the + // cookie, there might be an attack and the redirect got intercepted + if expected_state_hash != info.state { + return Err(InternalError::new( + "State and state cookie do not match", + StatusCode::BAD_REQUEST, + ) + .into()); + } + + // so we dont have to format twice for GET and DEL + let redis_state = format!("oidc:state:{}", state.value()); + // load the [`StateStore`] from the redis database + let state: String = redis + // this input is UNTRUSTED but since it is prefixed and it is + // not possible to inject commands (e.g. by using \n), it is ok + .get(&redis_state) + .await + // there is no StateStore in the redis database, this could be + // cuz it expired or it got modified + .map_err(|_| InternalError::new("Unknown state", StatusCode::BAD_REQUEST))?; + let state: StateStore = serde_json::from_str(&state).map_err(|_| { + InternalError::new( + "Cannot parse state from redis cache", + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + // in newer redis version, we could use `GETDEL` which would make + // this command unnessary + redis + .del(&redis_state) + .await + .map_err(|e| InternalError::new(e, StatusCode::INTERNAL_SERVER_ERROR))?; + + // recieve the client + let client: CoreClient = + config + .openid_connect + .clone() + .load_client() + .await + .map_err(|e| { + InternalError::new( + format!( + "cannot recieve openid connect identity provider client: {}", + e + ), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + // exchange the code for an access token (PKCE with client secret) + let token_response = client + .exchange_code(info.code.clone()) + .set_pkce_verifier(state.pkce_verifier) + .request_async(async_http_client) + .await + .map_err(|e| { + if let RequestTokenError::ServerResponse(ref e) = e { + if let BasicErrorResponseType::InvalidGrant = e.error() { + return InternalError::new( + // sent if a `code` is invalid or being + // reused. The latter should not ever be the + // case because the `state` is one time use and + // checked before + format!( + concat!("Invalid `code` in request. ", "Server sent: {}"), + e.error_description().unwrap_or(&"None".to_string()) + ), + StatusCode::BAD_REQUEST, + ); + } + } + // fallback if there's something else + // other events shouldn't be triggerable by an user + InternalError::new( + format!("Cannot request token: {}", e), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + // finally the expected id token used for authentication + let id_token = token_response.id_token().ok_or_else(|| { + InternalError::new( + "openid connect identity provider did not return an id token", + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + let claims = id_token + .claims(&client.id_token_verifier(), &state.nonce) + .map_err(|e| { + InternalError::new( + format!("Invalid id token: {}", e), + StatusCode::INTERNAL_SERVER_ERROR, + ) + })?; + + // this is the only verification done here (except for siganture + // validation). + // the `aud` claim (Audience) and other claims will be validated by + // the authentication guard + if claims.nonce() != Some(&state.nonce) { + return Err( + InternalError::new("Invalid nonce in token", StatusCode::BAD_REQUEST).into(), + ); + } + + info!("Authenticated '{}'", claims.subject().as_str()); + let authentication_cookie = CookieBuilder::new( + concat!(env!("CARGO_CRATE_NAME"), "_id_token"), + id_token.to_string(), + ) + .same_site(SameSite::Strict) + .http_only(true) + .secure(true) + .path("/") + .finish(); + response.cookie(authentication_cookie).insert_header(( + "Location", + config.openid_connect.app_redirect_success.as_str(), + )); + } + Either::Right(_) => { + let mut redirect = config.openid_connect.redirect_url.clone(); + // just redirect with the query provided by the openid connect + // provider. + redirect.set_query(Some(req.query_string())); + response.insert_header(("Location", redirect.as_str())); + } + }; + + Ok(response.finish()) +} From 21e8e09b480d50c95cd3c20b378b1ae656e4077d Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Sat, 18 Dec 2021 20:16:25 +0100 Subject: [PATCH 6/7] chore: put built-in openid connect authentication behind a feature flag --- Cargo.toml | 9 ++++++++- other/config.sample | 2 ++ src/config.rs | 13 +++++++++---- src/main.rs | 24 +++++++++++++++++------- 4 files changed, 36 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8e562b9..53d92e9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,4 +36,11 @@ sqlx = { version = "0.5.9", features = ["macros", "migrate", "postgres", "runtim redis = { version = "0.21.4", features = ["tokio-native-tls-comp", "tokio-comp", "connection-manager", "r2d2"] } serde_json = "1.0.59" # for an async Mutex -tokio = { version = "1.14.0", features = ["sync"] } \ No newline at end of file +tokio = { version = "1.14.0", features = ["sync"] } + +[features] +# built-in authentication with an openid connect provider +oidc_login = [] + +# features enabled by default +default = ["oidc_login"] \ No newline at end of file diff --git a/other/config.sample b/other/config.sample index 8357a37..a1e4e49 100644 --- a/other/config.sample +++ b/other/config.sample @@ -7,6 +7,8 @@ redis_uri = "rediss://redis:redis_password@example.com:6380" client_id = "minkan-server" client_secret = "aaa" discovery_url = "https://sso.erik-tesar.com/auth/realms/minkan" + +# Optional if the instance is built without the `oidc_login` feature flag redirect_url = "http://localhost:8080/odic/callback" app_redirect_error = "https://localhost:8080/#/oidc/err" app_redirect_success = "https://localhost:8080/#/oidc/ok" \ No newline at end of file diff --git a/src/config.rs b/src/config.rs index 11d826a..5352054 100644 --- a/src/config.rs +++ b/src/config.rs @@ -7,7 +7,7 @@ use figment::{ use openidconnect::{ core::{CoreClient, CoreProviderMetadata}, reqwest::async_http_client, - ClientId, ClientSecret, IssuerUrl, RedirectUrl, + ClientId, ClientSecret, IssuerUrl, }; use serde::Deserialize; use url::Url; @@ -39,17 +39,20 @@ pub struct OidcConfig { /// [1]: https://openid.net/specs/openid-connect-discovery-1_0.html pub discovery_url: Url, /// The url the User-Agent should be redirected to after an authentication + #[cfg(feature = "oidc_login")] pub redirect_url: Url, /// The url the server redirects to if the openid connect provider returned /// an error. The server will append the `error`, `error_description` and /// `error_uri` as recieved by the openid connect provider. This way, the /// application (frontend) can provide a nice UI + #[cfg(feature = "oidc_login")] pub app_redirect_error: Url, /// The url the server redirects to if the authentication with the openid /// connect provider was successful. The server WILL NOT include any token /// or informations from the openid connect identity provider. Instead, the /// server will set an `httpOnly` cookie with the access token which will /// be used to authenticate against the server (e.g. the GraphQL API). + #[cfg(feature = "oidc_login")] pub app_redirect_success: Url, } @@ -59,15 +62,17 @@ impl OidcConfig { pub async fn load_client(self) -> anyhow::Result { let issuer_url = IssuerUrl::from_url(self.discovery_url); - let redirect_url = RedirectUrl::from_url(self.redirect_url); + #[cfg(feature = "oidc_login")] + let redirect_url = openidconnect::RedirectUrl::from_url(self.redirect_url); // perform request to the openid connect endpoint let meta = CoreProviderMetadata::discover_async(issuer_url, async_http_client).await?; let client_id = ClientId::new(self.client_id); let client_secret = ClientSecret::new(self.client_secret); - let client = CoreClient::from_provider_metadata(meta, client_id, Some(client_secret)) - .set_redirect_uri(redirect_url); + let client = CoreClient::from_provider_metadata(meta, client_id, Some(client_secret)); + #[cfg(feature = "oidc_login")] + let client = client.set_redirect_uri(redirect_url); Ok(client) } } diff --git a/src/main.rs b/src/main.rs index 66fc9ca..43f3758 100644 --- a/src/main.rs +++ b/src/main.rs @@ -11,6 +11,7 @@ use tokio::sync::Mutex; extern crate log; mod config; +#[cfg(feature = "oidc_login")] mod oidc; #[actix_web::main] @@ -35,17 +36,26 @@ async fn main() -> anyhow::Result<()> { info!("Starting server at {}", &config.listen); let listen = config.listen.clone(); Ok(HttpServer::new(move || { - App::new() + // allow this because else there's no nice way to register endpoints + // based on a feature flag + #[warn(clippy::let_and_return)] + let app = App::new() .wrap(Logger::default()) // register endpoints - .service( - web::scope("/oidc") - .service(oidc::login_redirect) - .service(oidc::login_callback), - ) .app_data(web::Data::new(config.clone())) .app_data(web::Data::new(Mutex::new(redis.clone()))) - .app_data(web::Data::new(db.clone())) + .app_data(web::Data::new(db.clone())); + + // make built-in authentication with an openid connect identity + // provider optional + #[cfg(feature = "oidc_login")] + let app = app.service( + web::scope("/oidc") + .service(oidc::login_redirect) + .service(oidc::login_callback), + ); + + app }) .bind(listen)? .run() From d8cdf971a5ee4b70a046995e927ad8c14ac85d07 Mon Sep 17 00:00:00 2001 From: Erik Tesar Date: Fri, 25 Mar 2022 22:19:24 +0100 Subject: [PATCH 7/7] feat: implement authentication and session recognition --- Cargo.lock | 839 +++++++++--------- Cargo.toml | 25 +- migrations/20220318121420_sessions.sql | 8 + .../20220318132536_revoked_sessions.sql | 6 + src/authn.rs | 2 + src/authn/identity.rs | 115 +++ src/main.rs | 3 +- src/oidc.rs | 3 - 8 files changed, 553 insertions(+), 448 deletions(-) create mode 100644 migrations/20220318121420_sessions.sql create mode 100644 migrations/20220318132536_revoked_sessions.sql create mode 100644 src/authn.rs create mode 100644 src/authn/identity.rs diff --git a/Cargo.lock b/Cargo.lock index ab0658a..4d78369 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "actix-codec" -version = "0.4.1" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13895df506faee81e423febbae3a33b27fca71831b96bb3d60adf16ebcfea952" +checksum = "57a7559404a7f3573127aab53c08ce37a6c6a315c374a31070f3c91cd1b4a7fe" dependencies = [ "bitflags", "bytes", @@ -16,14 +16,14 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.7.0", ] [[package]] name = "actix-http" -version = "3.0.0-beta.15" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ff7b149cc1b99967c22cb81c2c31f128ac88ed12bbf80c29c55a7511d46edb" +checksum = "0f3fdd63b9cfeaf92eeeece719dabbddddb420a57d3fd171ce1490ecfb7086b1" dependencies = [ "actix-codec", "actix-rt", @@ -32,28 +32,26 @@ dependencies = [ "ahash", "base64", "bitflags", - "brotli2", + "brotli", "bytes", "bytestring", "derive_more", "encoding_rs", "flate2", "futures-core", - "futures-util", "h2", "http", "httparse", "httpdate", - "itoa", + "itoa 1.0.1", "language-tags", "local-channel", "log", "mime", "percent-encoding", - "pin-project", "pin-project-lite", "rand", - "sha-1", + "sha-1 0.10.0", "smallvec", "zstd", ] @@ -70,9 +68,9 @@ dependencies = [ [[package]] name = "actix-router" -version = "0.5.0-beta.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36b95ce0d76d1aa2f98b681702807475ade0f99bd4552546a6843a966d42ea3d" +checksum = "eb60846b52c118f2f04a56cc90880a274271c489b2498623d58176f8ca21fa80" dependencies = [ "bytestring", "firestorm", @@ -84,20 +82,19 @@ dependencies = [ [[package]] name = "actix-rt" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c2f80ce8d0c990941c7a7a931f69fd0701b76d521f8d36298edf59cd3fbf1f" +checksum = "cdf3f2183be1241ed4dd22611850b85d38de0b08a09f1f7bcccbd0809084b359" dependencies = [ - "actix-macros", "futures-core", "tokio", ] [[package]] name = "actix-server" -version = "2.0.0-rc.1" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78c9b22794b8af1c2e02434873ef858f2a7db40dbbf861ce77a04cd81ac6b767" +checksum = "d9e7472ac180abb0a8e592b653744345983a7a14f44691c8394a799d0df4dbbf" dependencies = [ "actix-rt", "actix-service", @@ -105,7 +102,7 @@ dependencies = [ "futures-core", "futures-util", "log", - "mio 0.8.0", + "mio", "num_cpus", "socket2", "tokio", @@ -113,9 +110,9 @@ dependencies = [ [[package]] name = "actix-service" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d3dc6a618b082974a08d7a4781d24d4691cba51500059bfebe6656a61ebfe1e" +checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" dependencies = [ "futures-core", "paste", @@ -134,9 +131,9 @@ dependencies = [ [[package]] name = "actix-web" -version = "4.0.0-beta.14" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9387ea044357f12b606b8fad0652d3804ba498954f66ae5c677236cb0bd47db4" +checksum = "f4e5ebffd51d50df56a3ae0de0e59487340ca456f05dd0b90c0a7a6dd6a74d31" dependencies = [ "actix-codec", "actix-http", @@ -149,19 +146,18 @@ dependencies = [ "actix-web-codegen", "ahash", "bytes", + "bytestring", "cfg-if", "cookie", "derive_more", - "either", "encoding_rs", "futures-core", "futures-util", - "itoa", + "itoa 1.0.1", "language-tags", "log", "mime", "once_cell", - "paste", "pin-project-lite", "regex", "serde", @@ -169,15 +165,15 @@ dependencies = [ "serde_urlencoded", "smallvec", "socket2", - "time 0.3.5", + "time 0.3.7", "url", ] [[package]] name = "actix-web-codegen" -version = "0.5.0-beta.6" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a90b7f6c2fde9a1fe3df4da758c2c3c9d620dfa3eae4da0b6925dc0a13444a" +checksum = "7525bedf54704abb1d469e88d7e7e9226df73778798a69cea5022d53b2ae91bc" dependencies = [ "actix-router", "proc-macro2", @@ -211,11 +207,26 @@ dependencies = [ "memchr", ] +[[package]] +name = "alloc-no-stdlib" +version = "2.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35ef4730490ad1c4eae5c4325b2a95f521d023e5c885853ff7aca0a6a1631db3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "697ed7edc0f1711de49ce108c541623a0af97c6c60b2f6e2b65229847ac843c2" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "anyhow" -version = "1.0.51" +version = "1.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b26702f315f53b6071259e15dd9d64528213b44d61de1ec926eca7715d62203" +checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" [[package]] name = "arc-swap" @@ -265,15 +276,9 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" - -[[package]] -name = "base-x" -version = "0.2.8" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64" @@ -298,38 +303,39 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1d36a02058e76b040de25a4464ba1c80935655595b661505c8b39b664828b95" +checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" dependencies = [ "generic-array", ] [[package]] -name = "brotli-sys" -version = "0.3.2" +name = "brotli" +version = "3.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4445dea95f4c2b41cde57cc9fee236ae4dbae88d8fcbdb4750fc1bb5d86aaecd" +checksum = "f838e47a451d5a8fa552371f80024dd6ace9b7acdf25c4c3d0f9bc6816fb1c39" dependencies = [ - "cc", - "libc", + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", ] [[package]] -name = "brotli2" -version = "0.3.2" +name = "brotli-decompressor" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cb036c3eade309815c15ddbacec5b22c4d1f3983a774ab2eac2e3e9ea85568e" +checksum = "59ad2d4653bf5ca36ae797b1f4bb4dbddb60ce49ca4aed8a2ce4829f60425b80" dependencies = [ - "brotli-sys", - "libc", + "alloc-no-stdlib", + "alloc-stdlib", ] [[package]] name = "bumpalo" -version = "3.8.0" +version = "3.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f1e260c3a9040a7c19a12468758f4c16f31a81a1fe087482be9570ec864bb6c" +checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" [[package]] name = "byteorder" @@ -357,9 +363,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.72" +version = "1.0.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" dependencies = [ "jobserver", ] @@ -380,29 +386,24 @@ dependencies = [ "num-integer", "num-traits", "serde", + "time 0.1.43", "winapi", ] [[package]] name = "combine" -version = "4.6.2" +version = "4.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b2f5d0ee456f3928812dfc8c6d9a1d592b98678f6d56db9b0cd2b7bc6c8db5" +checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" dependencies = [ "bytes", "futures-core", "memchr", "pin-project-lite", "tokio", - "tokio-util", + "tokio-util 0.6.9", ] -[[package]] -name = "const_fn" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" - [[package]] name = "convert_case" version = "0.4.0" @@ -411,20 +412,20 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cookie" -version = "0.15.1" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5f1c7727e460397e56abc4bddc1d49e07a1ad78fc98eb2e1c8f032a58a2f80d" +checksum = "94d4706de1b0fa5b132270cddffa8585166037822e260a944fe161acd137ca05" dependencies = [ "percent-encoding", - "time 0.2.27", + "time 0.3.7", "version_check", ] [[package]] name = "core-foundation" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6888e10551bb93e424d8df1d07f1a8b4fceb0001a3a4b048bfc47554946f47b3" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" dependencies = [ "core-foundation-sys", "libc", @@ -462,28 +463,18 @@ checksum = "ccaeedb56da03b09f598226e25e80088cb4cd25f316e6e4df7d695f0feeb1403" [[package]] name = "crc32fast" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "738c290dfaea84fc1ca15ad9c168d083b05a714e1efddd8edaab678dc28d2836" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "crossbeam-channel" -version = "0.5.1" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" dependencies = [ "cfg-if", - "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.2" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" +checksum = "4dd435b205a4842da59efd07628f921c096bc1cc0a156835b4fa0bcb9a19bcce" dependencies = [ "cfg-if", "crossbeam-utils", @@ -491,9 +482,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.5" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" +checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" dependencies = [ "cfg-if", "lazy_static", @@ -501,11 +492,12 @@ dependencies = [ [[package]] name = "crypto-common" -version = "0.1.0" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567569e659735adb39ff2d4c20600f7cd78be5471f8c58ab162bce3c03fdbc5f" +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" dependencies = [ "generic-array", + "typenum", ] [[package]] @@ -527,7 +519,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.4.0", + "rustc_version", "syn", ] @@ -542,20 +534,19 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.0" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8549e6bfdecd113b7e221fe60b433087f6957387a20f8118ebca9b12af19143d" +checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" dependencies = [ - "block-buffer 0.10.0", + "block-buffer 0.10.2", "crypto-common", - "generic-array", ] [[package]] name = "dirs" -version = "3.0.2" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30baa043103c9d0c2a57cf537cc2f35623889dc0d405e6c3cccfadbc81c71309" +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" dependencies = [ "dirs-sys", ] @@ -571,12 +562,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dotenv" version = "0.15.0" @@ -617,6 +602,15 @@ dependencies = [ "termcolor", ] +[[package]] +name = "fastrand" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" +dependencies = [ + "instant", +] + [[package]] name = "figment" version = "0.10.6" @@ -633,9 +627,9 @@ dependencies = [ [[package]] name = "firestorm" -version = "0.4.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31586bda1b136406162e381a3185a506cdfc1631708dd40cba2f6628d8634499" +checksum = "4d3d6188b8804df28032815ea256b6955c9625c24da7525f387a7af02fbb8f01" [[package]] name = "flate2" @@ -682,9 +676,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cd0210d8c325c245ff06fd95a3b13689a1a276ac8cfa8e8720cb840bfb84b9e" +checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" dependencies = [ "futures-channel", "futures-core", @@ -697,9 +691,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc8cd39e3dbf865f7340dce6a2d401d24fd37c6fe6c4f0ee0de8bfca2252d27" +checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", "futures-sink", @@ -707,15 +701,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "629316e42fe7c2a0b9a65b47d159ceaa5453ab14e8f0a3c5eedbb8cd55b4a445" +checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" [[package]] name = "futures-executor" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b808bf53348a36cab739d7e04755909b9fcaaa69b7d7e588b37b6ec62704c97" +checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" dependencies = [ "futures-core", "futures-task", @@ -730,20 +724,20 @@ checksum = "62007592ac46aa7c2b6416f7deb9a8a8f63a01e0f1d6e1787d5630170db2b63e" dependencies = [ "futures-core", "lock_api", - "parking_lot", + "parking_lot 0.11.2", ] [[package]] name = "futures-io" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e481354db6b5c353246ccf6a728b0c5511d752c08da7260546fc0933869daa11" +checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" [[package]] name = "futures-macro" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a89f17b21645bc4ed773c69af9c9a0effd4a3f1a3876eadd453469f8854e7fdd" +checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" dependencies = [ "proc-macro2", "quote", @@ -752,21 +746,21 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "996c6442437b62d21a32cd9906f9c41e7dc1e19a9579843fad948696769305af" +checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" [[package]] name = "futures-task" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dabf1872aaab32c886832f2276d2f5399887e2bd613698a02359e4ea83f8de12" +checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" [[package]] name = "futures-util" -version = "0.3.18" +version = "0.3.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d22213122356472061ac0f1ab2cee28d2bac8491410fd68c2af53d1cedb83e" +checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-channel", "futures-core", @@ -782,9 +776,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "0.14.4" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" dependencies = [ "typenum", "version_check", @@ -792,9 +786,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "js-sys", @@ -805,9 +799,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.3.9" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f072413d126e57991455e0a922b31e4c8ba7c2ffbebf6b78b4f8521397d65cd" +checksum = "d9f1f717ddc7b2ba36df7e871fd88db79326551d3d6f1fc406fbfd28b582ff8e" dependencies = [ "bytes", "fnv", @@ -818,7 +812,7 @@ dependencies = [ "indexmap", "slab", "tokio", - "tokio-util", + "tokio-util 0.6.9", "tracing", ] @@ -876,13 +870,13 @@ dependencies = [ [[package]] name = "http" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1323096b05d41827dadeaee54c9981958c0f94e670bc94ed80037d1a7b8b186b" +checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" dependencies = [ "bytes", "fnv", - "itoa", + "itoa 1.0.1", ] [[package]] @@ -898,9 +892,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acd94fdbe1d4ff688b67b04eee2e17bd50995534a61539e45adfefb45e5e5503" +checksum = "9100414882e15fb7feccb4897e5f0ff0ff1ca7d1a86a23208ada4d7a18e6c6c4" [[package]] name = "httpdate" @@ -916,9 +910,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.16" +version = "0.14.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ec3e62bdc98a2f0393a5048e4c30ef659440ea6e0e572965103e72bd836f55" +checksum = "043f0e083e9901b6cc658a77d1eb86f4fc650bbb977a4337dd63192826aa85dd" dependencies = [ "bytes", "futures-channel", @@ -929,7 +923,7 @@ dependencies = [ "http-body", "httparse", "httpdate", - "itoa", + "itoa 1.0.1", "pin-project-lite", "socket2", "tokio", @@ -946,9 +940,9 @@ checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" dependencies = [ "http", "hyper", - "rustls 0.20.2", + "rustls 0.20.4", "tokio", - "tokio-rustls 0.23.1", + "tokio-rustls 0.23.2", ] [[package]] @@ -964,9 +958,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" dependencies = [ "autocfg", "hashbrown", @@ -974,9 +968,9 @@ dependencies = [ [[package]] name = "inlinable_string" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3094308123a0e9fd59659ce45e22de9f53fc1d2ac6e1feb9fef988e4f76cad77" +checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" [[package]] name = "instant" @@ -1017,6 +1011,12 @@ version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "jobserver" version = "0.1.24" @@ -1028,9 +1028,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cc9ffccd38c451a86bf13657df244e9c3f37493cce8e5e21e940963777acc84" +checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" dependencies = [ "wasm-bindgen", ] @@ -1049,9 +1049,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.111" +version = "0.2.119" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e167738f1866a7ec625567bae89ca0d44477232a4f7c52b1c7f2adc2c98804f" +checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" [[package]] name = "local-channel" @@ -1067,15 +1067,15 @@ dependencies = [ [[package]] name = "local-waker" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84f9a2d3e27ce99ce2c3aad0b09b1a7b916293ea9b2bf624c13fe646fadd8da4" +checksum = "902eb695eb0591864543cbfbf6d742510642a605a61fc5e97fe6ceb5a30ac4fb" [[package]] name = "lock_api" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712a4d093c9976e24e7dbca41db895dabcbac38eb5f4045393d17a95bdfb1109" +checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" dependencies = [ "scopeguard", ] @@ -1142,6 +1142,7 @@ dependencies = [ "anyhow", "base64", "bytes", + "chrono", "env_logger", "figment", "log", @@ -1150,25 +1151,12 @@ dependencies = [ "redis", "serde", "serde_json", - "sha2 0.10.0", + "sha2 0.10.2", "sqlx", "tokio", "url", ] -[[package]] -name = "mio" -version = "0.7.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" -dependencies = [ - "libc", - "log", - "miow", - "ntapi", - "winapi", -] - [[package]] name = "mio" version = "0.8.0" @@ -1222,9 +1210,9 @@ dependencies = [ [[package]] name = "ntapi" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" dependencies = [ "winapi", ] @@ -1261,14 +1249,23 @@ dependencies = [ [[package]] name = "num_cpus" -version = "1.13.0" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" dependencies = [ "hermit-abi", "libc", ] +[[package]] +name = "num_threads" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ba99ba6393e2c3734791401b66902d981cb03bf190af674ca69949b6d5fb15" +dependencies = [ + "libc", +] + [[package]] name = "oauth2" version = "4.1.0" @@ -1284,16 +1281,16 @@ dependencies = [ "serde", "serde_json", "serde_path_to_error", - "sha2 0.9.8", + "sha2 0.9.9", "thiserror", "url", ] [[package]] name = "once_cell" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "692fcb63b64b1758029e0a96ee63e049ce8c5948587f2f7208df04625e5f6b56" +checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5" [[package]] name = "opaque-debug" @@ -1303,9 +1300,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] name = "openidconnect" -version = "2.1.2" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d523cf32bdf7696f36bc4198a42c34b65f0227b97f2f501ebfbe016baa5bc52" +checksum = "f6db0c030c3036f53c7108668641151b244358d221303a17985b07ac9bb60091" dependencies = [ "base64", "chrono", @@ -1342,9 +1339,9 @@ dependencies = [ [[package]] name = "openssl-probe" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" @@ -1376,7 +1373,17 @@ checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" dependencies = [ "instant", "lock_api", - "parking_lot_core", + "parking_lot_core 0.8.5", +] + +[[package]] +name = "parking_lot" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +dependencies = [ + "lock_api", + "parking_lot_core 0.9.1", ] [[package]] @@ -1393,6 +1400,19 @@ dependencies = [ "winapi", ] +[[package]] +name = "parking_lot_core" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-sys", +] + [[package]] name = "paste" version = "1.0.6" @@ -1428,31 +1448,11 @@ version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" -[[package]] -name = "pin-project" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "576bc800220cc65dac09e99e97b08b358cfab6e17078de8dc5fee223bd2d0c08" -dependencies = [ - "pin-project-internal", -] - -[[package]] -name = "pin-project-internal" -version = "1.0.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e8fe8163d14ce7f0cdac2e040116f22eac817edabff0be91e8aff7e9accf389" -dependencies = [ - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "pin-project-lite" -version = "0.2.7" +version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d31d11c69a6b52a174b42bdc0c30e5e11670f90788b2c471c31c1d17d449443" +checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" [[package]] name = "pin-utils" @@ -1468,21 +1468,15 @@ checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" [[package]] name = "ppv-lite86" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed0cfbc8191465bed66e1718596ee0b0b35d5ee1f41c5df2189d0fe8bde535ba" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" +checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" [[package]] name = "proc-macro2" -version = "1.0.33" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb37d2df5df740e582f28f8560cf425f52bb267d872fe58358eadb554909f07a" +checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" dependencies = [ "unicode-xid", ] @@ -1502,9 +1496,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.10" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bc8cc6a5f2e3655e0899c1b848643b2562f853f114bfec7be120678e3ace05" +checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" dependencies = [ "proc-macro2", ] @@ -1516,20 +1510,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "545c5bc2b880973c9c10e4067418407a0ccaa3091781d1671d46eb35107cb26f" dependencies = [ "log", - "parking_lot", + "parking_lot 0.11.2", "scheduled-thread-pool", ] [[package]] name = "rand" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e7573632e6454cf6b99d7aac4ccca54be06da05aca2ef7423d22d27d4d4bcd8" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", "rand_core", - "rand_hc", ] [[package]] @@ -1551,20 +1544,11 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d51e9f596de227fda2ea6c84607f5558e196eeaf43c986b724ba4fb8fdf497e7" -dependencies = [ - "rand_core", -] - [[package]] name = "redis" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f23ceed4c0e76b322657c2c3352ea116f9ec60a1a1aefeb3c84ed062c50865b" +checksum = "1a80b5f38d7f5a020856a0e16e40a9cfabf88ae8f0e4c2dcd8a3114c1e470852" dependencies = [ "arc-swap", "async-trait", @@ -1573,7 +1557,7 @@ dependencies = [ "dtoa", "futures", "futures-util", - "itoa", + "itoa 0.4.8", "native-tls", "percent-encoding", "pin-project-lite", @@ -1581,7 +1565,7 @@ dependencies = [ "sha1", "tokio", "tokio-native-tls", - "tokio-util", + "tokio-util 0.6.9", "url", ] @@ -1632,15 +1616,16 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.11.7" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07bea77bc708afa10e59905c3d4af7c8fd43c9214251673095ff8b14345fcbc5" +checksum = "87f242f1488a539a79bac6dbe7c8609ae43b7914b7736210f239a37cccb32525" dependencies = [ "base64", "bytes", "encoding_rs", "futures-core", "futures-util", + "h2", "http", "http-body", "hyper", @@ -1652,18 +1637,18 @@ dependencies = [ "mime", "percent-encoding", "pin-project-lite", - "rustls 0.20.2", + "rustls 0.20.4", "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "tokio", - "tokio-rustls 0.23.1", + "tokio-rustls 0.23.2", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.22.2", "winreg", ] @@ -1682,22 +1667,13 @@ dependencies = [ "winapi", ] -[[package]] -name = "rustc_version" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" -dependencies = [ - "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", + "semver", ] [[package]] @@ -1715,9 +1691,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.20.2" +version = "0.20.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37e5e2290f3e040b594b1a9e04377c2c671f1a1cfd9bfdef82106ac1c113f84" +checksum = "4fbfeb8d0ddb84706bc597a5574ab8912817c52a397f819e5b614e2265206921" dependencies = [ "log", "ring", @@ -1736,9 +1712,9 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.7" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "254df5081ce98661a883445175e52efe99d1cb2a5552891d965d2f5d0cad1c16" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" [[package]] name = "schannel" @@ -1756,7 +1732,7 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc6f74fd1204073fa02d5d5d68bec8021be4c38690b61264b2fdb48083d0e7d7" dependencies = [ - "parking_lot", + "parking_lot 0.11.2", ] [[package]] @@ -1787,9 +1763,9 @@ dependencies = [ [[package]] name = "security-framework" -version = "2.4.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525bc1abfda2e1998d152c45cf13e696f76d0a4972310b22fac1658b05df7c87" +checksum = "2dc14f172faf8a0194a3aded622712b0de276821addc574fa54fc0a1167e10dc" dependencies = [ "bitflags", "core-foundation", @@ -1800,9 +1776,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.4.2" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9dd14d83160b528b7bfd66439110573efcfbe281b17fc2ca9f39f550d619c7e" +checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556" dependencies = [ "core-foundation-sys", "libc", @@ -1810,30 +1786,15 @@ dependencies = [ [[package]] name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - -[[package]] -name = "semver" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "568a8e6258aa33c13358f81fd834adb854c6f7c9468520910a9b1e8fac068012" - -[[package]] -name = "semver-parser" -version = "0.7.0" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" [[package]] name = "serde" -version = "1.0.131" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4ad69dfbd3e45369132cc64e6748c2d65cdfb001a2b1c232d128b4ad60561c1" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" dependencies = [ "serde_derive", ] @@ -1850,9 +1811,9 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.131" +version = "1.0.136" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b710a83c4e0dff6a3d511946b95274ad9ca9e5d3ae497b63fda866ac955358d2" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" dependencies = [ "proc-macro2", "quote", @@ -1861,32 +1822,32 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.72" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0ffa0837f2dfa6fb90868c2b5468cad482e175f7dad97e7421951e663f2b527" +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" dependencies = [ - "itoa", + "itoa 1.0.1", "ryu", "serde", ] [[package]] name = "serde_path_to_error" -version = "0.1.5" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0421d4f173fab82d72d6babf36d57fae38b994ca5c2d78e704260ba6d12118b" +checksum = "d7868ad3b8196a8a0aea99a8220b124278ee5320a55e4fde97794b6f85b1a377" dependencies = [ "serde", ] [[package]] name = "serde_urlencoded" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edfa57a7f8d9c1d260a549e7224100f6c43d43f9103e06dd8b4095a9b2b43ce9" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" dependencies = [ "form_urlencoded", - "itoa", + "itoa 1.0.1", "ryu", "serde", ] @@ -1904,17 +1865,37 @@ dependencies = [ "opaque-debug", ] +[[package]] +name = "sha-1" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.3", +] + [[package]] name = "sha1" -version = "0.6.0" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1da05c97445caa12d05e848c4a4fcbbea29e748ac28f7e80e9b010392063770" +dependencies = [ + "sha1_smol", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" [[package]] name = "sha2" -version = "0.9.8" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b69f9a4c9740d74c5baa3fd2e547f9525fa8088a8a958e0ca2409a514e33f5fa" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", @@ -1925,13 +1906,13 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900d964dd36bb15bcf2f2b35694c072feab74969a54f2bbeec7a2d725d2bdcb6" +checksum = "55deaec60f81eefe3cce0dc50bda92d6d8e88f2a27df7c5033b42afeb1ed2676" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.0", + "digest 0.10.3", ] [[package]] @@ -1951,15 +1932,15 @@ checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" [[package]] name = "smallvec" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" [[package]] name = "socket2" -version = "0.4.2" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5dc90fe6c7be1a323296982db1836d1ea9e47b6839496dde9a541bc496df3516" +checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" dependencies = [ "libc", "winapi", @@ -1984,9 +1965,9 @@ dependencies = [ [[package]] name = "sqlx" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7911b0031a0247af40095838002999c7a52fba29d9739e93326e71a5a1bc9d43" +checksum = "fc15591eb44ffb5816a4a70a7efd5dd87bfd3aa84c4c200401c4396140525826" dependencies = [ "sqlx-core", "sqlx-macros", @@ -1994,9 +1975,9 @@ dependencies = [ [[package]] name = "sqlx-core" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aec89bfaca8f7737439bad16d52b07f1ccd0730520d3bf6ae9d069fe4b641fb1" +checksum = "195183bf6ff8328bb82c0511a83faf60aacf75840103388851db61d7a9854ae3" dependencies = [ "ahash", "atoi", @@ -2005,9 +1986,7 @@ dependencies = [ "byteorder", "bytes", "crc", - "crossbeam-channel", "crossbeam-queue", - "crossbeam-utils", "dirs", "either", "futures-channel", @@ -2018,20 +1997,20 @@ dependencies = [ "hex", "hmac", "indexmap", - "itoa", + "itoa 1.0.1", "libc", "log", "md-5", "memchr", "once_cell", - "parking_lot", + "paste", "percent-encoding", "rand", "rustls 0.19.1", "serde", "serde_json", - "sha-1", - "sha2 0.9.8", + "sha-1 0.9.8", + "sha2 0.9.9", "smallvec", "sqlformat", "sqlx-rt", @@ -2040,15 +2019,15 @@ dependencies = [ "tokio-stream", "url", "webpki 0.21.4", - "webpki-roots", + "webpki-roots 0.21.1", "whoami", ] [[package]] name = "sqlx-macros" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "584866c833511b1a152e87a7ee20dee2739746f60c858b3c5209150bc4b466f5" +checksum = "eee35713129561f5e55c554bba1c378e2a7e67f81257b7311183de98c50e6f94" dependencies = [ "dotenv", "either", @@ -2056,7 +2035,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "sha2 0.9.8", + "sha2 0.9.9", "sqlx-core", "sqlx-rt", "syn", @@ -2065,9 +2044,9 @@ dependencies = [ [[package]] name = "sqlx-rt" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d1bd069de53442e7a320f525a6d4deb8bb0621ac7a55f7eccbc2b58b57f43d0" +checksum = "b555e70fbbf84e269ec3858b7a6515bcfe7a166a7cc9c636dd6efd20431678b6" dependencies = [ "actix-rt", "once_cell", @@ -2075,64 +2054,6 @@ dependencies = [ "tokio-rustls 0.22.0", ] -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", -] - -[[package]] -name = "stdweb-internal-macros" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" -dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", -] - -[[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" - [[package]] name = "stringprep" version = "0.1.2" @@ -2151,9 +2072,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.82" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8daf5dd0bb60cbd4137b1b587d2fc0ae729bc07cf01cd70b36a1ed5ade3b9d59" +checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" dependencies = [ "proc-macro2", "quote", @@ -2162,13 +2083,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.2.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" +checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" dependencies = [ "cfg-if", + "fastrand", "libc", - "rand", "redox_syscall", "remove_dir_all", "winapi", @@ -2205,51 +2126,31 @@ dependencies = [ [[package]] name = "time" -version = "0.2.27" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "const_fn", "libc", - "standback", - "stdweb", - "time-macros", - "version_check", "winapi", ] [[package]] name = "time" -version = "0.3.5" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41effe7cfa8af36f439fac33861b66b049edc6f9a32331e2312660529c1c24ad" +checksum = "004cbc98f30fa233c61a38bc77e96a9106e65c88f2d3bef182ae952027e5753d" dependencies = [ - "itoa", + "itoa 1.0.1", "libc", + "num_threads", + "time-macros", ] [[package]] name = "time-macros" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" -dependencies = [ - "proc-macro-hack", - "time-macros-impl", -] - -[[package]] -name = "time-macros-impl" -version = "0.1.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" -dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", -] +checksum = "25eb0ca3468fc0acc11828786797f6ef9aa1555e4a211a60d64cc8e4d1be47d6" [[package]] name = "tinyvec" @@ -2268,20 +2169,20 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "tokio" -version = "1.14.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e992e41e0d2fb9f755b37446f20900f64446ef54874f40a60c78f021ac6144" +checksum = "2af73ac49756f3f7c01172e34a23e5d0216f6c32333757c2c61feb2bbff5a5ee" dependencies = [ - "autocfg", "bytes", "libc", "memchr", - "mio 0.7.14", + "mio", "num_cpus", "once_cell", - "parking_lot", + "parking_lot 0.12.0", "pin-project-lite", "signal-hook-registry", + "socket2", "winapi", ] @@ -2308,11 +2209,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.23.1" +version = "0.23.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4baa378e417d780beff82bf54ceb0d195193ea6a00c14e22359e7f39456b5689" +checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" dependencies = [ - "rustls 0.20.2", + "rustls 0.20.4", "tokio", "webpki 0.22.0", ] @@ -2342,6 +2243,20 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-util" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64910e1b9c1901aaf5375561e35b9c057d95ff41a44ede043a03e09279eabaf1" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] + [[package]] name = "toml" version = "0.5.8" @@ -2359,9 +2274,9 @@ checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" [[package]] name = "tracing" -version = "0.1.29" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375a639232caf30edfc78e8d89b2d4c375515393e7af7e16f01cd96917fb2105" +checksum = "f6c650a8ef0cd2dd93736f033d21cbd1224c5a967aa0c258d00fcf7dafef9b9f" dependencies = [ "cfg-if", "pin-project-lite", @@ -2370,9 +2285,9 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.21" +version = "0.1.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4ed65637b8390770814083d20756f87bfa2c21bf2f110babdc5438351746e4" +checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23" dependencies = [ "lazy_static", ] @@ -2385,9 +2300,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" [[package]] name = "typenum" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63708a265f51345575b27fe43f9500ad611579e764c79edbc2037b1121959ec" +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" [[package]] name = "uncased" @@ -2415,9 +2330,9 @@ dependencies = [ [[package]] name = "unicode-segmentation" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" [[package]] name = "unicode-xid" @@ -2458,9 +2373,9 @@ checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "want" @@ -2480,9 +2395,9 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" +checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -2490,9 +2405,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a317bf8f9fba2476b4b2c85ef4c4af8ff39c3c7f0cdfeed4f82c34a880aa837b" +checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" dependencies = [ "bumpalo", "lazy_static", @@ -2505,9 +2420,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" dependencies = [ "cfg-if", "js-sys", @@ -2517,9 +2432,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d56146e7c495528bf6587663bea13a8eb588d39b36b679d83972e1a2dbbdacf9" +checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -2527,9 +2442,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7803e0eea25835f8abdc585cd3021b3deb11543c6fe226dcd30b228857c5c5ab" +checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" dependencies = [ "proc-macro2", "quote", @@ -2540,15 +2455,15 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.78" +version = "0.2.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0237232789cf037d5480773fe568aac745bfe2afbc11a863e97901780a6b47cc" +checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" [[package]] name = "web-sys" -version = "0.3.55" +version = "0.3.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" dependencies = [ "js-sys", "wasm-bindgen", @@ -2583,6 +2498,15 @@ dependencies = [ "webpki 0.21.4", ] +[[package]] +name = "webpki-roots" +version = "0.22.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" +dependencies = [ + "webpki 0.22.0", +] + [[package]] name = "whoami" version = "1.2.1" @@ -2624,6 +2548,49 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" +dependencies = [ + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" + +[[package]] +name = "windows_i686_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" + +[[package]] +name = "windows_i686_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" + [[package]] name = "winreg" version = "0.7.0" @@ -2641,18 +2608,18 @@ checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" [[package]] name = "zstd" -version = "0.9.0+zstd.1.5.0" +version = "0.10.0+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07749a5dc2cb6b36661290245e350f15ec3bbb304e493db54a1d354480522ccd" +checksum = "3b1365becbe415f3f0fcd024e2f7b45bacfb5bdd055f0dc113571394114e7bdd" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "4.1.1+zstd.1.5.0" +version = "4.1.4+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c91c90f2c593b003603e5e0493c837088df4469da25aafff8bce42ba48caf079" +checksum = "2f7cd17c9af1a4d6c24beb1cc54b17e2ef7b593dc92f19e9d9acad8b182bbaee" dependencies = [ "libc", "zstd-sys", @@ -2660,9 +2627,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "1.6.1+zstd.1.5.0" +version = "1.6.3+zstd.1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615120c7a2431d16cf1cf979e7fc31ba7a5b5e5707b29c8a99e5dbf8a8392a33" +checksum = "fc49afa5c8d634e75761feda8c592051e7eeb4683ba827211eb0d731d3402ea8" dependencies = [ "cc", "libc", diff --git a/Cargo.toml b/Cargo.toml index 53d92e9..902a41f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,15 +1,13 @@ [package] name = "minkan_server" version = "0.1.0" -authors = [ - "Erik Tesar ", -] +authors = ["Erik Tesar "] edition = "2021" license = "AGPL-3.0-or-later" [dependencies] # the web framework to serve endpoints -actix-web = "4.0.0-beta.14" +actix-web = "4.0.1" # for the logger macros log = "0.4.14" # an backend to actually output logs @@ -22,7 +20,8 @@ anyhow = { version = "1.0.51", features = ["std"] } # for configuration figment = { version = "0.10.6", features = ["env", "toml"] } # for openid connect integrations -openidconnect = "2.1.2" +openidconnect = "2.2" +chrono = { version = "0.4.19", features = ["clock"] } oauth2 = "4.1.0" # for hashing of the nonce and state parameter sha2 = "0.10.0" @@ -31,9 +30,19 @@ base64 = "0.13.0" # used for redirect url parsing and cookie domain / path url = { version = "2.2.2", features = ["serde"] } # for communication with the postgres database -sqlx = { version = "0.5.9", features = ["macros", "migrate", "postgres", "runtime-actix-rustls"]} +sqlx = { version = "0.5.9", features = [ + "macros", + "migrate", + "postgres", + "runtime-actix-rustls", +] } # for communication with redis so we can share state between instances -redis = { version = "0.21.4", features = ["tokio-native-tls-comp", "tokio-comp", "connection-manager", "r2d2"] } +redis = { version = "0.21.4", features = [ + "tokio-native-tls-comp", + "tokio-comp", + "connection-manager", + "r2d2", +] } serde_json = "1.0.59" # for an async Mutex tokio = { version = "1.14.0", features = ["sync"] } @@ -43,4 +52,4 @@ tokio = { version = "1.14.0", features = ["sync"] } oidc_login = [] # features enabled by default -default = ["oidc_login"] \ No newline at end of file +default = ["oidc_login"] diff --git a/migrations/20220318121420_sessions.sql b/migrations/20220318121420_sessions.sql new file mode 100644 index 0000000..15a9439 --- /dev/null +++ b/migrations/20220318121420_sessions.sql @@ -0,0 +1,8 @@ +CREATE TABLE sessions ( + -- the session id (`sid` claim in the id token) + "id" TEXT NOT NULL PRIMARY KEY, + -- the user this session related to (`sub` claim) + "user_id" TEXT NOT NULL REFERENCES users(id), + -- the date and time this session was first encountered + "encountered" TIMESTAMPTZ NOT NULL DEFAULT current_timestamp +) \ No newline at end of file diff --git a/migrations/20220318132536_revoked_sessions.sql b/migrations/20220318132536_revoked_sessions.sql new file mode 100644 index 0000000..affcc68 --- /dev/null +++ b/migrations/20220318132536_revoked_sessions.sql @@ -0,0 +1,6 @@ +-- this table stores sessions which got revoked via backchannel logout +-- if a session is encountered and it is in this table, it will be rejected. +CREATE TABLE revoked_sessions ( + -- the `sid` claim + "id" TEXT NOT NULL PRIMARY KEY UNIQUE +) \ No newline at end of file diff --git a/src/authn.rs b/src/authn.rs new file mode 100644 index 0000000..b184659 --- /dev/null +++ b/src/authn.rs @@ -0,0 +1,2 @@ +//! Authentication with OpenID Connect +mod identity; diff --git a/src/authn/identity.rs b/src/authn/identity.rs new file mode 100644 index 0000000..ac83938 --- /dev/null +++ b/src/authn/identity.rs @@ -0,0 +1,115 @@ +use std::{collections::HashSet, hash::Hash, str::FromStr}; + +use chrono::Utc; +use openidconnect::{ + core::{ + CoreGenderClaim, CoreJsonWebKey, CoreJsonWebKeyType, CoreJsonWebKeyUse, + CoreJweContentEncryptionAlgorithm, CoreJwsSigningAlgorithm, + }, + AdditionalClaims, Audience, IdToken, IdTokenClaims, IdTokenVerifier, +}; +use serde::{Deserialize, Serialize}; +use sqlx::PgPool; + +/// A pair of an [`Identity`] and a [`Session`] +pub struct Identifier { + identity: Identity, + session: Session, +} + +impl Identifier { + /// Load an [`Identifer`] from a authentication token + pub async fn load( + token: &str, + verifier: &IdTokenVerifier< + '_, + CoreJwsSigningAlgorithm, + CoreJsonWebKeyType, + CoreJsonWebKeyUse, + CoreJsonWebKey, + >, + audiences: &HashSet, + pool: &PgPool, + ) -> anyhow::Result { + let token: IdTokenClaims = IdToken::< + Session, + CoreGenderClaim, + CoreJweContentEncryptionAlgorithm, + CoreJwsSigningAlgorithm, + CoreJsonWebKeyType, + >::from_str(token)? + .into_claims(verifier, |_: Option<&_>| Ok(()))?; + + // ensure the token is intended for us + anyhow::ensure!( + token.audiences().iter().any(|a| audiences.contains(a)), + "invalid audience" + ); + // ensure the token is not expired + anyhow::ensure!(token.expiration() > Utc::now(), "token expired"); + + // use the `preferred_username` claim as username or else fallback to + // the `sub` claim. A user can update their username later via the graphql api + let username = token + .preferred_username() + .map(|name| name.as_str()) + .unwrap_or_else(|| token.subject().as_str()); + + // if the database returns the id (one optional) + sqlx::query!( + r#" + WITH info AS ( + -- a session is considered valid if it is not in the revoked_sessions table + -- e.g. the result from this select is null + SELECT (SELECT id FROM revoked_sessions WHERE id=$1 LIMIT 1) IS NULL AS valid + ), + i AS ( + -- insert user if unknown + INSERT INTO users(id, username) VALUES ($2, $3) ON CONFLICT DO NOTHING + ), + ii AS ( + -- insert session if unknown and not revoked + INSERT INTO sessions(id, user_id) SELECT $1, $2 WHERE (SELECT valid FROM info) ON CONFLICT DO NOTHING + ) + -- select the session if it is valid / not revoked + SELECT id FROM sessions WHERE id=$1 AND (SELECT valid FROM info) + "#, + token.additional_claims().sid, + token.subject().as_str(), + username, + ) + .fetch_optional(pool) + .await? + .ok_or(anyhow::anyhow!("session revoked"))?; + + Ok(Identifier { + identity: Identity { + subject: token.subject().to_string(), + }, + session: Session { + sid: token.additional_claims().sid.to_owned(), + }, + }) + } +} + +/// The minimal information we get from the OpenID Connect provider. +#[derive(Debug, Hash, PartialEq, Eq)] +pub struct Identity { + /// `sub` claim + subject: String, +} + +/// A session is (or at least should) be bound to an installation of minkan on +/// the enduser's device. For example, if the user installed a desktop app for +/// minkan, the session should stay the same for that installation (even with +/// refresh token rotation). This allows us to keep track for how long we need +/// to store a message. +/// +/// It uses the `sid` claim in the OpenID Connect tokens. +#[derive(Debug, Deserialize, Serialize, Hash, PartialEq, Eq)] +pub struct Session { + sid: String, +} + +impl AdditionalClaims for Session {} diff --git a/src/main.rs b/src/main.rs index 43f3758..31517af 100644 --- a/src/main.rs +++ b/src/main.rs @@ -10,6 +10,7 @@ use tokio::sync::Mutex; #[macro_use] extern crate log; +mod authn; mod config; #[cfg(feature = "oidc_login")] mod oidc; @@ -38,7 +39,7 @@ async fn main() -> anyhow::Result<()> { Ok(HttpServer::new(move || { // allow this because else there's no nice way to register endpoints // based on a feature flag - #[warn(clippy::let_and_return)] + #[allow(clippy::let_and_return)] let app = App::new() .wrap(Logger::default()) // register endpoints diff --git a/src/oidc.rs b/src/oidc.rs index 14392f6..759cca2 100644 --- a/src/oidc.rs +++ b/src/oidc.rs @@ -164,9 +164,6 @@ async fn login_callback( .ok_or_else(|| InternalError::new("Missing state cookie", StatusCode::BAD_REQUEST))?; let mut response = HttpResponse::Found(); - // delete the state since they are one time use only no matter if - // the request was successful or not - response.del_cookie(&state); match oidc_response { Either::Left(info) => {