diff --git a/.sqlx/query-fdb364b8984eff1c2ca14153eaf44fa0ccc6a7e26874afecc62b00de993a12aa.json b/.sqlx/query-367204ba11a051f52d4b287eea7ca6a5c5c81a0ebc294a31c49e68e3fdbb20f0.json similarity index 83% rename from .sqlx/query-fdb364b8984eff1c2ca14153eaf44fa0ccc6a7e26874afecc62b00de993a12aa.json rename to .sqlx/query-367204ba11a051f52d4b287eea7ca6a5c5c81a0ebc294a31c49e68e3fdbb20f0.json index 9b24a3350..8b98d1ab2 100644 --- a/.sqlx/query-fdb364b8984eff1c2ca14153eaf44fa0ccc6a7e26874afecc62b00de993a12aa.json +++ b/.sqlx/query-367204ba11a051f52d4b287eea7ca6a5c5c81a0ebc294a31c49e68e3fdbb20f0.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "INSERT INTO \"settings\" (\"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\",\"smtp_user\",\"smtp_password\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32) RETURNING id", + "query": "INSERT INTO \"settings\" (\"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\",\"smtp_user\",\"smtp_password\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\",\"license\") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16,$17,$18,$19,$20,$21,$22,$23,$24,$25,$26,$27,$28,$29,$30,$31,$32,$33) RETURNING id", "describe": { "columns": [ { @@ -53,12 +53,13 @@ "Text", "Text", "Text", - "Bool" + "Bool", + "Text" ] }, "nullable": [ false ] }, - "hash": "fdb364b8984eff1c2ca14153eaf44fa0ccc6a7e26874afecc62b00de993a12aa" + "hash": "367204ba11a051f52d4b287eea7ca6a5c5c81a0ebc294a31c49e68e3fdbb20f0" } diff --git a/.sqlx/query-e769bdd845a133b817d33627fd43862607a138b42416ccb2dabfb2ea953b482f.json b/.sqlx/query-9c8efc3773f13460b73bd9d1a93839a587d727a9d036505203b4260603cf0ee6.json similarity index 90% rename from .sqlx/query-e769bdd845a133b817d33627fd43862607a138b42416ccb2dabfb2ea953b482f.json rename to .sqlx/query-9c8efc3773f13460b73bd9d1a93839a587d727a9d036505203b4260603cf0ee6.json index ff55394f7..9c3826048 100644 --- a/.sqlx/query-e769bdd845a133b817d33627fd43862607a138b42416ccb2dabfb2ea953b482f.json +++ b/.sqlx/query-9c8efc3773f13460b73bd9d1a93839a587d727a9d036505203b4260603cf0ee6.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "UPDATE \"settings\" SET \"openid_enabled\" = $2,\"wireguard_enabled\" = $3,\"webhooks_enabled\" = $4,\"worker_enabled\" = $5,\"challenge_template\" = $6,\"instance_name\" = $7,\"main_logo_url\" = $8,\"nav_logo_url\" = $9,\"smtp_server\" = $10,\"smtp_port\" = $11,\"smtp_encryption\" = $12,\"smtp_user\" = $13,\"smtp_password\" = $14,\"smtp_sender\" = $15,\"enrollment_vpn_step_optional\" = $16,\"enrollment_welcome_message\" = $17,\"enrollment_welcome_email\" = $18,\"enrollment_welcome_email_subject\" = $19,\"enrollment_use_welcome_message_as_email\" = $20,\"uuid\" = $21,\"ldap_url\" = $22,\"ldap_bind_username\" = $23,\"ldap_bind_password\" = $24,\"ldap_group_search_base\" = $25,\"ldap_user_search_base\" = $26,\"ldap_user_obj_class\" = $27,\"ldap_group_obj_class\" = $28,\"ldap_username_attr\" = $29,\"ldap_groupname_attr\" = $30,\"ldap_group_member_attr\" = $31,\"ldap_member_attr\" = $32,\"openid_create_account\" = $33 WHERE id = $1", + "query": "UPDATE \"settings\" SET \"openid_enabled\" = $2,\"wireguard_enabled\" = $3,\"webhooks_enabled\" = $4,\"worker_enabled\" = $5,\"challenge_template\" = $6,\"instance_name\" = $7,\"main_logo_url\" = $8,\"nav_logo_url\" = $9,\"smtp_server\" = $10,\"smtp_port\" = $11,\"smtp_encryption\" = $12,\"smtp_user\" = $13,\"smtp_password\" = $14,\"smtp_sender\" = $15,\"enrollment_vpn_step_optional\" = $16,\"enrollment_welcome_message\" = $17,\"enrollment_welcome_email\" = $18,\"enrollment_welcome_email_subject\" = $19,\"enrollment_use_welcome_message_as_email\" = $20,\"uuid\" = $21,\"ldap_url\" = $22,\"ldap_bind_username\" = $23,\"ldap_bind_password\" = $24,\"ldap_group_search_base\" = $25,\"ldap_user_search_base\" = $26,\"ldap_user_obj_class\" = $27,\"ldap_group_obj_class\" = $28,\"ldap_username_attr\" = $29,\"ldap_groupname_attr\" = $30,\"ldap_group_member_attr\" = $31,\"ldap_member_attr\" = $32,\"openid_create_account\" = $33,\"license\" = $34 WHERE id = $1", "describe": { "columns": [], "parameters": { @@ -48,10 +48,11 @@ "Text", "Text", "Text", - "Bool" + "Bool", + "Text" ] }, "nullable": [] }, - "hash": "e769bdd845a133b817d33627fd43862607a138b42416ccb2dabfb2ea953b482f" + "hash": "9c8efc3773f13460b73bd9d1a93839a587d727a9d036505203b4260603cf0ee6" } diff --git a/.sqlx/query-fb71770a725becd8d8f53554ded17e189c90b658aa343fc682b05be24f410b85.json b/.sqlx/query-b90afee0fbb1a4590e0e9d032e34f24ab82b04015634f99ddac9284e47b10f8d.json similarity index 95% rename from .sqlx/query-fb71770a725becd8d8f53554ded17e189c90b658aa343fc682b05be24f410b85.json rename to .sqlx/query-b90afee0fbb1a4590e0e9d032e34f24ab82b04015634f99ddac9284e47b10f8d.json index 5441c9602..4949c3e33 100644 --- a/.sqlx/query-fb71770a725becd8d8f53554ded17e189c90b658aa343fc682b05be24f410b85.json +++ b/.sqlx/query-b90afee0fbb1a4590e0e9d032e34f24ab82b04015634f99ddac9284e47b10f8d.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id \"id?\", \"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\" \"smtp_encryption: _\",\"smtp_user\",\"smtp_password\" \"smtp_password?: SecretString\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\" \"ldap_bind_password?: SecretString\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\" FROM \"settings\" WHERE id = $1", + "query": "SELECT id \"id?\", \"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\" \"smtp_encryption: _\",\"smtp_user\",\"smtp_password\" \"smtp_password?: SecretString\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\" \"ldap_bind_password?: SecretString\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\",\"license\" FROM \"settings\" WHERE id = $1", "describe": { "columns": [ { @@ -178,6 +178,11 @@ "ordinal": 32, "name": "openid_create_account", "type_info": "Bool" + }, + { + "ordinal": 33, + "name": "license", + "type_info": "Text" } ], "parameters": { @@ -218,8 +223,9 @@ true, true, true, - false + false, + true ] }, - "hash": "fb71770a725becd8d8f53554ded17e189c90b658aa343fc682b05be24f410b85" + "hash": "b90afee0fbb1a4590e0e9d032e34f24ab82b04015634f99ddac9284e47b10f8d" } diff --git a/.sqlx/query-a9d694c5efe301ef975e1b6fc0ca0acc741c16c3efdd7a92475a419e9e30db4c.json b/.sqlx/query-e626ef3ad2f23b3981f911da0c81d452f3b0e9c64f20488bf7f5d6c2fdd38a16.json similarity index 95% rename from .sqlx/query-a9d694c5efe301ef975e1b6fc0ca0acc741c16c3efdd7a92475a419e9e30db4c.json rename to .sqlx/query-e626ef3ad2f23b3981f911da0c81d452f3b0e9c64f20488bf7f5d6c2fdd38a16.json index 83250222b..3d8c67150 100644 --- a/.sqlx/query-a9d694c5efe301ef975e1b6fc0ca0acc741c16c3efdd7a92475a419e9e30db4c.json +++ b/.sqlx/query-e626ef3ad2f23b3981f911da0c81d452f3b0e9c64f20488bf7f5d6c2fdd38a16.json @@ -1,6 +1,6 @@ { "db_name": "PostgreSQL", - "query": "SELECT id \"id?\", \"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\" \"smtp_encryption: _\",\"smtp_user\",\"smtp_password\" \"smtp_password?: SecretString\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\" \"ldap_bind_password?: SecretString\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\" FROM \"settings\"", + "query": "SELECT id \"id?\", \"openid_enabled\",\"wireguard_enabled\",\"webhooks_enabled\",\"worker_enabled\",\"challenge_template\",\"instance_name\",\"main_logo_url\",\"nav_logo_url\",\"smtp_server\",\"smtp_port\",\"smtp_encryption\" \"smtp_encryption: _\",\"smtp_user\",\"smtp_password\" \"smtp_password?: SecretString\",\"smtp_sender\",\"enrollment_vpn_step_optional\",\"enrollment_welcome_message\",\"enrollment_welcome_email\",\"enrollment_welcome_email_subject\",\"enrollment_use_welcome_message_as_email\",\"uuid\",\"ldap_url\",\"ldap_bind_username\",\"ldap_bind_password\" \"ldap_bind_password?: SecretString\",\"ldap_group_search_base\",\"ldap_user_search_base\",\"ldap_user_obj_class\",\"ldap_group_obj_class\",\"ldap_username_attr\",\"ldap_groupname_attr\",\"ldap_group_member_attr\",\"ldap_member_attr\",\"openid_create_account\",\"license\" FROM \"settings\"", "describe": { "columns": [ { @@ -178,6 +178,11 @@ "ordinal": 32, "name": "openid_create_account", "type_info": "Bool" + }, + { + "ordinal": 33, + "name": "license", + "type_info": "Text" } ], "parameters": { @@ -216,8 +221,9 @@ true, true, true, - false + false, + true ] }, - "hash": "a9d694c5efe301ef975e1b6fc0ca0acc741c16c3efdd7a92475a419e9e30db4c" + "hash": "e626ef3ad2f23b3981f911da0c81d452f3b0e9c64f20488bf7f5d6c2fdd38a16" } diff --git a/Cargo.lock b/Cargo.lock index adfce2fc4..22f885608 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -483,6 +483,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bitfield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d7e60934ceec538daadb9d8432424ed043a904d8e0243f3c6446bce549a46ac" + [[package]] name = "bitflags" version = "1.3.2" @@ -528,6 +534,25 @@ dependencies = [ "generic-array", ] +[[package]] +name = "block-padding" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8894febbff9f758034a5b8e12d87918f56dfc64a8e1fe757d65e29041538d93" +dependencies = [ + "generic-array", +] + +[[package]] +name = "blowfish" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e412e2cd0f2b2d93e02543ceae7917b3c70331573df19ee046bcbc35e45e87d7" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "bstr" version = "1.10.0" @@ -538,6 +563,15 @@ dependencies = [ "serde", ] +[[package]] +name = "buffer-redux" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c9f8ddd22e0a12391d1e7ada69ec3b0da1914f1cec39c5cf977143c5b2854f5" +dependencies = [ + "memchr", +] + [[package]] name = "bumpalo" version = "3.16.0" @@ -565,12 +599,40 @@ dependencies = [ "serde", ] +[[package]] +name = "camellia" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3264e2574e9ef2b53ce6f536dea83a69ac0bc600b762d1523ff83fe07230ce30" +dependencies = [ + "byteorder", + "cipher", +] + +[[package]] +name = "cast5" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b07d673db1ccf000e90f54b819db9e75a8348d6eb056e9b8ab53231b7a9911" +dependencies = [ + "cipher", +] + [[package]] name = "cc" version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9e8aabfac534be767c909e0690571677d49f41bd8465ae876fe043d52ba5292" +[[package]] +name = "cfb-mode" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "738b8d467867f80a71351933f70461f5b56f24d5c93e0cf216e59229c968d330" +dependencies = [ + "cipher", +] + [[package]] name = "cfg-if" version = "1.0.0" @@ -683,6 +745,17 @@ version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +[[package]] +name = "cmac" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8543454e3c3f5126effff9cd44d562af4e31fb8ce1cc0d3dcd8f084515dbc1aa" +dependencies = [ + "cipher", + "dbl", + "digest", +] + [[package]] name = "colorchoice" version = "1.0.2" @@ -834,6 +907,12 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crc24" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd121741cf3eb82c08dd3023eb55bf2665e5f60ec20f89760cf836ae4562e6a0" + [[package]] name = "crc32fast" version = "1.4.2" @@ -983,6 +1062,15 @@ version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" +[[package]] +name = "dbl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd2735a791158376708f9347fe8faba9667589d82427ef3aed6794a8981de3d9" +dependencies = [ + "generic-array", +] + [[package]] name = "defguard" version = "0.11.0" @@ -1010,6 +1098,7 @@ dependencies = [ "mime_guess", "model_derive", "openidconnect", + "pgp", "prost", "prost-build", "pulldown-cmark", @@ -1100,6 +1189,37 @@ dependencies = [ "syn 2.0.74", ] +[[package]] +name = "derive_builder" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0350b5cb0331628a5916d6c5c0b72e97393b8b6b03b47a9284f4e7f5a405ffd7" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d48cda787f839151732d396ac69e3473923d54312c070ee21e9effcaa8ca0b1d" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206868b8242f27cecce124c19fd88157fbd0dd334df2587f36417bafbc85097b" +dependencies = [ + "derive_builder_core", + "syn 2.0.74", +] + [[package]] name = "derive_more" version = "0.99.18" @@ -1113,6 +1233,15 @@ dependencies = [ "syn 2.0.74", ] +[[package]] +name = "des" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffdd80ce8ce993de27e9f063a444a4d53ce8e8db4c1f00cc03af5ad5a9867a1e" +dependencies = [ + "cipher", +] + [[package]] name = "deunicode" version = "1.6.0" @@ -1157,12 +1286,41 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "dsa" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48bc224a9084ad760195584ce5abb3c2c34a225fa312a128ad245a6b412b7689" +dependencies = [ + "digest", + "num-bigint-dig", + "num-traits", + "pkcs8", + "rfc6979", + "sha2", + "signature", + "zeroize", +] + [[package]] name = "dyn-clone" version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125" +[[package]] +name = "eax" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9954fabd903b82b9d7a68f65f97dc96dd9ad368e40ccc907a7c19d53e6bfac28" +dependencies = [ + "aead", + "cipher", + "cmac", + "ctr", + "subtle", +] + [[package]] name = "ecdsa" version = "0.16.9" @@ -2027,6 +2185,15 @@ dependencies = [ "cc", ] +[[package]] +name = "idea" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "075557004419d7f2031b8bb7f44bb43e55a83ca7b63076a8fb8fe75753836477" +dependencies = [ + "cipher", +] + [[package]] name = "ident_case" version = "1.0.1" @@ -2159,6 +2326,12 @@ version = "1.70.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +[[package]] +name = "iter-read" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a598c1abae8e3456ebda517868b254b6bc2a9bb6501ffd5b9d0875bf332e048b" + [[package]] name = "itertools" version = "0.10.5" @@ -2218,6 +2391,7 @@ dependencies = [ "elliptic-curve", "once_cell", "sha2", + "signature", ] [[package]] @@ -2514,6 +2688,7 @@ dependencies = [ "num-iter", "num-traits", "rand", + "serde", "smallvec", "zeroize", ] @@ -2615,6 +2790,18 @@ dependencies = [ "memchr", ] +[[package]] +name = "ocb3" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c196e0276c471c843dd5777e7543a36a298a4be942a2a688d8111cd43390dedb" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + [[package]] name = "oid-registry" version = "0.4.0" @@ -2955,6 +3142,70 @@ dependencies = [ "indexmap 2.3.0", ] +[[package]] +name = "pgp" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aeab6e08a63a51a29a65e461d0b6fd0f8d350914712ec43773ca22ed51d5501c" +dependencies = [ + "aes", + "aes-gcm", + "argon2", + "base64 0.22.1", + "bitfield", + "block-padding", + "blowfish", + "bstr", + "buffer-redux", + "byteorder", + "camellia", + "cast5", + "cfb-mode", + "chrono", + "cipher", + "const-oid", + "crc24", + "curve25519-dalek", + "derive_builder", + "des", + "digest", + "dsa", + "eax", + "ecdsa", + "ed25519-dalek", + "elliptic-curve", + "flate2", + "generic-array", + "hex", + "hkdf", + "idea", + "iter-read", + "k256", + "log", + "md-5", + "nom", + "num-bigint-dig", + "num-traits", + "num_enum", + "ocb3", + "p256", + "p384", + "p521", + "rand", + "ripemd", + "rsa", + "sha1", + "sha1-checked", + "sha2", + "sha3", + "signature", + "smallvec", + "thiserror", + "twofish", + "x25519-dalek", + "zeroize", +] + [[package]] name = "phf" version = "0.11.2" @@ -3554,6 +3805,15 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "ripemd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd124222d17ad93a644ed9d011a40f4fb64aa54275c08cc216524a9ea82fb09f" +dependencies = [ + "digest", +] + [[package]] name = "rlp" version = "0.5.2" @@ -4100,6 +4360,16 @@ dependencies = [ "digest", ] +[[package]] +name = "sha1-checked" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89f599ac0c323ebb1c6082821a54962b839832b03984598375bff3975b804423" +dependencies = [ + "digest", + "sha1", +] + [[package]] name = "sha2" version = "0.10.8" @@ -5062,6 +5332,15 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" +[[package]] +name = "twofish" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a78e83a30223c757c3947cd144a31014ff04298d8719ae10d03c31c0448c8013" +dependencies = [ + "cipher", +] + [[package]] name = "typenum" version = "1.17.0" diff --git a/Cargo.toml b/Cargo.toml index a5317a6e6..9372576f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,7 @@ model_derive = { path = "model-derive" } openidconnect = { version = "3.5", default-features = false, optional = true, features = [ "reqwest", ] } +pgp = "0.13" prost = "0.12" pulldown-cmark = "0.11" rand = "0.8" @@ -88,11 +89,15 @@ tokio = { version = "1", features = [ ] } tokio-stream = "0.1" tonic = { version = "0.11", features = ["gzip", "tls", "tls-roots"] } +tonic-health = "0.11" totp-lite = { version = "2.0" } tower-http = { version = "0.5", features = ["fs", "trace"] } tracing = "0.1" tracing-subscriber = { version = "0.3", features = ["env-filter"] } uaparser = "0.6" +# openapi +utoipa = { version = "4", features = ["axum_extras"] } +utoipa-swagger-ui = { version = "7", features = ["axum"] } uuid = { version = "1.9", features = ["v4"] } webauthn-authenticator-rs = { version = "0.5" } webauthn-rs = { version = "0.5", features = [ @@ -100,10 +105,6 @@ webauthn-rs = { version = "0.5", features = [ ] } webauthn-rs-proto = "0.5" x25519-dalek = { version = "2.0", features = ["static_secrets"] } -# openapi -utoipa = { version = "4", features = ["axum_extras"] } -utoipa-swagger-ui = { version = "7", features = ["axum"] } -tonic-health = "0.11" [dev-dependencies] bytes = "1.6" diff --git a/build.rs b/build.rs index 1fda0abc2..334ce9cb4 100644 --- a/build.rs +++ b/build.rs @@ -7,10 +7,16 @@ fn main() -> Result<(), Box> { "proto/core/auth.proto", "proto/core/proxy.proto", "proto/core/vpn.proto", + "src/enterprise/proto/license.proto", "proto/worker/worker.proto", "proto/wireguard/gateway.proto", ], - &["proto/core", "proto/worker", "proto/wireguard"], + &[ + "proto/core", + "proto/worker", + "proto/wireguard", + "src/enterprise/proto", + ], )?; println!("cargo:rerun-if-changed=proto"); println!("cargo:rerun-if-changed=migrations"); diff --git a/e2e/pnpm-lock.yaml b/e2e/pnpm-lock.yaml index 40171809c..b4f041267 100644 --- a/e2e/pnpm-lock.yaml +++ b/e2e/pnpm-lock.yaml @@ -1,96 +1,1107 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: - '@faker-js/faker': - specifier: ^8.0.2 - version: 8.0.2 - '@playwright/test': - specifier: ^1.32.3 - version: 1.32.3 - '@scure/base': - specifier: ^1.1.3 - version: 1.1.3 - '@types/lodash': - specifier: ^4.14.195 - version: 4.14.195 - '@types/pg': - specifier: ^8.10.9 - version: 8.10.9 - axios: - specifier: ^1.4.0 - version: 1.4.0 - dotenv: - specifier: ^16.0.3 - version: 16.0.3 - lodash: - specifier: ^4.17.21 - version: 4.17.21 - pg: - specifier: ^8.11.3 - version: 8.11.3 - playwright: - specifier: ^1.32.3 - version: 1.32.3 - totp-generator: - specifier: ^0.0.14 - version: 0.0.14 - -devDependencies: - '@types/node': - specifier: ^18.16.0 - version: 18.16.0 - '@types/totp-generator': - specifier: ^0.0.5 - version: 0.0.5 - '@typescript-eslint/eslint-plugin': - specifier: ^5.59.0 - version: 5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.39.0)(typescript@5.0.4) - '@typescript-eslint/parser': - specifier: ^5.59.0 - version: 5.59.0(eslint@8.39.0)(typescript@5.0.4) - eslint: - specifier: ^8.39.0 - version: 8.39.0 - eslint-config-prettier: - specifier: ^8.8.0 - version: 8.8.0(eslint@8.39.0) - eslint-plugin-import: - specifier: ^2.27.5 - version: 2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.39.0) - eslint-plugin-prettier: - specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.39.0)(prettier@2.8.8) - eslint-plugin-simple-import-sort: - specifier: ^10.0.0 - version: 10.0.0(eslint@8.39.0) - prettier: - specifier: ^2.8.8 - version: 2.8.8 +importers: + + .: + dependencies: + '@faker-js/faker': + specifier: ^8.0.2 + version: 8.0.2 + '@playwright/test': + specifier: ^1.32.3 + version: 1.32.3 + '@scure/base': + specifier: ^1.1.3 + version: 1.1.3 + '@types/lodash': + specifier: ^4.14.195 + version: 4.14.195 + '@types/pg': + specifier: ^8.10.9 + version: 8.10.9 + axios: + specifier: ^1.4.0 + version: 1.4.0 + dotenv: + specifier: ^16.0.3 + version: 16.0.3 + lodash: + specifier: ^4.17.21 + version: 4.17.21 + pg: + specifier: ^8.11.3 + version: 8.11.3 + playwright: + specifier: ^1.32.3 + version: 1.32.3 + totp-generator: + specifier: ^0.0.14 + version: 0.0.14 + devDependencies: + '@types/node': + specifier: ^18.16.0 + version: 18.16.0 + '@types/totp-generator': + specifier: ^0.0.5 + version: 0.0.5 + '@typescript-eslint/eslint-plugin': + specifier: ^5.59.0 + version: 5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.39.0)(typescript@5.0.4) + '@typescript-eslint/parser': + specifier: ^5.59.0 + version: 5.59.0(eslint@8.39.0)(typescript@5.0.4) + eslint: + specifier: ^8.39.0 + version: 8.39.0 + eslint-config-prettier: + specifier: ^8.8.0 + version: 8.8.0(eslint@8.39.0) + eslint-plugin-import: + specifier: ^2.27.5 + version: 2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.39.0) + eslint-plugin-prettier: + specifier: ^4.2.1 + version: 4.2.1(eslint-config-prettier@8.8.0)(eslint@8.39.0)(prettier@2.8.8) + eslint-plugin-simple-import-sort: + specifier: ^10.0.0 + version: 10.0.0(eslint@8.39.0) + prettier: + specifier: ^2.8.8 + version: 2.8.8 packages: - /@eslint-community/eslint-utils@4.4.0(eslint@8.39.0): + '@eslint-community/eslint-utils@4.4.0': resolution: {integrity: sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.5.0': + resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.0.2': + resolution: {integrity: sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.39.0': + resolution: {integrity: sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@faker-js/faker@8.0.2': + resolution: {integrity: sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} + + '@humanwhocodes/config-array@0.11.8': + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} + engines: {node: '>=10.10.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@1.2.1': + resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@playwright/test@1.32.3': + resolution: {integrity: sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==} + engines: {node: '>=14'} + hasBin: true + + '@scure/base@1.1.3': + resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==} + + '@types/json-schema@7.0.11': + resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} + + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + + '@types/lodash@4.14.195': + resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==} + + '@types/node@18.16.0': + resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==} + + '@types/pg@8.10.9': + resolution: {integrity: sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ==} + + '@types/semver@7.3.13': + resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} + + '@types/totp-generator@0.0.5': + resolution: {integrity: sha512-ryo6U5lfQg2/7pNQnpEXG49EPX7/cmRi/FX7sPBYO7QVJf0z6turM3km3w+98mpqlM4E+vkoOrN+gcjqCBmX0g==} + + '@typescript-eslint/eslint-plugin@5.59.0': + resolution: {integrity: sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + '@typescript-eslint/parser': ^5.0.0 + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@5.59.0': + resolution: {integrity: sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@5.59.0': + resolution: {integrity: sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/type-utils@5.59.0': + resolution: {integrity: sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@5.59.0': + resolution: {integrity: sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/typescript-estree@5.59.0': + resolution: {integrity: sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@5.59.0': + resolution: {integrity: sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@5.59.0': + resolution: {integrity: sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.8.2: + resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-buffer-byte-length@1.0.0: + resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + + array-includes@3.1.6: + resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} + engines: {node: '>= 0.4'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + array.prototype.flat@1.3.1: + resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.1: + resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} + engines: {node: '>= 0.4'} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + available-typed-arrays@1.0.5: + resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} + engines: {node: '>= 0.4'} + + axios@1.4.0: + resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + + buffer-writer@2.0.0: + resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} + engines: {node: '>=4'} + + call-bind@1.0.2: + resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + cross-spawn@7.0.3: + resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} + engines: {node: '>= 8'} + + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + define-properties@1.2.0: + resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} + engines: {node: '>= 0.4'} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dotenv@16.0.3: + resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} + engines: {node: '>=12'} + + es-abstract@1.21.2: + resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.0.1: + resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} + engines: {node: '>= 0.4'} + + es-shim-unscopables@1.0.0: + resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + + es-to-primitive@1.2.1: + resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} + engines: {node: '>= 0.4'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-config-prettier@8.8.0: + resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} + hasBin: true + peerDependencies: + eslint: '>=7.0.0' + + eslint-import-resolver-node@0.3.7: + resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + + eslint-module-utils@2.8.0: + resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + + eslint-plugin-import@2.27.5: + resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + + eslint-plugin-prettier@4.2.1: + resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} + engines: {node: '>=12.0.0'} + peerDependencies: + eslint: '>=7.28.0' + eslint-config-prettier: '*' + prettier: '>=2.0.0' + peerDependenciesMeta: + eslint-config-prettier: + optional: true + + eslint-plugin-simple-import-sort@10.0.0: + resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@7.2.0: + resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.0: + resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.39.0: + resolution: {integrity: sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + hasBin: true + + espree@9.5.1: + resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.5.0: + resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.2.0: + resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} + + fast-glob@3.2.12: + resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fastq@1.15.0: + resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@3.0.4: + resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.2.7: + resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} + + follow-redirects@1.15.2: + resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + for-each@0.3.3: + resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + + form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.1: + resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} + + function.prototype.name@1.1.5: + resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} + engines: {node: '>= 0.4'} + + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + + get-intrinsic@1.2.0: + resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + + get-symbol-description@1.0.0: + resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} + engines: {node: '>= 0.4'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + + globals@13.20.0: + resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} + engines: {node: '>=8'} + + globalthis@1.0.3: + resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} + engines: {node: '>= 0.4'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + + grapheme-splitter@1.0.4: + resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} + + has-bigints@1.0.2: + resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.0: + resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + + has-proto@1.0.1: + resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} + engines: {node: '>= 0.4'} + + has-symbols@1.0.3: + resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.0: + resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} + engines: {node: '>= 0.4'} + + has@1.0.3: + resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} + engines: {node: '>= 0.4.0'} + + ignore@5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} + engines: {node: '>= 4'} + + import-fresh@3.3.0: + resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + internal-slot@1.0.5: + resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} + engines: {node: '>= 0.4'} + + is-array-buffer@3.0.2: + resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + + is-bigint@1.0.4: + resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + + is-boolean-object@1.1.2: + resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} + engines: {node: '>= 0.4'} + + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} + + is-core-module@2.12.0: + resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} + + is-date-object@1.0.5: + resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-negative-zero@2.0.2: + resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} + engines: {node: '>= 0.4'} + + is-number-object@1.0.7: + resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} + engines: {node: '>= 0.4'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-regex@1.1.4: + resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} + engines: {node: '>= 0.4'} + + is-shared-array-buffer@1.0.2: + resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + + is-string@1.0.7: + resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} + engines: {node: '>= 0.4'} + + is-symbol@1.0.4: + resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} + engines: {node: '>= 0.4'} + + is-typed-array@1.1.10: + resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} + engines: {node: '>= 0.4'} + + is-weakref@1.0.2: + resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + js-sdsl@4.4.0: + resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} + hasBin: true + + jssha@3.3.0: + resolution: {integrity: sha512-w9OtT4ALL+fbbwG3gw7erAO0jvS5nfvrukGPMWIAoea359B26ALXGpzy4YJSp9yGnpUvuvOw1nSjSoHDfWSr1w==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.5: + resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + object-inspect@1.12.3: + resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + object.assign@4.1.4: + resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} + engines: {node: '>= 0.4'} + + object.values@1.1.6: + resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} + engines: {node: '>= 0.4'} + + obuf@1.1.2: + resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + optionator@0.9.1: + resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + packet-reader@1.0.0: + resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pg-cloudflare@1.1.1: + resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} + + pg-connection-string@2.6.2: + resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + + pg-int8@1.0.1: + resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} + engines: {node: '>=4.0.0'} + + pg-numeric@1.0.2: + resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} + engines: {node: '>=4'} + + pg-pool@3.6.1: + resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + peerDependencies: + pg: '>=8.0' + + pg-protocol@1.6.0: + resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + + pg-types@2.2.0: + resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} + engines: {node: '>=4'} + + pg-types@4.0.1: + resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==} + engines: {node: '>=10'} + + pg@8.11.3: + resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + engines: {node: '>= 8.0.0'} + peerDependencies: + pg-native: '>=3.0.1' + peerDependenciesMeta: + pg-native: + optional: true + + pgpass@1.0.5: + resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + playwright-core@1.32.3: + resolution: {integrity: sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==} + engines: {node: '>=14'} + hasBin: true + + playwright@1.32.3: + resolution: {integrity: sha512-h/ylpgoj6l/EjkfUDyx8cdOlfzC96itPpPe8BXacFkqpw/YsuxkpPyVbzEq4jw+bAJh5FLgh31Ljg2cR6HV3uw==} + engines: {node: '>=14'} + hasBin: true + + postgres-array@2.0.0: + resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} + engines: {node: '>=4'} + + postgres-array@3.0.2: + resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} + engines: {node: '>=12'} + + postgres-bytea@1.0.0: + resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} + engines: {node: '>=0.10.0'} + + postgres-bytea@3.0.0: + resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} + engines: {node: '>= 6'} + + postgres-date@1.0.7: + resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} + engines: {node: '>=0.10.0'} + + postgres-date@2.0.1: + resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==} + engines: {node: '>=12'} + + postgres-interval@1.2.0: + resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} + engines: {node: '>=0.10.0'} + + postgres-interval@3.0.0: + resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} + engines: {node: '>=12'} + + postgres-range@1.1.3: + resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@2.8.8: + resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} + engines: {node: '>=10.13.0'} + hasBin: true + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.0: + resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + regexp.prototype.flags@1.5.0: + resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} + engines: {node: '>= 0.4'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve@1.22.2: + resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} + hasBin: true + + reusify@1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-regex-test@1.0.0: + resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + + semver@6.3.0: + resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true + + semver@7.5.0: + resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel@1.0.4: + resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} + + string.prototype.trim@1.2.7: + resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} + engines: {node: '>= 0.4'} + + string.prototype.trimend@1.0.6: + resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + + string.prototype.trimstart@1.0.6: + resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + totp-generator@0.0.14: + resolution: {integrity: sha512-vFZ8N2TdF4mCj8bUW460jI73LqS+JKccsZ8cttQSuXa3dkTmZo8q81Pq2yAuiPxCI5fPfUrfaKuU+7adjx5s4w==} + + tsconfig-paths@3.14.2: + resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + typed-array-length@1.0.4: + resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + + typescript@5.0.4: + resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} + engines: {node: '>=12.20'} + hasBin: true + + unbox-primitive@1.0.2: + resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + which-boxed-primitive@1.0.2: + resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + + which-typed-array@1.1.9: + resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} + engines: {node: '>= 0.4'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.3: + resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} + engines: {node: '>=0.10.0'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@eslint-community/eslint-utils@4.4.0(eslint@8.39.0)': dependencies: eslint: 8.39.0 eslint-visitor-keys: 3.4.0 - dev: true - /@eslint-community/regexpp@4.5.0: - resolution: {integrity: sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true + '@eslint-community/regexpp@4.5.0': {} - /@eslint/eslintrc@2.0.2: - resolution: {integrity: sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@eslint/eslintrc@2.0.2': dependencies: ajv: 6.12.6 debug: 4.3.4 @@ -103,115 +1114,63 @@ packages: strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - dev: true - /@eslint/js@8.39.0: - resolution: {integrity: sha512-kf9RB0Fg7NZfap83B3QOqOGg9QmD9yBudqQXzzOtn3i4y7ZUXe5ONeW34Gwi+TxhH4mvj72R1Zc300KUMa9Bng==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@eslint/js@8.39.0': {} - /@faker-js/faker@8.0.2: - resolution: {integrity: sha512-Uo3pGspElQW91PCvKSIAXoEgAUlRnH29sX2/p89kg7sP1m2PzCufHINd0FhTXQf6DYGiUlVncdSPa2F9wxed2A==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0, npm: '>=6.14.13'} - dev: false + '@faker-js/faker@8.0.2': {} - /@humanwhocodes/config-array@0.11.8: - resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} - engines: {node: '>=10.10.0'} + '@humanwhocodes/config-array@0.11.8': dependencies: '@humanwhocodes/object-schema': 1.2.1 debug: 4.3.4 minimatch: 3.1.2 transitivePeerDependencies: - supports-color - dev: true - /@humanwhocodes/module-importer@1.0.1: - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - dev: true + '@humanwhocodes/module-importer@1.0.1': {} - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} - dev: true + '@humanwhocodes/object-schema@1.2.1': {} - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: true - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true + '@nodelib/fs.stat@2.0.5': {} - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} + '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - dev: true - /@playwright/test@1.32.3: - resolution: {integrity: sha512-BvWNvK0RfBriindxhLVabi8BRe3X0J9EVjKlcmhxjg4giWBD/xleLcg2dz7Tx0agu28rczjNIPQWznwzDwVsZQ==} - engines: {node: '>=14'} - hasBin: true + '@playwright/test@1.32.3': dependencies: '@types/node': 18.16.0 playwright-core: 1.32.3 optionalDependencies: fsevents: 2.3.2 - dev: false - /@scure/base@1.1.3: - resolution: {integrity: sha512-/+SgoRjLq7Xlf0CWuLHq2LUZeL/w65kfzAPG5NH9pcmBhs+nunQTn4gvdwgMTIXnt9b2C/1SeL2XiysZEyIC9Q==} - dev: false + '@scure/base@1.1.3': {} - /@types/json-schema@7.0.11: - resolution: {integrity: sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==} - dev: true + '@types/json-schema@7.0.11': {} - /@types/json5@0.0.29: - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - dev: true + '@types/json5@0.0.29': {} - /@types/lodash@4.14.195: - resolution: {integrity: sha512-Hwx9EUgdwf2GLarOjQp5ZH8ZmblzcbTBC2wtQWNKARBSxM9ezRIAUpeDTgoQRAFB0+8CNWXVA9+MaSOzOF3nPg==} - dev: false + '@types/lodash@4.14.195': {} - /@types/node@18.16.0: - resolution: {integrity: sha512-BsAaKhB+7X+H4GnSjGhJG9Qi8Tw+inU9nJDwmD5CgOmBLEI6ArdhikpLX7DjbjDRDTbqZzU2LSQNZg8WGPiSZQ==} + '@types/node@18.16.0': {} - /@types/pg@8.10.9: - resolution: {integrity: sha512-UksbANNE/f8w0wOMxVKKIrLCbEMV+oM1uKejmwXr39olg4xqcfBDbXxObJAt6XxHbDa4XTKOlUEcEltXDX+XLQ==} + '@types/pg@8.10.9': dependencies: '@types/node': 18.16.0 pg-protocol: 1.6.0 pg-types: 4.0.1 - dev: false - /@types/semver@7.3.13: - resolution: {integrity: sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==} - dev: true + '@types/semver@7.3.13': {} - /@types/totp-generator@0.0.5: - resolution: {integrity: sha512-ryo6U5lfQg2/7pNQnpEXG49EPX7/cmRi/FX7sPBYO7QVJf0z6turM3km3w+98mpqlM4E+vkoOrN+gcjqCBmX0g==} - dev: true + '@types/totp-generator@0.0.5': {} - /@typescript-eslint/eslint-plugin@5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.39.0)(typescript@5.0.4): - resolution: {integrity: sha512-p0QgrEyrxAWBecR56gyn3wkG15TJdI//eetInP3zYRewDh0XS+DhB3VUAd3QqvziFsfaQIoIuZMxZRB7vXYaYw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - '@typescript-eslint/parser': ^5.0.0 - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/eslint-plugin@5.59.0(@typescript-eslint/parser@5.59.0)(eslint@8.39.0)(typescript@5.0.4)': dependencies: '@eslint-community/regexpp': 4.5.0 '@typescript-eslint/parser': 5.59.0(eslint@8.39.0)(typescript@5.0.4) @@ -228,17 +1187,8 @@ packages: typescript: 5.0.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/parser@5.59.0(eslint@8.39.0)(typescript@5.0.4): - resolution: {integrity: sha512-qK9TZ70eJtjojSUMrrEwA9ZDQ4N0e/AuoOIgXuNBorXYcBDk397D2r5MIe1B3cok/oCtdNC5j+lUUpVB+Dpb+w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/parser@5.59.0(eslint@8.39.0)(typescript@5.0.4)': dependencies: '@typescript-eslint/scope-manager': 5.59.0 '@typescript-eslint/types': 5.59.0 @@ -248,25 +1198,13 @@ packages: typescript: 5.0.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/scope-manager@5.59.0: - resolution: {integrity: sha512-tsoldKaMh7izN6BvkK6zRMINj4Z2d6gGhO2UsI8zGZY3XhLq1DndP3Ycjhi1JwdwPRwtLMW4EFPgpuKhbCGOvQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/scope-manager@5.59.0': dependencies: '@typescript-eslint/types': 5.59.0 '@typescript-eslint/visitor-keys': 5.59.0 - dev: true - /@typescript-eslint/type-utils@5.59.0(eslint@8.39.0)(typescript@5.0.4): - resolution: {integrity: sha512-d/B6VSWnZwu70kcKQSCqjcXpVH+7ABKH8P1KNn4K7j5PXXuycZTPXF44Nui0TEm6rbWGi8kc78xRgOC4n7xFgA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/type-utils@5.59.0(eslint@8.39.0)(typescript@5.0.4)': dependencies: '@typescript-eslint/typescript-estree': 5.59.0(typescript@5.0.4) '@typescript-eslint/utils': 5.59.0(eslint@8.39.0)(typescript@5.0.4) @@ -276,21 +1214,10 @@ packages: typescript: 5.0.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/types@5.59.0: - resolution: {integrity: sha512-yR2h1NotF23xFFYKHZs17QJnB51J/s+ud4PYU4MqdZbzeNxpgUr05+dNeCN/bb6raslHvGdd6BFCkVhpPk/ZeA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + '@typescript-eslint/types@5.59.0': {} - /@typescript-eslint/typescript-estree@5.59.0(typescript@5.0.4): - resolution: {integrity: sha512-sUNnktjmI8DyGzPdZ8dRwW741zopGxltGs/SAPgGL/AAgDpiLsCFLcMNSpbfXfmnNeHmK9h3wGmCkGRGAoUZAg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + '@typescript-eslint/typescript-estree@5.59.0(typescript@5.0.4)': dependencies: '@typescript-eslint/types': 5.59.0 '@typescript-eslint/visitor-keys': 5.59.0 @@ -302,13 +1229,8 @@ packages: typescript: 5.0.4 transitivePeerDependencies: - supports-color - dev: true - /@typescript-eslint/utils@5.59.0(eslint@8.39.0)(typescript@5.0.4): - resolution: {integrity: sha512-GGLFd+86drlHSvPgN/el6dRQNYYGOvRSDVydsUaQluwIW3HvbXuxyuD5JETvBt/9qGYe+lOrDk6gRrWOHb/FvA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@typescript-eslint/utils@5.59.0(eslint@8.39.0)(typescript@5.0.4)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.39.0) '@types/json-schema': 7.0.11 @@ -322,260 +1244,149 @@ packages: transitivePeerDependencies: - supports-color - typescript - dev: true - /@typescript-eslint/visitor-keys@5.59.0: - resolution: {integrity: sha512-qZ3iXxQhanchCeaExlKPV3gDQFxMUmU35xfd5eCXB6+kUw1TUAbIy2n7QIrwz9s98DQLzNWyHp61fY0da4ZcbA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/visitor-keys@5.59.0': dependencies: '@typescript-eslint/types': 5.59.0 eslint-visitor-keys: 3.4.0 - dev: true - /acorn-jsx@5.3.2(acorn@8.8.2): - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + acorn-jsx@5.3.2(acorn@8.8.2): dependencies: acorn: 8.8.2 - dev: true - /acorn@8.8.2: - resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==} - engines: {node: '>=0.4.0'} - hasBin: true - dev: true + acorn@8.8.2: {} - /ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 json-schema-traverse: 0.4.1 uri-js: 4.4.1 - dev: true - /ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - dev: true + ansi-regex@5.0.1: {} - /ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 - dev: true - /argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true + argparse@2.0.1: {} - /array-buffer-byte-length@1.0.0: - resolution: {integrity: sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A==} + array-buffer-byte-length@1.0.0: dependencies: call-bind: 1.0.2 is-array-buffer: 3.0.2 - dev: true - /array-includes@3.1.6: - resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} - engines: {node: '>= 0.4'} + array-includes@3.1.6: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 get-intrinsic: 1.2.0 is-string: 1.0.7 - dev: true - /array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - dev: true + array-union@2.1.0: {} - /array.prototype.flat@1.3.1: - resolution: {integrity: sha512-roTU0KWIOmJ4DRLmwKd19Otg0/mT3qPNt0Qb3GWW8iObuZXxrjB/pzn0R3hqpRSWg4HCwqx+0vwOnWnvlOyeIA==} - engines: {node: '>= 0.4'} + array.prototype.flat@1.3.1: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 es-shim-unscopables: 1.0.0 - dev: true - /array.prototype.flatmap@1.3.1: - resolution: {integrity: sha512-8UGn9O1FDVvMNB0UlLv4voxRMze7+FpHyF5mSMRjWHUMlpoDViniy05870VlxhfgTnLbpuwTzvD76MTtWxB/mQ==} - engines: {node: '>= 0.4'} + array.prototype.flatmap@1.3.1: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 es-shim-unscopables: 1.0.0 - dev: true - /asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false + asynckit@0.4.0: {} - /available-typed-arrays@1.0.5: - resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==} - engines: {node: '>= 0.4'} - dev: true + available-typed-arrays@1.0.5: {} - /axios@1.4.0: - resolution: {integrity: sha512-S4XCWMEmzvo64T9GfvQDOXgYRDJ/wsSZc7Jvdgx5u1sd0JwsuPLqb3SYmusag+edF6ziyMensPVqLTSc1PiSEA==} + axios@1.4.0: dependencies: follow-redirects: 1.15.2 form-data: 4.0.0 proxy-from-env: 1.1.0 transitivePeerDependencies: - debug - dev: false - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true + balanced-match@1.0.2: {} - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + brace-expansion@1.1.11: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - dev: true - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} + braces@3.0.2: dependencies: fill-range: 7.0.1 - dev: true - /buffer-writer@2.0.0: - resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} - engines: {node: '>=4'} - dev: false + buffer-writer@2.0.0: {} - /call-bind@1.0.2: - resolution: {integrity: sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==} + call-bind@1.0.2: dependencies: function-bind: 1.1.1 get-intrinsic: 1.2.0 - dev: true - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true + callsites@3.1.0: {} - /chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - dev: true - /color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + color-convert@2.0.1: dependencies: color-name: 1.1.4 - dev: true - /color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true + color-name@1.1.4: {} - /combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 - dev: false - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true + concat-map@0.0.1: {} - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} + cross-spawn@7.0.3: dependencies: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: true - /debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@3.2.7: dependencies: ms: 2.1.3 - dev: true - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true + debug@4.3.4: dependencies: ms: 2.1.2 - dev: true - /deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true + deep-is@0.1.4: {} - /define-properties@1.2.0: - resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==} - engines: {node: '>= 0.4'} + define-properties@1.2.0: dependencies: has-property-descriptors: 1.0.0 object-keys: 1.1.1 - dev: true - /delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - dev: false + delayed-stream@1.0.0: {} - /dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + dir-glob@3.0.1: dependencies: path-type: 4.0.0 - dev: true - /doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + doctrine@2.1.0: dependencies: esutils: 2.0.3 - dev: true - /doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + doctrine@3.0.0: dependencies: esutils: 2.0.3 - dev: true - /dotenv@16.0.3: - resolution: {integrity: sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ==} - engines: {node: '>=12'} - dev: false + dotenv@16.0.3: {} - /es-abstract@1.21.2: - resolution: {integrity: sha512-y/B5POM2iBnIxCiernH1G7rC9qQoM77lLIMQLuob0zhp8C56Po81+2Nj0WFKnd0pNReDTnkYryc+zhOzpEIROg==} - engines: {node: '>= 0.4'} + es-abstract@1.21.2: dependencies: array-buffer-byte-length: 1.0.0 available-typed-arrays: 1.0.5 @@ -611,76 +1422,38 @@ packages: typed-array-length: 1.0.4 unbox-primitive: 1.0.2 which-typed-array: 1.1.9 - dev: true - /es-set-tostringtag@2.0.1: - resolution: {integrity: sha512-g3OMbtlwY3QewlqAiMLI47KywjWZoEytKr8pf6iTC8uJq5bIAH52Z9pnQ8pVL6whrCto53JZDuUIsifGeLorTg==} - engines: {node: '>= 0.4'} + es-set-tostringtag@2.0.1: dependencies: get-intrinsic: 1.2.0 has: 1.0.3 has-tostringtag: 1.0.0 - dev: true - /es-shim-unscopables@1.0.0: - resolution: {integrity: sha512-Jm6GPcCdC30eMLbZ2x8z2WuRwAws3zTBBKuusffYVUrNj/GVSUAZ+xKMaUpfNDR5IbyNA5LJbaecoUVbmUcB1w==} + es-shim-unscopables@1.0.0: dependencies: has: 1.0.3 - dev: true - /es-to-primitive@1.2.1: - resolution: {integrity: sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==} - engines: {node: '>= 0.4'} + es-to-primitive@1.2.1: dependencies: is-callable: 1.2.7 is-date-object: 1.0.5 is-symbol: 1.0.4 - dev: true - /escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - dev: true + escape-string-regexp@4.0.0: {} - /eslint-config-prettier@8.8.0(eslint@8.39.0): - resolution: {integrity: sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' + eslint-config-prettier@8.8.0(eslint@8.39.0): dependencies: eslint: 8.39.0 - dev: true - /eslint-import-resolver-node@0.3.7: - resolution: {integrity: sha512-gozW2blMLJCeFpBwugLTGyvVjNoeo1knonXAcatC6bjPBZitotxdWf7Gimr25N4c0AAOo4eOUfaG82IJPDpqCA==} + eslint-import-resolver-node@0.3.7: dependencies: debug: 3.2.7 is-core-module: 2.12.0 resolve: 1.22.2 transitivePeerDependencies: - supports-color - dev: true - /eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.0)(eslint-import-resolver-node@0.3.7)(eslint@8.39.0): - resolution: {integrity: sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true + eslint-module-utils@2.8.0(@typescript-eslint/parser@5.59.0)(eslint-import-resolver-node@0.3.7)(eslint@8.39.0): dependencies: '@typescript-eslint/parser': 5.59.0(eslint@8.39.0)(typescript@5.0.4) debug: 3.2.7 @@ -688,17 +1461,8 @@ packages: eslint-import-resolver-node: 0.3.7 transitivePeerDependencies: - supports-color - dev: true - /eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.39.0): - resolution: {integrity: sha512-LmEt3GVofgiGuiE+ORpnvP+kAm3h6MLZJ4Q5HCyHADofsb4VzXFsRiWj3c0OFiV+3DWFh0qg3v9gcPlfc3zRow==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true + eslint-plugin-import@2.27.5(@typescript-eslint/parser@5.59.0)(eslint@8.39.0): dependencies: '@typescript-eslint/parser': 5.59.0(eslint@8.39.0)(typescript@5.0.4) array-includes: 3.1.6 @@ -721,58 +1485,31 @@ packages: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.39.0)(prettier@2.8.8): - resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} - engines: {node: '>=12.0.0'} - peerDependencies: - eslint: '>=7.28.0' - eslint-config-prettier: '*' - prettier: '>=2.0.0' - peerDependenciesMeta: - eslint-config-prettier: - optional: true + eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.8.0)(eslint@8.39.0)(prettier@2.8.8): dependencies: eslint: 8.39.0 eslint-config-prettier: 8.8.0(eslint@8.39.0) prettier: 2.8.8 prettier-linter-helpers: 1.0.0 - dev: true - /eslint-plugin-simple-import-sort@10.0.0(eslint@8.39.0): - resolution: {integrity: sha512-AeTvO9UCMSNzIHRkg8S6c3RPy5YEwKWSQPx3DYghLedo2ZQxowPFLGDN1AZ2evfg6r6mjBSZSLxLFsWSu3acsw==} - peerDependencies: - eslint: '>=5.0.0' + eslint-plugin-simple-import-sort@10.0.0(eslint@8.39.0): dependencies: eslint: 8.39.0 - dev: true - /eslint-scope@5.1.1: - resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} - engines: {node: '>=8.0.0'} + eslint-scope@5.1.1: dependencies: esrecurse: 4.3.0 estraverse: 4.3.0 - dev: true - /eslint-scope@7.2.0: - resolution: {integrity: sha512-DYj5deGlHBfMt15J7rdtyKNq/Nqlv5KfU4iodrQ019XESsRnwXH9KAE0y3cwtUHDo2ob7CypAnCqefh6vioWRw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + eslint-scope@7.2.0: dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.0: - resolution: {integrity: sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true + eslint-visitor-keys@3.4.0: {} - /eslint@8.39.0: - resolution: {integrity: sha512-mwiok6cy7KTW7rBpo05k6+p4YVZByLNjAZ/ACB9DRCu4YDRwjXI01tWHp6KAUWelsBetTxKK/2sHB0vdS8Z2Og==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - hasBin: true + eslint@8.39.0: dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.39.0) '@eslint-community/regexpp': 4.5.0 @@ -816,200 +1553,115 @@ packages: text-table: 0.2.0 transitivePeerDependencies: - supports-color - dev: true - /espree@9.5.1: - resolution: {integrity: sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + espree@9.5.1: dependencies: acorn: 8.8.2 acorn-jsx: 5.3.2(acorn@8.8.2) eslint-visitor-keys: 3.4.0 - dev: true - /esquery@1.5.0: - resolution: {integrity: sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==} - engines: {node: '>=0.10'} + esquery@1.5.0: dependencies: estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + esrecurse@4.3.0: dependencies: estraverse: 5.3.0 - dev: true - /estraverse@4.3.0: - resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} - engines: {node: '>=4.0'} - dev: true + estraverse@4.3.0: {} - /estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - dev: true + estraverse@5.3.0: {} - /esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - dev: true + esutils@2.0.3: {} - /fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true + fast-deep-equal@3.1.3: {} - /fast-diff@1.2.0: - resolution: {integrity: sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==} - dev: true + fast-diff@1.2.0: {} - /fast-glob@3.2.12: - resolution: {integrity: sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==} - engines: {node: '>=8.6.0'} + fast-glob@3.2.12: dependencies: '@nodelib/fs.stat': 2.0.5 '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: true - /fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true + fast-json-stable-stringify@2.1.0: {} - /fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true + fast-levenshtein@2.0.6: {} - /fastq@1.15.0: - resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} + fastq@1.15.0: dependencies: reusify: 1.0.4 - dev: true - /file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + file-entry-cache@6.0.1: dependencies: flat-cache: 3.0.4 - dev: true - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} + fill-range@7.0.1: dependencies: to-regex-range: 5.0.1 - dev: true - /find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} + find-up@5.0.0: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: true - /flat-cache@3.0.4: - resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} - engines: {node: ^10.12.0 || >=12.0.0} + flat-cache@3.0.4: dependencies: flatted: 3.2.7 rimraf: 3.0.2 - dev: true - /flatted@3.2.7: - resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} - dev: true + flatted@3.2.7: {} - /follow-redirects@1.15.2: - resolution: {integrity: sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - dev: false + follow-redirects@1.15.2: {} - /for-each@0.3.3: - resolution: {integrity: sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==} + for-each@0.3.3: dependencies: is-callable: 1.2.7 - dev: true - /form-data@4.0.0: - resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} - engines: {node: '>= 6'} + form-data@4.0.0: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 mime-types: 2.1.35 - dev: false - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true + fs.realpath@1.0.0: {} - /fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - dev: false + fsevents@2.3.2: optional: true - /function-bind@1.1.1: - resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} - dev: true + function-bind@1.1.1: {} - /function.prototype.name@1.1.5: - resolution: {integrity: sha512-uN7m/BzVKQnCUF/iW8jYea67v++2u7m5UgENbHRtdDVclOUP+FMPlCNdmk0h/ysGyo2tavMJEDqJAkJdRa1vMA==} - engines: {node: '>= 0.4'} + function.prototype.name@1.1.5: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 functions-have-names: 1.2.3 - dev: true - /functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - dev: true + functions-have-names@1.2.3: {} - /get-intrinsic@1.2.0: - resolution: {integrity: sha512-L049y6nFOuom5wGyRc3/gdTLO94dySVKRACj1RmJZBQXlbTMhtNIgkWkUHq+jYmZvKf14EW1EoJnnjbmoHij0Q==} + get-intrinsic@1.2.0: dependencies: function-bind: 1.1.1 has: 1.0.3 has-symbols: 1.0.3 - dev: true - /get-symbol-description@1.0.0: - resolution: {integrity: sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==} - engines: {node: '>= 0.4'} + get-symbol-description@1.0.0: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.0 - dev: true - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + glob-parent@5.1.2: dependencies: is-glob: 4.0.3 - dev: true - /glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 - dev: true - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + glob@7.2.3: dependencies: fs.realpath: 1.0.0 inflight: 1.0.6 @@ -1017,25 +1669,16 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true - /globals@13.20.0: - resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==} - engines: {node: '>=8'} + globals@13.20.0: dependencies: type-fest: 0.20.2 - dev: true - /globalthis@1.0.3: - resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} - engines: {node: '>= 0.4'} + globalthis@1.0.3: dependencies: define-properties: 1.2.0 - dev: true - /globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + globby@11.1.0: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 @@ -1043,370 +1686,211 @@ packages: ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 - dev: true - /gopd@1.0.1: - resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + gopd@1.0.1: dependencies: get-intrinsic: 1.2.0 - dev: true - /grapheme-splitter@1.0.4: - resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} - dev: true + grapheme-splitter@1.0.4: {} - /has-bigints@1.0.2: - resolution: {integrity: sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==} - dev: true + has-bigints@1.0.2: {} - /has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - dev: true + has-flag@4.0.0: {} - /has-property-descriptors@1.0.0: - resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} + has-property-descriptors@1.0.0: dependencies: get-intrinsic: 1.2.0 - dev: true - /has-proto@1.0.1: - resolution: {integrity: sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==} - engines: {node: '>= 0.4'} - dev: true + has-proto@1.0.1: {} - /has-symbols@1.0.3: - resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} - engines: {node: '>= 0.4'} - dev: true + has-symbols@1.0.3: {} - /has-tostringtag@1.0.0: - resolution: {integrity: sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==} - engines: {node: '>= 0.4'} + has-tostringtag@1.0.0: dependencies: has-symbols: 1.0.3 - dev: true - /has@1.0.3: - resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} - engines: {node: '>= 0.4.0'} + has@1.0.3: dependencies: function-bind: 1.1.1 - dev: true - /ignore@5.2.4: - resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} - engines: {node: '>= 4'} - dev: true + ignore@5.2.4: {} - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} + import-fresh@3.3.0: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - dev: true - /imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - dev: true + imurmurhash@0.1.4: {} - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + inflight@1.0.6: dependencies: once: 1.4.0 wrappy: 1.0.2 - dev: true - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true + inherits@2.0.4: {} - /internal-slot@1.0.5: - resolution: {integrity: sha512-Y+R5hJrzs52QCG2laLn4udYVnxsfny9CpOhNhUvk/SSSVyF6T27FzRbF0sroPidSu3X8oEAkOn2K804mjpt6UQ==} - engines: {node: '>= 0.4'} + internal-slot@1.0.5: dependencies: get-intrinsic: 1.2.0 has: 1.0.3 side-channel: 1.0.4 - dev: true - /is-array-buffer@3.0.2: - resolution: {integrity: sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w==} + is-array-buffer@3.0.2: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.0 is-typed-array: 1.1.10 - dev: true - /is-bigint@1.0.4: - resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==} + is-bigint@1.0.4: dependencies: has-bigints: 1.0.2 - dev: true - /is-boolean-object@1.1.2: - resolution: {integrity: sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==} - engines: {node: '>= 0.4'} + is-boolean-object@1.1.2: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: true - /is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - dev: true + is-callable@1.2.7: {} - /is-core-module@2.12.0: - resolution: {integrity: sha512-RECHCBCd/viahWmwj6enj19sKbHfJrddi/6cBDsNTKbNq0f7VeaUkBo60BqzvPqo/W54ChS62Z5qyun7cfOMqQ==} + is-core-module@2.12.0: dependencies: has: 1.0.3 - dev: true - /is-date-object@1.0.5: - resolution: {integrity: sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==} - engines: {node: '>= 0.4'} + is-date-object@1.0.5: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true + is-extglob@2.1.1: {} - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 - dev: true - /is-negative-zero@2.0.2: - resolution: {integrity: sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==} - engines: {node: '>= 0.4'} - dev: true + is-negative-zero@2.0.2: {} - /is-number-object@1.0.7: - resolution: {integrity: sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==} - engines: {node: '>= 0.4'} + is-number-object@1.0.7: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true + is-number@7.0.0: {} - /is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} - dev: true + is-path-inside@3.0.3: {} - /is-regex@1.1.4: - resolution: {integrity: sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==} - engines: {node: '>= 0.4'} + is-regex@1.1.4: dependencies: call-bind: 1.0.2 has-tostringtag: 1.0.0 - dev: true - /is-shared-array-buffer@1.0.2: - resolution: {integrity: sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==} + is-shared-array-buffer@1.0.2: dependencies: call-bind: 1.0.2 - dev: true - /is-string@1.0.7: - resolution: {integrity: sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==} - engines: {node: '>= 0.4'} + is-string@1.0.7: dependencies: has-tostringtag: 1.0.0 - dev: true - /is-symbol@1.0.4: - resolution: {integrity: sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==} - engines: {node: '>= 0.4'} + is-symbol@1.0.4: dependencies: has-symbols: 1.0.3 - dev: true - /is-typed-array@1.1.10: - resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==} - engines: {node: '>= 0.4'} + is-typed-array@1.1.10: dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 for-each: 0.3.3 gopd: 1.0.1 has-tostringtag: 1.0.0 - dev: true - /is-weakref@1.0.2: - resolution: {integrity: sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==} + is-weakref@1.0.2: dependencies: call-bind: 1.0.2 - dev: true - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true + isexe@2.0.0: {} - /js-sdsl@4.4.0: - resolution: {integrity: sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==} - dev: true + js-sdsl@4.4.0: {} - /js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 - dev: true - /json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true + json-schema-traverse@0.4.1: {} - /json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true + json-stable-stringify-without-jsonify@1.0.1: {} - /json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true + json5@1.0.2: dependencies: minimist: 1.2.8 - dev: true - /jssha@3.3.0: - resolution: {integrity: sha512-w9OtT4ALL+fbbwG3gw7erAO0jvS5nfvrukGPMWIAoea359B26ALXGpzy4YJSp9yGnpUvuvOw1nSjSoHDfWSr1w==} - dev: false + jssha@3.3.0: {} - /levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - dev: true - /locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + locate-path@6.0.0: dependencies: p-locate: 5.0.0 - dev: true - /lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true + lodash.merge@4.6.2: {} - /lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - dev: false + lodash@4.17.21: {} - /lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + lru-cache@6.0.0: dependencies: yallist: 4.0.0 - dev: true - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true + merge2@1.4.1: {} - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} + micromatch@4.0.5: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: true - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false + mime-db@1.52.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - dev: false - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.11 - dev: true - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true + minimist@1.2.8: {} - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: true + ms@2.1.2: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - dev: true + ms@2.1.3: {} - /natural-compare-lite@1.4.0: - resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} - dev: true + natural-compare-lite@1.4.0: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /object-inspect@1.12.3: - resolution: {integrity: sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==} - dev: true + object-inspect@1.12.3: {} - /object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - dev: true + object-keys@1.1.1: {} - /object.assign@4.1.4: - resolution: {integrity: sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ==} - engines: {node: '>= 0.4'} + object.assign@4.1.4: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 has-symbols: 1.0.3 object-keys: 1.1.1 - dev: true - /object.values@1.1.6: - resolution: {integrity: sha512-FVVTkD1vENCsAcwNs9k6jea2uHC/X0+JcjG8YA60FN5CMaJmG95wT9jek/xX9nornqGRrBkKtzuAu2wuHpKqvw==} - engines: {node: '>= 0.4'} + object.values@1.1.6: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: true - /obuf@1.1.2: - resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} - dev: false + obuf@1.1.2: {} - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + once@1.4.0: dependencies: wrappy: 1.0.2 - dev: true - /optionator@0.9.1: - resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} - engines: {node: '>= 0.8.0'} + optionator@0.9.1: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -1414,103 +1898,55 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.3 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - /packet-reader@1.0.0: - resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: false + packet-reader@1.0.0: {} - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true + path-is-absolute@1.0.1: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: true + path-parse@1.0.7: {} - /path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} - dev: true + path-type@4.0.0: {} - /pg-cloudflare@1.1.1: - resolution: {integrity: sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==} - requiresBuild: true - dev: false + pg-cloudflare@1.1.1: optional: true - /pg-connection-string@2.6.2: - resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} - dev: false + pg-connection-string@2.6.2: {} - /pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - dev: false + pg-int8@1.0.1: {} - /pg-numeric@1.0.2: - resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} - engines: {node: '>=4'} - dev: false + pg-numeric@1.0.2: {} - /pg-pool@3.6.1(pg@8.11.3): - resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} - peerDependencies: - pg: '>=8.0' + pg-pool@3.6.1(pg@8.11.3): dependencies: pg: 8.11.3 - dev: false - /pg-protocol@1.6.0: - resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} - dev: false + pg-protocol@1.6.0: {} - /pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} + pg-types@2.2.0: dependencies: pg-int8: 1.0.1 postgres-array: 2.0.0 postgres-bytea: 1.0.0 postgres-date: 1.0.7 postgres-interval: 1.2.0 - dev: false - /pg-types@4.0.1: - resolution: {integrity: sha512-hRCSDuLII9/LE3smys1hRHcu5QGcLs9ggT7I/TCs0IE+2Eesxi9+9RWAAwZ0yaGjxoWICF/YHLOEjydGujoJ+g==} - engines: {node: '>=10'} + pg-types@4.0.1: dependencies: pg-int8: 1.0.1 pg-numeric: 1.0.2 @@ -1519,16 +1955,8 @@ packages: postgres-date: 2.0.1 postgres-interval: 3.0.0 postgres-range: 1.1.3 - dev: false - /pg@8.11.3: - resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} - engines: {node: '>= 8.0.0'} - peerDependencies: - pg-native: '>=3.0.1' - peerDependenciesMeta: - pg-native: - optional: true + pg@8.11.3: dependencies: buffer-writer: 2.0.0 packet-reader: 1.0.0 @@ -1539,353 +1967,197 @@ packages: pgpass: 1.0.5 optionalDependencies: pg-cloudflare: 1.1.1 - dev: false - /pgpass@1.0.5: - resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} + pgpass@1.0.5: dependencies: split2: 4.2.0 - dev: false - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true + picomatch@2.3.1: {} - /playwright-core@1.32.3: - resolution: {integrity: sha512-SB+cdrnu74ZIn5Ogh/8278ngEh9NEEV0vR4sJFmK04h2iZpybfbqBY0bX6+BLYWVdV12JLLI+JEFtSnYgR+mWg==} - engines: {node: '>=14'} - hasBin: true - dev: false + playwright-core@1.32.3: {} - /playwright@1.32.3: - resolution: {integrity: sha512-h/ylpgoj6l/EjkfUDyx8cdOlfzC96itPpPe8BXacFkqpw/YsuxkpPyVbzEq4jw+bAJh5FLgh31Ljg2cR6HV3uw==} - engines: {node: '>=14'} - hasBin: true - requiresBuild: true + playwright@1.32.3: dependencies: playwright-core: 1.32.3 - dev: false - /postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - dev: false + postgres-array@2.0.0: {} - /postgres-array@3.0.2: - resolution: {integrity: sha512-6faShkdFugNQCLwucjPcY5ARoW1SlbnrZjmGl0IrrqewpvxvhSLHimCVzqeuULCbG0fQv7Dtk1yDbG3xv7Veog==} - engines: {node: '>=12'} - dev: false + postgres-array@3.0.2: {} - /postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} - dev: false + postgres-bytea@1.0.0: {} - /postgres-bytea@3.0.0: - resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} - engines: {node: '>= 6'} + postgres-bytea@3.0.0: dependencies: obuf: 1.1.2 - dev: false - /postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - dev: false + postgres-date@1.0.7: {} - /postgres-date@2.0.1: - resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==} - engines: {node: '>=12'} - dev: false + postgres-date@2.0.1: {} - /postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} + postgres-interval@1.2.0: dependencies: xtend: 4.0.2 - dev: false - /postgres-interval@3.0.0: - resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} - engines: {node: '>=12'} - dev: false + postgres-interval@3.0.0: {} - /postgres-range@1.1.3: - resolution: {integrity: sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==} - dev: false + postgres-range@1.1.3: {} - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} + prettier-linter-helpers@1.0.0: dependencies: fast-diff: 1.2.0 - dev: true - /prettier@2.8.8: - resolution: {integrity: sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==} - engines: {node: '>=10.13.0'} - hasBin: true - dev: true + prettier@2.8.8: {} - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false + proxy-from-env@1.1.0: {} - /punycode@2.3.0: - resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} - engines: {node: '>=6'} - dev: true + punycode@2.3.0: {} - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true + queue-microtask@1.2.3: {} - /regexp.prototype.flags@1.5.0: - resolution: {integrity: sha512-0SutC3pNudRKgquxGoRGIz946MZVHqbNfPjBdxeOhBrdgDKlRoXmYLQN9xRbrR09ZXWeGAdPuif7egofn6v5LA==} - engines: {node: '>= 0.4'} + regexp.prototype.flags@1.5.0: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 functions-have-names: 1.2.3 - dev: true - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /resolve@1.22.2: - resolution: {integrity: sha512-Sb+mjNHOULsBv818T40qSPeRiuWLyaGMa5ewydRLFimneixmVy2zdivRl+AF6jaYPC8ERxGDmFSiqui6SfPd+g==} - hasBin: true + resolve@1.22.2: dependencies: is-core-module: 2.12.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: true - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true + reusify@1.0.4: {} - /rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - hasBin: true + rimraf@3.0.2: dependencies: glob: 7.2.3 - dev: true - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 - dev: true - /safe-regex-test@1.0.0: - resolution: {integrity: sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA==} + safe-regex-test@1.0.0: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.0 is-regex: 1.1.4 - dev: true - /semver@6.3.0: - resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} - hasBin: true - dev: true + semver@6.3.0: {} - /semver@7.5.0: - resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==} - engines: {node: '>=10'} - hasBin: true + semver@7.5.0: dependencies: lru-cache: 6.0.0 - dev: true - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /side-channel@1.0.4: - resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} + side-channel@1.0.4: dependencies: call-bind: 1.0.2 get-intrinsic: 1.2.0 object-inspect: 1.12.3 - dev: true - /slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} - dev: true + slash@3.0.0: {} - /split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - dev: false + split2@4.2.0: {} - /string.prototype.trim@1.2.7: - resolution: {integrity: sha512-p6TmeT1T3411M8Cgg9wBTMRtY2q9+PNy9EV1i2lIXUN/btt763oIfxwN3RR8VU6wHX8j/1CFy0L+YuThm6bgOg==} - engines: {node: '>= 0.4'} + string.prototype.trim@1.2.7: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: true - /string.prototype.trimend@1.0.6: - resolution: {integrity: sha512-JySq+4mrPf9EsDBEDYMOb/lM7XQLulwg5R/m1r0PXEFqrV0qHvl58sdTilSXtKOflCsK2E8jxf+GKC0T07RWwQ==} + string.prototype.trimend@1.0.6: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: true - /string.prototype.trimstart@1.0.6: - resolution: {integrity: sha512-omqjMDaY92pbn5HOX7f9IccLA+U1tA9GvtU4JrodiXFfYB7jPzzHpRzpglLAjtUV6bB557zwClJezTqnAiYnQA==} + string.prototype.trimstart@1.0.6: dependencies: call-bind: 1.0.2 define-properties: 1.2.0 es-abstract: 1.21.2 - dev: true - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} - dev: true + strip-bom@3.0.0: {} - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-json-comments@3.1.1: {} - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - dev: true + supports-preserve-symlinks-flag@1.0.0: {} - /text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} - dev: true + text-table@0.2.0: {} - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 - dev: true - /totp-generator@0.0.14: - resolution: {integrity: sha512-vFZ8N2TdF4mCj8bUW460jI73LqS+JKccsZ8cttQSuXa3dkTmZo8q81Pq2yAuiPxCI5fPfUrfaKuU+7adjx5s4w==} + totp-generator@0.0.14: dependencies: jssha: 3.3.0 - dev: false - /tsconfig-paths@3.14.2: - resolution: {integrity: sha512-o/9iXgCYc5L/JxCHPe3Hvh8Q/2xm5Z+p18PESBU6Ff33695QnCHBEjcytY2q19ua7Mbl/DavtBOLq+oG0RCL+g==} + tsconfig-paths@3.14.2: dependencies: '@types/json5': 0.0.29 json5: 1.0.2 minimist: 1.2.8 strip-bom: 3.0.0 - dev: true - /tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - dev: true + tslib@1.14.1: {} - /tsutils@3.21.0(typescript@5.0.4): - resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} - engines: {node: '>= 6'} - peerDependencies: - typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + tsutils@3.21.0(typescript@5.0.4): dependencies: tslib: 1.14.1 typescript: 5.0.4 - dev: true - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} - dev: true + type-fest@0.20.2: {} - /typed-array-length@1.0.4: - resolution: {integrity: sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==} + typed-array-length@1.0.4: dependencies: call-bind: 1.0.2 for-each: 0.3.3 is-typed-array: 1.1.10 - dev: true - /typescript@5.0.4: - resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} - engines: {node: '>=12.20'} - hasBin: true - dev: true + typescript@5.0.4: {} - /unbox-primitive@1.0.2: - resolution: {integrity: sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==} + unbox-primitive@1.0.2: dependencies: call-bind: 1.0.2 has-bigints: 1.0.2 has-symbols: 1.0.3 which-boxed-primitive: 1.0.2 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.0 - dev: true - /which-boxed-primitive@1.0.2: - resolution: {integrity: sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==} + which-boxed-primitive@1.0.2: dependencies: is-bigint: 1.0.4 is-boolean-object: 1.1.2 is-number-object: 1.0.7 is-string: 1.0.7 is-symbol: 1.0.4 - dev: true - /which-typed-array@1.1.9: - resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==} - engines: {node: '>= 0.4'} + which-typed-array@1.1.9: dependencies: available-typed-arrays: 1.0.5 call-bind: 1.0.2 @@ -1893,35 +2165,17 @@ packages: gopd: 1.0.1 has-tostringtag: 1.0.0 is-typed-array: 1.1.10 - dev: true - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /word-wrap@1.2.3: - resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==} - engines: {node: '>=0.10.0'} - dev: true + word-wrap@1.2.3: {} - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true + wrappy@1.0.2: {} - /xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - dev: false + xtend@4.0.2: {} - /yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - dev: true + yallist@4.0.0: {} - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} diff --git a/src/bin/defguard.rs b/src/bin/defguard.rs index 749ca4001..a25f50a83 100644 --- a/src/bin/defguard.rs +++ b/src/bin/defguard.rs @@ -3,14 +3,11 @@ use std::{ sync::{Arc, Mutex}, }; -use secrecy::ExposeSecret; -use tokio::sync::{broadcast, mpsc::unbounded_channel}; -use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; - use defguard::{ auth::failed_login::FailedLoginMap, config::{Command, DefGuardConfig}, db::{init_db, AppEvent, GatewayEvent, Settings, User}, + enterprise::license::{run_periodic_license_check, set_cached_license, License}, grpc::{run_grpc_bidi_stream, run_grpc_server, GatewayMap, WorkerState}, headers::create_user_agent_parser, init_dev_env, init_vpn_location, @@ -20,6 +17,9 @@ use defguard::{ wireguard_stats_purge::run_periodic_stats_purge, SERVER_CONFIG, VERSION, }; +use secrecy::ExposeSecret; +use tokio::sync::{broadcast, mpsc::unbounded_channel}; +use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt}; #[macro_use] extern crate tracing; @@ -101,6 +101,17 @@ async fn main() -> Result<(), anyhow::Error> { let failed_logins = FailedLoginMap::new(); let failed_logins = Arc::new(Mutex::new(failed_logins)); + debug!("Checking enterprise license status"); + match License::load_or_renew(&pool).await { + Ok(license) => { + set_cached_license(license); + } + Err(err) => { + warn!("There was an error while loading the license, error: {err}. The enterprise features will be disabled."); + set_cached_license(None); + } + }; + // run services tokio::select! { res = run_grpc_bidi_stream(pool.clone(), wireguard_tx.clone(), mail_tx.clone(), user_agent_parser.clone()), if config.proxy_url.is_some() => error!("Proxy gRPC stream returned early: {res:#?}"), @@ -108,7 +119,8 @@ async fn main() -> Result<(), anyhow::Error> { res = run_web_server(worker_state, gateway_state, webhook_tx, webhook_rx, wireguard_tx.clone(), mail_tx, pool.clone(), user_agent_parser, failed_logins) => error!("Web server returned early: {res:#?}"), res = run_mail_handler(mail_rx, pool.clone()) => error!("Mail handler returned early: {res:#?}"), res = run_periodic_peer_disconnect(pool.clone(), wireguard_tx) => error!("Periodic peer disconnect task returned early: {res:#?}"), - res = run_periodic_stats_purge(pool, config.stats_purge_frequency.into(), config.stats_purge_threshold.into()), if !config.disable_stats_purge => error!("Periodic stats purge task returned early: {res:#?}"), + res = run_periodic_stats_purge(pool.clone(), config.stats_purge_frequency.into(), config.stats_purge_threshold.into()), if !config.disable_stats_purge => error!("Periodic stats purge task returned early: {res:#?}"), + res = run_periodic_license_check(pool) => error!("Periodic license check task returned early: {res:#?}"), } Ok(()) } diff --git a/src/config.rs b/src/config.rs index 3b66f28b2..859ee0e0b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -163,6 +163,34 @@ pub struct DefGuardConfig { #[serde(skip_serializing)] pub gateway_disconnection_notification_timeout: Duration, + #[arg( + long, + env = "DEFGUARD_LICENSE_SERVER_URL", + default_value = "https://update-service-dev.teonite.net/api/license/refresh" + )] + #[serde(skip_serializing)] + pub license_server_url: String, + + #[arg(long, env = "DEFGUARD_LICENSE_CHECK_PERIOD", default_value = "10s")] + #[serde(skip_serializing)] + pub license_check_period: Duration, + + #[arg( + long, + env = "DEFGUARD_LICENSE_CHECK_PERIOD_RENEWAL_WINDOW", + default_value = "5s" + )] + #[serde(skip_serializing)] + pub license_check_period_renewal_window: Duration, + + #[arg( + long, + env = "DEFGUARD_LICENSE_CHECK_PERIOD_NO_LICENSE", + default_value = "15s" + )] + #[serde(skip_serializing)] + pub license_check_period_no_license: Duration, + #[command(subcommand)] #[serde(skip_serializing)] pub cmd: Option, diff --git a/src/db/models/auth_code.rs b/src/db/models/auth_code.rs index f25aa9066..52ad8bf8d 100644 --- a/src/db/models/auth_code.rs +++ b/src/db/models/auth_code.rs @@ -1,9 +1,10 @@ -use super::DbPool; -use crate::random::gen_alphanumeric; use chrono::Utc; use model_derive::Model; use sqlx::{query_as, Error as SqlxError}; +use super::DbPool; +use crate::random::gen_alphanumeric; + #[derive(Model, Clone)] #[table(authorization_code)] pub struct AuthCode { diff --git a/src/db/models/device.rs b/src/db/models/device.rs index c137e779c..47383b9c1 100644 --- a/src/db/models/device.rs +++ b/src/db/models/device.rs @@ -621,9 +621,10 @@ impl Device { #[cfg(test)] mod test { + use claims::{assert_err, assert_ok}; + use super::*; use crate::db::User; - use claims::{assert_err, assert_ok}; impl Device { /// Create new device and assign IP in a given network diff --git a/src/db/models/oauth2authorizedapp.rs b/src/db/models/oauth2authorizedapp.rs index 011221b93..f4566ce26 100644 --- a/src/db/models/oauth2authorizedapp.rs +++ b/src/db/models/oauth2authorizedapp.rs @@ -1,7 +1,8 @@ -use super::DbPool; use model_derive::Model; use sqlx::{query_as, Error as SqlxError}; +use super::DbPool; + #[derive(Model)] pub struct OAuth2AuthorizedApp { pub id: Option, diff --git a/src/db/models/oauth2client.rs b/src/db/models/oauth2client.rs index db13edf32..113d92be6 100644 --- a/src/db/models/oauth2client.rs +++ b/src/db/models/oauth2client.rs @@ -1,8 +1,9 @@ -use super::{DbPool, NewOpenIDClient}; -use crate::random::gen_alphanumeric; use model_derive::Model; use sqlx::{query_as, Error as SqlxError}; +use super::{DbPool, NewOpenIDClient}; +use crate::random::gen_alphanumeric; + #[derive(Deserialize, Model, Serialize)] pub struct OAuth2Client { pub id: Option, diff --git a/src/db/models/oauth2token.rs b/src/db/models/oauth2token.rs index a49a04ffa..94c5e10a6 100644 --- a/src/db/models/oauth2token.rs +++ b/src/db/models/oauth2token.rs @@ -1,8 +1,9 @@ -use super::DbPool; -use crate::{random::gen_alphanumeric, server_config}; use chrono::{Duration, Utc}; use sqlx::{query, query_as, Error as SqlxError}; +use super::DbPool; +use crate::{random::gen_alphanumeric, server_config}; + pub struct OAuth2Token { pub oauth2authorizedapp_id: i64, pub access_token: String, diff --git a/src/db/models/settings.rs b/src/db/models/settings.rs index edaa4b366..569db58ef 100644 --- a/src/db/models/settings.rs +++ b/src/db/models/settings.rs @@ -64,6 +64,7 @@ pub struct Settings { pub ldap_member_attr: Option, // Whether to create a new account when users try to log in with external OpenID pub openid_create_account: bool, + pub license: Option, } impl Settings { diff --git a/src/db/models/webhook.rs b/src/db/models/webhook.rs index 5ffd2e4a6..ed8f31d17 100644 --- a/src/db/models/webhook.rs +++ b/src/db/models/webhook.rs @@ -1,8 +1,9 @@ -use super::UserInfo; -use crate::DbPool; use model_derive::Model; use sqlx::{query_as, Error as SqlxError, FromRow}; +use super::UserInfo; +use crate::DbPool; + /// App events which triggers webhook action #[derive(Debug)] pub enum AppEvent { diff --git a/src/db/models/wireguard.rs b/src/db/models/wireguard.rs index 15f61fc1e..54cdad5a6 100644 --- a/src/db/models/wireguard.rs +++ b/src/db/models/wireguard.rs @@ -1020,9 +1020,8 @@ pub struct WireguardNetworkStats { mod test { use chrono::{Duration, SubsecRound}; - use crate::db::models::device::WireguardNetworkDevice; - use super::*; + use crate::db::models::device::WireguardNetworkDevice; async fn add_devices(pool: &DbPool, network: &WireguardNetwork, count: usize) { let mut user = User::new( diff --git a/src/enterprise/handlers/mod.rs b/src/enterprise/handlers/mod.rs index 0ffbdd9e5..d926bf0bb 100644 --- a/src/enterprise/handlers/mod.rs +++ b/src/enterprise/handlers/mod.rs @@ -1,2 +1,50 @@ +use crate::{ + enterprise::license::validate_license, + handlers::{ApiResponse, ApiResult}, +}; + pub mod openid_login; pub mod openid_providers; + +use axum::{ + async_trait, + extract::{FromRef, FromRequestParts}, + http::{request::Parts, StatusCode}, +}; + +use super::license::get_cached_license; +use crate::{appstate::AppState, error::WebError}; + +pub struct LicenseInfo { + pub valid: bool, +} + +#[async_trait] +impl FromRequestParts for LicenseInfo +where + S: Send + Sync, + AppState: FromRef, +{ + type Rejection = WebError; + + async fn from_request_parts(_parts: &mut Parts, _state: &S) -> Result { + let license = get_cached_license(); + + match validate_license((*license).as_ref()) { + // Useless struct, but may come in handy later + Ok(_) => Ok(LicenseInfo { valid: true }), + Err(e) => Err(WebError::Forbidden(e.to_string())), + } + } +} + +pub async fn check_enterprise_status() -> ApiResult { + let license = get_cached_license(); + + let valid = validate_license((*license).as_ref()).is_ok(); + + Ok(ApiResponse { + json: serde_json::json!({ "enabled": valid }), + status: StatusCode::OK, + }) +} diff --git a/src/enterprise/handlers/openid_login.rs b/src/enterprise/handlers/openid_login.rs index b052f7ae1..549f5f06c 100644 --- a/src/enterprise/handlers/openid_login.rs +++ b/src/enterprise/handlers/openid_login.rs @@ -1,14 +1,8 @@ +use axum::extract::State; use axum::http::StatusCode; - use axum::Json; -use axum_extra::extract::cookie::{Cookie, SameSite}; -use serde_json::json; - -use time::Duration; - -use axum::extract::State; - use axum_client_ip::{InsecureClientIp, LeftmostXForwardedFor}; +use axum_extra::extract::cookie::{Cookie, SameSite}; use axum_extra::extract::{CookieJar, PrivateCookieJar}; use axum_extra::headers::UserAgent; use axum_extra::TypedHeader; @@ -21,7 +15,10 @@ use openidconnect::{ ProviderMetadata, RedirectUrl, }; use openidconnect::{AuthenticationFlow, CsrfToken, EmptyAdditionalClaims, IdToken, Nonce, Scope}; +use serde_json::json; +use time::Duration; +use super::LicenseInfo; use crate::appstate::AppState; use crate::db::{DbPool, MFAInfo, Session, SessionState, Settings, User, UserInfo}; use crate::enterprise::db::models::openid_provider::OpenIdProvider; @@ -105,6 +102,7 @@ async fn make_oidc_client(pool: &DbPool) -> Result { } pub async fn get_auth_info( + _license: LicenseInfo, private_cookies: PrivateCookieJar, State(appstate): State, ) -> Result<(PrivateCookieJar, ApiResponse), WebError> { @@ -177,6 +175,7 @@ pub struct AuthenticationResponse { } pub async fn auth_callback( + _license: LicenseInfo, cookies: CookieJar, private_cookies: PrivateCookieJar, user_agent: Option>, diff --git a/src/enterprise/handlers/openid_providers.rs b/src/enterprise/handlers/openid_providers.rs index 6c94149d1..928dcb235 100644 --- a/src/enterprise/handlers/openid_providers.rs +++ b/src/enterprise/handlers/openid_providers.rs @@ -3,7 +3,9 @@ use axum::{ http::StatusCode, Json, }; +use serde_json::json; +use super::LicenseInfo; use crate::{ appstate::AppState, auth::{AdminRole, SessionInfo}, @@ -11,8 +13,6 @@ use crate::{ handlers::{ApiResponse, ApiResult}, }; -use serde_json::json; - #[derive(Debug, Deserialize, Serialize)] pub struct AddProviderData { name: String, @@ -38,6 +38,7 @@ impl AddProviderData { } pub async fn add_openid_provider( + _license: LicenseInfo, _admin: AdminRole, session: SessionInfo, State(appstate): State, @@ -66,6 +67,7 @@ pub async fn add_openid_provider( } pub async fn get_current_openid_provider( + _license: LicenseInfo, _admin: AdminRole, State(appstate): State, ) -> ApiResult { @@ -82,6 +84,7 @@ pub async fn get_current_openid_provider( } pub async fn delete_openid_provider( + _license: LicenseInfo, _admin: AdminRole, session: SessionInfo, State(appstate): State, @@ -115,6 +118,7 @@ pub async fn delete_openid_provider( } pub async fn modify_openid_provider( + _license: LicenseInfo, _admin: AdminRole, session: SessionInfo, State(appstate): State, @@ -151,6 +155,7 @@ pub async fn modify_openid_provider( } pub async fn list_openid_providers( + _license: LicenseInfo, _admin: AdminRole, State(appstate): State, ) -> ApiResult { diff --git a/src/enterprise/license.rs b/src/enterprise/license.rs new file mode 100644 index 000000000..4cffd1ea3 --- /dev/null +++ b/src/enterprise/license.rs @@ -0,0 +1,508 @@ +use std::sync::{Mutex, MutexGuard}; + +use anyhow::Result; +use base64::prelude::*; +use chrono::{DateTime, TimeDelta, Utc}; +use pgp::{Deserializable, SignedPublicKey, StandaloneSignature}; +use prost::Message; +use sqlx::error::Error as SqlxError; +use thiserror::Error; +use tokio::time::sleep; + +use crate::{ + db::{DbPool, Settings}, + server_config, +}; + +static LICENSE: Mutex> = Mutex::new(None); + +pub fn set_cached_license(license: Option) { + *LICENSE + .lock() + .expect("Failed to acquire lock on the license mutex.") = license; +} + +pub fn get_cached_license() -> MutexGuard<'static, Option> { + LICENSE + .lock() + .expect("Failed to acquire lock on the license mutex.") +} + +tonic::include_proto!("license"); + +// Mock license key +#[cfg(test)] +pub(crate) const PUBLIC_KEY: &str = "-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBGa0jtoBCAC63WkY0btyVzHI8JGVfIkFClNggcDgK+X/if5ndJtHKRXcW6DB +bRTBNCdUr7sDzCMEYWu8t400Yn/mrLKuubA3G6rp3Eo2nHnOicoZ6mfAdUQL862l +m9M8zpJtFodWR5G0nznyvabQi9kI1JT87DEIAdfLhN4eoMpgEm+jASSgFeT63oJ9 +fLHofMZLwYZW/mqsnGxElmUsfnVWeseUSgmKBP4IgdtX4LsCx8XiOyQJww6bEUTj +ZBSqwwuRa1ybtsV3ihEKjDBmXQo5+J3fsadm/6m5PRJVk5rq9/LGVKIBG9m/x6Pn +xeYaLsjNyAwOSHH2KpeBLPVEfjsqWRt8fyAzABEBAAG0HEF1dG9nZW5lcmF0ZWQg +S2V5IDxkZWZndWFyZD6JAU4EEwEKADgWIQTyH9Rb8S5I78bRYzghGgZ+AdnRKwUC +ZrSO2gIbLwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAhGgZ+AdnRKyzzCACW +oGBnAPHkCuvlnZjcYUAJVrjI/S02x4t3wFjaFOu+GQSjeB+AjDawF/S4D5ReQ8iq +D3dTvno3lk/F5HvqV/ZDU9WMmkDFzJoEwKbNIlWwQvvrTnoyy7lpKskNxwwsErEL +2+rW+lW/N5KNHFaUh2d5JhK08VRPfyl0WA8gqQ99Wnhq4rHF7ijKFm3im0RlzkMI +NTXxxee/9J0/Pzh+7zFZlMxnnjwiHlxJXpQFwh7+TS9C3IpChW3ipyPgp1DkzsNv +Xry1crUOhOyEozdKYh2H6tZEi3bjtGwpYkXJs/g3f6HPKjS8rDOMXw4Japb7LYtC +Aao60J8cOm8J96u1MsUK +=6cHp +-----END PGP PUBLIC KEY BLOCK----- +"; + +#[cfg(not(test))] +pub(crate) const PUBLIC_KEY: &str = "-----BEGIN PGP PUBLIC KEY BLOCK----- + +mQENBGa0jtoBCAC63WkY0btyVzHI8JGVfIkFClNggcDgK+X/if5ndJtHKRXcW6DB +bRTBNCdUr7sDzCMEYWu8t400Yn/mrLKuubA3G6rp3Eo2nHnOicoZ6mfAdUQL862l +m9M8zpJtFodWR5G0nznyvabQi9kI1JT87DEIAdfLhN4eoMpgEm+jASSgFeT63oJ9 +fLHofMZLwYZW/mqsnGxElmUsfnVWeseUSgmKBP4IgdtX4LsCx8XiOyQJww6bEUTj +ZBSqwwuRa1ybtsV3ihEKjDBmXQo5+J3fsadm/6m5PRJVk5rq9/LGVKIBG9m/x6Pn +xeYaLsjNyAwOSHH2KpeBLPVEfjsqWRt8fyAzABEBAAG0HEF1dG9nZW5lcmF0ZWQg +S2V5IDxkZWZndWFyZD6JAU4EEwEKADgWIQTyH9Rb8S5I78bRYzghGgZ+AdnRKwUC +ZrSO2gIbLwULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRAhGgZ+AdnRKyzzCACW +oGBnAPHkCuvlnZjcYUAJVrjI/S02x4t3wFjaFOu+GQSjeB+AjDawF/S4D5ReQ8iq +D3dTvno3lk/F5HvqV/ZDU9WMmkDFzJoEwKbNIlWwQvvrTnoyy7lpKskNxwwsErEL +2+rW+lW/N5KNHFaUh2d5JhK08VRPfyl0WA8gqQ99Wnhq4rHF7ijKFm3im0RlzkMI +NTXxxee/9J0/Pzh+7zFZlMxnnjwiHlxJXpQFwh7+TS9C3IpChW3ipyPgp1DkzsNv +Xry1crUOhOyEozdKYh2H6tZEi3bjtGwpYkXJs/g3f6HPKjS8rDOMXw4Japb7LYtC +Aao60J8cOm8J96u1MsUK +=6cHp +-----END PGP PUBLIC KEY BLOCK----- +"; + +#[derive(Debug, Error)] +pub enum LicenseError { + #[error("Provided license is invalid: {0}")] + InvalidLicense(String), + #[error("Provided signature is does not match the license")] + SignatureMismatch, + #[error("Provided signature is invalid")] + InvalidSignature, + #[error("Database error")] + DbError(#[from] SqlxError), + #[error("License decoding error: {0}")] + DecodeError(String), + #[error("License is expired and has reached its maximum overdue time, please contact sales")] + LicenseExpired, + #[error("License not found")] + LicenseNotFound, + #[error("License server error: {0}")] + LicenseServerError(String), +} + +#[derive(Debug, Serialize, Deserialize)] +struct RefreshRequestResponse { + key: String, +} + +#[derive(Debug, Serialize, Deserialize, Clone)] +pub struct License { + pub customer_id: String, + pub subscription: bool, + pub valid_until: Option>, +} + +impl License { + #[must_use] + pub fn new( + customer_id: String, + subscription: bool, + valid_until: Option>, + ) -> Self { + Self { + customer_id, + subscription, + valid_until, + } + } + + fn decode(bytes: &[u8]) -> Result, LicenseError> { + let bytes = BASE64_STANDARD.decode(bytes).map_err(|_| { + LicenseError::DecodeError( + "Failed to decode the license key, check if the provided key is correct." + .to_string(), + ) + })?; + Ok(bytes) + } + + fn verify_signature(data: &[u8], signature: &[u8]) -> Result<(), LicenseError> { + // A hardcoded public key should be always valid, so we can unwrap here + let (public_key, _headers_public) = SignedPublicKey::from_string(PUBLIC_KEY).unwrap(); + let sig = StandaloneSignature::from_bytes(signature) + .map_err(|_| LicenseError::InvalidSignature)?; + sig.verify(&public_key, data) + .map_err(|_| LicenseError::SignatureMismatch) + } + + /// Deserialize the license object from a base64 encoded string + /// Also verifies the signature of the license + pub fn from_base64(key: &str) -> Result { + debug!("Decoding the license key from a provided base64 string..."); + let bytes = key.as_bytes(); + let decoded = Self::decode(bytes)?; + let slice: &[u8] = &decoded; + debug!("Decoded the license key, deserializing the license object..."); + + let license_key = LicenseKey::decode(slice).map_err(|_| { + LicenseError::DecodeError( + "The license key is malformed, check if the provided key is correct.".to_string(), + ) + })?; + let metadata = license_key.metadata.ok_or(LicenseError::InvalidLicense( + "License metadata is missing from the license key, the provided license key is incorrect.".to_string(), + ))?; + let signature = license_key.signature.ok_or(LicenseError::InvalidLicense( + "License signature is missing from the license key, the provided license key is incorrect.".to_string(), + ))?; + let metadata_bytes = metadata.encode_to_vec(); + + debug!("Deserialized the license object, verifying the license signature..."); + + match Self::verify_signature(&metadata_bytes, &signature.signature) { + Ok(_) => { + info!("Successfully decoded the license validated the license signature"); + let valid_until = match metadata.valid_until { + Some(until) => DateTime::from_timestamp(until, 0), + None => None, + }; + + let license = + License::new(metadata.customer_id, metadata.subscription, valid_until); + + if license.requires_renewal() { + if license.is_max_overdue() { + warn!("The provided license has expired and reached its maximum overdue time, please contact salesdefguard.net"); + } else { + warn!("The provided license is about to expire and requires a renewal. An automatic renewal process will attempt to renew the license soon. Alternatively, automatic renewal attempt will be also performed at the next defguard start."); + } + } + + if !license.subscription && license.is_expired() { + warn!("The provided license is not a subscription and has expired, please contact salesdefguard.net"); + } + + Ok(license) + } + Err(_) => Err(LicenseError::SignatureMismatch), + } + } + + /// Get the key from the database + async fn get_key(pool: &DbPool) -> Result, LicenseError> { + let settings = Settings::get_settings(pool).await?; + match settings.license { + Some(key) => { + if key.is_empty() { + Ok(None) + } else { + Ok(Some(key)) + } + } + None => Ok(None), + } + } + + /// Create the license object based on the license key stored in the database. + /// Automatically decodes and deserializes the keys and verifies the signature. + pub async fn load(pool: &DbPool) -> Result, LicenseError> { + match Self::get_key(pool).await? { + Some(key) => Ok(Some(Self::from_base64(&key)?)), + None => { + debug!("No license key found in the database"); + Ok(None) + } + } + } + + /// Try to load the license from the database, if the license requires a renewal, try to renew it. + /// If the renewal fails, it will return the old license for the renewal service to renew it later. + pub async fn load_or_renew(pool: &DbPool) -> Result, LicenseError> { + match Self::load(pool).await? { + Some(license) => { + if license.requires_renewal() { + if !license.is_max_overdue() { + info!("License requires renewal, trying to renew it..."); + match renew_license(pool).await { + Ok(new_key) => { + let new_license = License::from_base64(&new_key)?; + save_license_key(pool, &new_key).await?; + info!("Successfully renewed and loaded the license, new license key saved to the database"); + Ok(Some(new_license)) + } + Err(err) => { + error!("Failed to renew the license: {err}"); + Ok(Some(license)) + } + } + } else { + Err(LicenseError::LicenseExpired) + } + } else { + info!("Successfully loaded the license from the database."); + Ok(Some(license)) + } + } + None => Ok(None), + } + } + + /// Checks whether the license is past its expiry date (`valid_until` field) + /// + /// NOTE: license should be considered valid for an additional period of `MAX_OVERDUE_TIME`. + /// If you want to check if the license reached this point, use `is_max_overdue` instead. + pub fn is_expired(&self) -> bool { + match self.valid_until { + Some(time) => time < Utc::now(), + None => false, + } + } + + /// Checks how much time has left until the `valid_until` time. + pub fn time_left(&self) -> Option { + self.valid_until.map(|time| time - Utc::now()) + } + + /// Gets the time the license is past its expiry date. + /// If the license doesn't have a `valid_until` field, it will return 0. + pub fn time_overdue(&self) -> TimeDelta { + match self.valid_until { + Some(time) => { + let delta = Utc::now() - time; + if delta <= TimeDelta::zero() { + TimeDelta::zero() + } else { + delta + } + } + None => TimeDelta::zero(), + } + } + + /// Checks whether we should try to renew the license. + pub fn requires_renewal(&self) -> bool { + if self.subscription { + if let Some(remaining) = self.time_left() { + remaining <= RENEWAL_TIME + } else { + false + } + } else { + false + } + } + + /// Checks if the license has reached its maximum overdue time. + pub fn is_max_overdue(&self) -> bool { + self.time_overdue() > MAX_OVERDUE_TIME + } +} + +/// Exchange the currently stored key for a new one from the license server. +/// +/// Doesn't update the cached license, nor does it save the new key in the database. +async fn renew_license(db_pool: &DbPool) -> Result { + debug!("Exchanging license for a new one..."); + let old_license_key = match Settings::get_settings(db_pool).await?.license { + Some(key) => key, + None => return Err(LicenseError::LicenseNotFound), + }; + + let client = reqwest::Client::new(); + + let request_body = RefreshRequestResponse { + key: old_license_key, + }; + + // FIXME: this should be a hardcoded IP, make sure to add appropriate host headers + let license_server_url = &server_config().license_server_url; + + let new_license_key = match client + .post(license_server_url) + .json(&request_body) + .send() + .await + { + Ok(response) => match response.status() { + reqwest::StatusCode::OK => { + let response: RefreshRequestResponse = response.json().await.map_err(|err| { + error!("Failed to parse the response from the license server while trying to renew the license: {err:?}"); + LicenseError::LicenseServerError(err.to_string()) + })?; + response.key + } + status => { + let status_message = response.text().await.unwrap_or_default(); + let message = format!( + "Failed to renew the license, the license server returned a status code {status} with error: {status_message}" + ); + return Err(LicenseError::LicenseServerError(message)); + } + }, + Err(err) => { + return Err(LicenseError::LicenseServerError(err.to_string())); + } + }; + + info!("Successfully exchanged the license for a new one"); + + Ok(new_license_key) +} + +/// Helper function used to check if the cached license should be considered valid. +/// As the license is often passed around in the form of `Option`, this function takes care +/// of the whole logic related to checking whether the license is even present in the first place. +/// +/// This function checks the following two things: +/// 1. Does the cached license exist +/// 2. Does the cached license is past its maximum expiry date +pub fn validate_license(license: Option<&License>) -> Result<(), LicenseError> { + debug!("Validating if the license is present and not expired..."); + match license { + Some(license) => { + if license.is_max_overdue() { + return Err(LicenseError::LicenseExpired); + } + Ok(()) + } + None => Err(LicenseError::LicenseNotFound), + } +} + +/// Helper function to save the license key string in the database +async fn save_license_key(pool: &DbPool, key: &str) -> Result<(), LicenseError> { + debug!("Saving the license key to the database..."); + let mut settings = Settings::get_settings(pool).await?; + settings.license = Some(key.to_string()); + settings.save(pool).await?; + info!("Successfully saved the license key to the database."); + Ok(()) +} + +/// Helper function to update the cached license mutex. The mutex is used mainly in the appstate. +pub fn update_cached_license(key: Option<&str>) -> Result<(), LicenseError> { + debug!("Updating the cached license information with the provided key..."); + let license = if let Some(key) = key { + // Handle the Some("") case + if key.is_empty() { + debug!("The new license key is empty, clearing the cached license"); + None + } else { + debug!("A new license key has been provided, decoding and validating it..."); + Some(License::from_base64(key)?) + } + } else { + None + }; + set_cached_license(license); + info!("Successfully updated the cached license information."); + Ok(()) +} + +/// Amount of time before the license expiry date we should start the renewal attempts. +const RENEWAL_TIME: TimeDelta = TimeDelta::hours(24); + +/// Maximum amount of time a license can be over its expiry date. +const MAX_OVERDUE_TIME: TimeDelta = TimeDelta::hours(24); + +pub async fn run_periodic_license_check(pool: DbPool) -> Result<(), LicenseError> { + let mut check_period = server_config().license_check_period; + info!("Starting periodic license check every {check_period:?}"); + loop { + debug!("Checking the license status..."); + // Check if the license is present in the mutex, if not skip the check + if get_cached_license().is_none() { + debug!("No license found, skipping license check"); + sleep(*server_config().license_check_period_no_license).await; + continue; + } + + // Check if the license requires renewal, uses the cached value to be more efficient + // The block here is to avoid holding the lock through awaits + // + // Multiple locks here may cause a race condition if the user decides to update the license key + // while the renewal is in progress. However this seems like a rare case and shouldn't be very problematic. + let requires_renewal = { + let license = get_cached_license(); + debug!("Checking if the license {license:?} requires a renewal..."); + + match &*license { + Some(license) => { + if license.requires_renewal() { + // check if we are pass the maximum expiration date, after which we don't + // want to try to renew the license anymore + if !license.is_max_overdue() { + debug!("License requires renewal, as it is about to expire and is not past the maximum overdue time"); + true + } else { + check_period = server_config().license_check_period; + warn!("Your license has expired and reached its maximum overdue date, please contact sales at salesdefguard.net"); + debug!("Changing check period to {check_period}"); + false + } + } else { + // This if is only for logging purposes, to provide more detailed information + if license.subscription { + debug!("License doesn't need to be renewed yet, skipping renewal check") + } else { + debug!("License is not a subscription, skipping renewal check") + } + false + } + } + None => { + debug!("No license found, skipping license check"); + false + } + } + }; + + if requires_renewal { + info!("License requires renewal, renewing license..."); + check_period = server_config().license_check_period_renewal_window; + debug!("Changing check period to {check_period}"); + match renew_license(&pool).await { + Ok(new_license_key) => match save_license_key(&pool, &new_license_key).await { + Ok(_) => { + update_cached_license(Some(&new_license_key))?; + check_period = server_config().license_check_period; + debug!("Changing check period to {check_period} seconds"); + info!("Successfully renewed the license, new license key saved to the database"); + } + Err(err) => { + error!("Couldn't save the newly fetched license key to the database, error: {}", err); + } + }, + Err(err) => { + warn!("Failed to renew the license: {err}. Retrying in {check_period} seconds"); + } + } + } + + sleep(*check_period).await; + } +} + +#[cfg(test)] +mod test { + use chrono::TimeZone; + + use super::*; + + #[test] + fn test_license() { + let license = "ChMKCTEyMzEyMzEyMxABGMju8bUGErkCCrYCiQEzBAABCgAdFiEE8h/UW/EuSO/G0WM4IRoGfgHZ0SsFAma8d0sACgkQIRoGfgHZ0SvTlwf/TGAsexg4lwBREpb2LaaVGhPIZQE6Jm9IvQXiAkpgqdFruu7A5+wnw90RwKtS8tPlLsCEj6vHHeZUVEAgMZ6HKF56Vkk3fTBvVsLIFoGxLj9GEqBdaxjTZumsHCGUxy7aun/kwprvREsiw/V/tibuXakHUX0SgJZKU/a2bNEg/xdyyqrovYCQVUDFZunLP1Pk8EJbRRLzvlupTq6e726cu3axhDNqKysG3M40WUzMqTicjh/bA7ZXCLiZm0q3vmvwCdPRs51m/Kijo7xTaPzusTjXcicsqiEBinH8i3w/ZwA+pqEo2U92t4oSosJVg/5RKRnGmZSGanEQj6NEp/7Yew=="; + let license = License::from_base64(license).unwrap(); + assert_eq!(license.customer_id, "123123123"); + assert!(license.subscription); + assert_eq!( + license.valid_until.unwrap(), + Utc.with_ymd_and_hms(2024, 8, 14, 9, 22, 16).unwrap() + ); + + assert!(license.is_expired()); + } +} diff --git a/src/enterprise/mod.rs b/src/enterprise/mod.rs index 212ebefc9..6af234a38 100644 --- a/src/enterprise/mod.rs +++ b/src/enterprise/mod.rs @@ -1,2 +1,3 @@ pub mod db; pub mod handlers; +pub mod license; diff --git a/src/enterprise/proto/license.proto b/src/enterprise/proto/license.proto new file mode 100644 index 000000000..54a3f949a --- /dev/null +++ b/src/enterprise/proto/license.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package license; + +message LicenseMetadata { + string customer_id = 1; + bool subscription = 2; + optional int64 valid_until = 3; +} + +message LicenseSignature { + bytes signature = 1; +} + +message LicenseKey { + LicenseMetadata metadata = 1; + LicenseSignature signature = 2; +} diff --git a/src/error.rs b/src/error.rs index cda17066f..9a7e99187 100644 --- a/src/error.rs +++ b/src/error.rs @@ -9,6 +9,7 @@ use crate::{ device::DeviceError, enrollment::TokenError, error::ModelError, wireguard::WireguardNetworkError, }, + enterprise::license::LicenseError, grpc::GatewayMapError, ldap::error::LdapError, templates::TemplateError, @@ -53,6 +54,8 @@ pub enum WebError { TemplateError(#[from] TemplateError), #[error("Server config missing")] ServerConfigMissing, + #[error("License error: {0}")] + LicenseError(#[from] LicenseError), } impl From for WebError { diff --git a/src/grpc/desktop_client_mfa.rs b/src/grpc/desktop_client_mfa.rs index 3d7eb091d..4fb5e5d32 100644 --- a/src/grpc/desktop_client_mfa.rs +++ b/src/grpc/desktop_client_mfa.rs @@ -1,3 +1,9 @@ +use std::collections::HashMap; + +use chrono::Utc; +use tokio::sync::{broadcast::Sender, mpsc::UnboundedSender}; +use tonic::Status; + use super::proto::{ ClientMfaFinishRequest, ClientMfaFinishResponse, ClientMfaStartRequest, ClientMfaStartResponse, MfaMethod, @@ -11,10 +17,6 @@ use crate::{ handlers::mail::send_email_mfa_code_email, mail::Mail, }; -use chrono::Utc; -use std::collections::HashMap; -use tokio::sync::{broadcast::Sender, mpsc::UnboundedSender}; -use tonic::Status; const CLIENT_SESSION_TIMEOUT: u64 = 60 * 5; // 10 minutes diff --git a/src/grpc/enrollment.rs b/src/grpc/enrollment.rs index c43bfc796..0307b250a 100644 --- a/src/grpc/enrollment.rs +++ b/src/grpc/enrollment.rs @@ -1,5 +1,17 @@ use std::sync::Arc; +use ipnetwork::IpNetwork; +use reqwest::Url; +use sqlx::Transaction; +use tokio::sync::{broadcast::Sender, mpsc::UnboundedSender}; +use tonic::Status; +use uaparser::UserAgentParser; + +use super::proto::{ + ActivateUserRequest, AdminInfo, Device as ProtoDevice, DeviceConfig as ProtoDeviceConfig, + DeviceConfigResponse, EnrollmentStartRequest, EnrollmentStartResponse, ExistingDevice, + InitialUserInfo, NewDevice, +}; use crate::{ db::{ models::{ @@ -16,18 +28,6 @@ use crate::{ server_config, templates::{self, TemplateLocation}, }; -use ipnetwork::IpNetwork; -use reqwest::Url; -use sqlx::Transaction; -use tokio::sync::{broadcast::Sender, mpsc::UnboundedSender}; -use tonic::Status; -use uaparser::UserAgentParser; - -use super::proto::{ - ActivateUserRequest, AdminInfo, Device as ProtoDevice, DeviceConfig as ProtoDeviceConfig, - DeviceConfigResponse, EnrollmentStartRequest, EnrollmentStartResponse, ExistingDevice, - InitialUserInfo, NewDevice, -}; pub(super) struct EnrollmentServer { pool: DbPool, diff --git a/src/grpc/interceptor.rs b/src/grpc/interceptor.rs index 4872a327b..75d254459 100644 --- a/src/grpc/interceptor.rs +++ b/src/grpc/interceptor.rs @@ -1,6 +1,7 @@ -use crate::auth::{Claims, ClaimsType}; use tonic::{service::Interceptor, Status}; +use crate::auth::{Claims, ClaimsType}; + /// Auth interceptor used by GRPC services. Verifies JWT token sent /// in GRPC metadata under "authorization" key. #[derive(Clone)] diff --git a/src/grpc/password_reset.rs b/src/grpc/password_reset.rs index d94c25c7c..98e021bdd 100644 --- a/src/grpc/password_reset.rs +++ b/src/grpc/password_reset.rs @@ -1,6 +1,10 @@ use tokio::sync::mpsc::UnboundedSender; use tonic::Status; +use super::proto::{ + PasswordResetInitializeRequest, PasswordResetRequest, PasswordResetStartRequest, + PasswordResetStartResponse, +}; use crate::{ db::{ models::enrollment::{Token, PASSWORD_RESET_TOKEN_TYPE}, @@ -15,11 +19,6 @@ use crate::{ server_config, }; -use super::proto::{ - PasswordResetInitializeRequest, PasswordResetRequest, PasswordResetStartRequest, - PasswordResetStartResponse, -}; - pub(super) struct PasswordResetServer { pool: DbPool, mail_tx: UnboundedSender, diff --git a/src/grpc/worker.rs b/src/grpc/worker.rs index cf08b0d7b..4636cc85e 100644 --- a/src/grpc/worker.rs +++ b/src/grpc/worker.rs @@ -1,9 +1,3 @@ -use super::{Job, JobResponse, WorkerDetail, WorkerInfo, WorkerState}; -use crate::db::{ - models::authentication_key::{AuthenticationKey, AuthenticationKeyType}, - AppEvent, DbPool, HWKeyUserData, User, YubiKey, -}; -use sqlx::query; use std::{ collections::hash_map::{Entry, HashMap}, env, @@ -11,9 +5,17 @@ use std::{ sync::{Arc, Mutex}, time::Instant, }; + +use sqlx::query; use tokio::sync::mpsc::UnboundedSender; use tonic::{Request, Response, Status}; +use super::{Job, JobResponse, WorkerDetail, WorkerInfo, WorkerState}; +use crate::db::{ + models::authentication_key::{AuthenticationKey, AuthenticationKeyType}, + AppEvent, DbPool, HWKeyUserData, User, YubiKey, +}; + tonic::include_proto!("worker"); impl WorkerInfo { diff --git a/src/handlers/app_info.rs b/src/handlers/app_info.rs index fd3a66a09..dc7f387e4 100644 --- a/src/handlers/app_info.rs +++ b/src/handlers/app_info.rs @@ -1,16 +1,22 @@ -use super::{ApiResponse, ApiResult, VERSION}; -use crate::{appstate::AppState, auth::SessionInfo, db::WireguardNetwork}; - -use crate::db::Settings; use axum::{extract::State, http::StatusCode}; use serde_json::json; +use super::{ApiResponse, ApiResult, VERSION}; +use crate::db::Settings; +use crate::enterprise::license::get_cached_license; +use crate::{ + appstate::AppState, auth::SessionInfo, db::WireguardNetwork, + enterprise::license::validate_license, +}; + /// Additional information about core state. #[derive(Serialize)] pub struct AppInfo { version: String, network_present: bool, smtp_enabled: bool, + /// Whether the core has an enterprise license. + enterprise: bool, } pub(crate) async fn get_app_info( @@ -19,10 +25,13 @@ pub(crate) async fn get_app_info( ) -> ApiResult { let networks = WireguardNetwork::all(&appstate.pool).await?; let settings = Settings::get_settings(&appstate.pool).await?; + let license = get_cached_license(); + let enterprise = validate_license((*license).as_ref()).is_ok(); let res = AppInfo { network_present: !networks.is_empty(), smtp_enabled: settings.smtp_configured(), version: VERSION.into(), + enterprise, }; Ok(ApiResponse::new(json!(res), StatusCode::OK)) diff --git a/src/handlers/mod.rs b/src/handlers/mod.rs index e029e42cb..93ca655cd 100644 --- a/src/handlers/mod.rs +++ b/src/handlers/mod.rs @@ -12,6 +12,7 @@ use crate::db::Device; use crate::{ auth::SessionInfo, db::{DbPool, User, UserInfo}, + enterprise::license::LicenseError, error::WebError, VERSION, }; @@ -105,6 +106,34 @@ impl From for ApiResponse { StatusCode::INTERNAL_SERVER_ERROR, ) } + WebError::LicenseError(err) => match err { + LicenseError::DecodeError(msg) | LicenseError::InvalidLicense(msg) => { + warn!(msg); + ApiResponse::new(json!({ "msg": msg }), StatusCode::BAD_REQUEST) + } + LicenseError::SignatureMismatch => { + let msg = "License signature doesn't match its content"; + warn!(msg); + ApiResponse::new(json!({ "msg": msg }), StatusCode::BAD_REQUEST) + } + LicenseError::InvalidSignature => { + let msg = "License signature is malformed and couldn't be read"; + warn!(msg); + ApiResponse::new(json!({ "msg": msg }), StatusCode::BAD_REQUEST) + } + LicenseError::LicenseNotFound => { + let msg = "License not found"; + warn!(msg); + ApiResponse::new(json!({ "msg": msg }), StatusCode::NOT_FOUND) + } + _ => { + error!("License error: {err}"); + ApiResponse::new( + json!({"msg": "Internal server error"}), + StatusCode::FORBIDDEN, + ) + } + }, } } } diff --git a/src/handlers/settings.rs b/src/handlers/settings.rs index 118531784..16c167d68 100644 --- a/src/handlers/settings.rs +++ b/src/handlers/settings.rs @@ -12,6 +12,7 @@ use crate::{ models::settings::{SettingsEssentials, SettingsPatch}, Settings, }, + enterprise::license::update_cached_license, error::WebError, ldap::LDAPConnection, AppState, @@ -48,6 +49,7 @@ pub async fn update_settings( Json(mut data): Json, ) -> ApiResult { debug!("User {} updating settings", session.user.username); + update_cached_license(data.license.as_deref())?; data.id = Some(1); data.save(&appstate.pool).await?; info!("User {} updated settings", session.user.username); @@ -108,6 +110,13 @@ pub async fn patch_settings( ) -> ApiResult { debug!("Admin {} patching settings.", &session.user.username); let mut settings = Settings::get_settings(&appstate.pool).await?; + + // Handle updating the cached license + if let Some(license_key) = &data.license { + update_cached_license(license_key.as_deref())?; + debug!("Saving the new license key to the database as part of the settings patch"); + }; + settings.apply(data); settings.save(&appstate.pool).await?; info!("Admin {} patched settings.", &session.user.username); diff --git a/src/handlers/user.rs b/src/handlers/user.rs index 4199e57b8..dfd59610a 100644 --- a/src/handlers/user.rs +++ b/src/handlers/user.rs @@ -1394,9 +1394,10 @@ pub async fn delete_authorized_app( #[cfg(test)] mod test { - use super::*; use claims::{assert_err, assert_ok}; + use super::*; + #[test] fn test_username_validation() { // valid usernames diff --git a/src/lib.rs b/src/lib.rs index 78a38b112..3dc454904 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,14 +5,14 @@ use std::{ }; use anyhow::anyhow; +use assets::{index, svg, web_asset}; use axum::{ http::{Request, StatusCode}, routing::{delete, get, patch, post, put}, serve, Extension, Json, Router, }; - -use assets::{index, svg, web_asset}; use enterprise::handlers::{ + check_enterprise_status, openid_login::{auth_callback, get_auth_info}, openid_providers::{add_openid_provider, delete_openid_provider, get_current_openid_provider}, }; @@ -37,13 +37,33 @@ use tokio::{ use tower_http::trace::{DefaultOnResponse, TraceLayer}; use tracing::Level; use uaparser::UserAgentParser; - use utoipa::{ openapi::security::{ApiKey, ApiKeyValue, SecurityScheme}, Modify, OpenApi, }; use utoipa_swagger_ui::SwaggerUi; +#[cfg(feature = "wireguard")] +use self::handlers::wireguard::{ + add_device, add_user_devices, create_network, create_network_token, delete_device, + delete_network, download_config, gateway_status, get_device, import_network, list_devices, + list_networks, list_user_devices, modify_device, modify_network, network_details, + network_stats, remove_gateway, user_stats, +}; +#[cfg(feature = "worker")] +use self::handlers::worker::{ + create_job, create_worker_token, job_status, list_workers, remove_worker, +}; +#[cfg(feature = "openid")] +use self::handlers::{ + openid_clients::{ + add_openid_client, change_openid_client, change_openid_client_state, delete_openid_client, + get_openid_client, list_openid_clients, + }, + openid_flow::{ + authorization, discovery_keys, openid_configuration, secure_authorization, token, userinfo, + }, +}; use self::{ appstate::AppState, auth::{Claims, ClaimsType}, @@ -84,28 +104,6 @@ use self::{ }, mail::Mail, }; - -#[cfg(feature = "wireguard")] -use self::handlers::wireguard::{ - add_device, add_user_devices, create_network, create_network_token, delete_device, - delete_network, download_config, gateway_status, get_device, import_network, list_devices, - list_networks, list_user_devices, modify_device, modify_network, network_details, - network_stats, remove_gateway, user_stats, -}; -#[cfg(feature = "worker")] -use self::handlers::worker::{ - create_job, create_worker_token, job_status, list_workers, remove_worker, -}; -#[cfg(feature = "openid")] -use self::handlers::{ - openid_clients::{ - add_openid_client, change_openid_client, change_openid_client_state, delete_openid_client, - get_openid_client, list_openid_clients, - }, - openid_flow::{ - authorization, discovery_keys, openid_configuration, secure_authorization, token, userinfo, - }, -}; #[cfg(any(feature = "openid", feature = "worker"))] use self::{ auth::failed_login::FailedLoginMap, @@ -154,14 +152,12 @@ pub(crate) fn server_config() -> &'static DefGuardConfig { pub(crate) const KEY_LENGTH: usize = 32; mod openapi { - use super::*; use db::{ models::device::{ModifyDevice, UserDevice}, AddDevice, UserDetails, UserInfo, }; use error::WebError; - use utoipa::OpenApi; - + use handlers::wireguard as device; use handlers::{ group::{self, BulkAssignToGroupsRequest, Groups}, user::{self, WalletInfoShort}, @@ -169,8 +165,9 @@ mod openapi { ApiResponse, EditGroupInfo, GroupInfo, PasswordChange, PasswordChangeSelf, StartEnrollmentRequest, Username, WalletChange, WalletSignature, }; + use utoipa::OpenApi; - use handlers::wireguard as device; + use super::*; #[derive(OpenApi)] #[openapi( @@ -402,14 +399,20 @@ pub fn build_webapp( .route("/webhook/:id", delete(delete_webhook)) .route("/webhook/:id", post(change_enabled)) // ldap - .route("/ldap/test", get(test_ldap_settings)) - // OIDC login - .route("/openid/provider", get(get_current_openid_provider)) - .route("/openid/provider", post(add_openid_provider)) - .route("/openid/provider/:name", delete(delete_openid_provider)) - .route("/openid/callback", post(auth_callback)) - .route("/openid/auth_info", get(get_auth_info)), + .route("/ldap/test", get(test_ldap_settings)), + ); + + // Enterprise features + let webapp = webapp.nest( + "/api/v1/openid", + Router::new() + .route("/provider", get(get_current_openid_provider)) + .route("/provider", post(add_openid_provider)) + .route("/provider/:name", delete(delete_openid_provider)) + .route("/callback", post(auth_callback)) + .route("/auth_info", get(get_auth_info)), ); + let webapp = webapp.route("/api/v1/enterprise_status", get(check_enterprise_status)); #[cfg(feature = "openid")] let webapp = webapp diff --git a/src/templates.rs b/src/templates.rs index 1c4b802bc..5ee67a78f 100644 --- a/src/templates.rs +++ b/src/templates.rs @@ -311,10 +311,10 @@ pub fn email_password_reset_success_mail( #[cfg(test)] mod test { - use crate::{config::DefGuardConfig, SERVER_CONFIG}; use claims::assert_ok; use super::*; + use crate::{config::DefGuardConfig, SERVER_CONFIG}; fn get_welcome_context() -> Context { let mut context = Context::new(); diff --git a/src/wireguard_peer_disconnect.rs b/src/wireguard_peer_disconnect.rs index 70b4926fb..eab1aa2be 100644 --- a/src/wireguard_peer_disconnect.rs +++ b/src/wireguard_peer_disconnect.rs @@ -4,6 +4,12 @@ //! it should be removed from gateway configuration and marked as "not allowed", //! which enforces an authentication requirement to connect again. +use std::time::Duration; + +use sqlx::{query_as, Error as SqlxError}; +use thiserror::Error; +use tokio::{sync::broadcast::Sender, time::sleep}; + use crate::db::{ models::{ device::{DeviceInfo, DeviceNetworkInfo, WireguardNetworkDevice}, @@ -12,10 +18,6 @@ use crate::db::{ }, DbPool, Device, GatewayEvent, WireguardNetwork, }; -use sqlx::{query_as, Error as SqlxError}; -use std::time::Duration; -use thiserror::Error; -use tokio::{sync::broadcast::Sender, time::sleep}; // How long to sleep between loop iterations const DISCONNECT_LOOP_SLEEP_SECONDS: u64 = 60; // 1 minute diff --git a/src/wireguard_stats_purge.rs b/src/wireguard_stats_purge.rs index 2280a075f..b1949ee90 100644 --- a/src/wireguard_stats_purge.rs +++ b/src/wireguard_stats_purge.rs @@ -1,10 +1,12 @@ -use crate::db::{DbPool, WireguardPeerStats}; +use std::time::Duration; + use chrono::{DateTime, Duration as ChronoDuration, NaiveDateTime, Utc}; use humantime::format_duration; use sqlx::{query, query_scalar, Error as SqlxError, PgExecutor}; -use std::time::Duration; use tokio::time::sleep; +use crate::db::{DbPool, WireguardPeerStats}; + // How long to sleep between loop iterations const PURGE_LOOP_SLEEP_SECONDS: u64 = 300; // 5 minutes diff --git a/tests/common/mod.rs b/tests/common/mod.rs index df003efbe..7eed5c45e 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -2,11 +2,13 @@ pub(crate) mod client; use std::sync::{Arc, Mutex}; +use chrono::{DateTime, TimeZone, Utc}; use defguard::{ auth::failed_login::FailedLoginMap, build_webapp, config::DefGuardConfig, db::{init_db, AppEvent, DbPool, GatewayEvent, User, UserDetails}, + enterprise::license::{set_cached_license, License}, grpc::{GatewayMap, WorkerState}, headers::create_user_agent_parser, mail::Mail, @@ -120,6 +122,16 @@ pub async fn make_base_client(pool: DbPool, config: DefGuardConfig) -> (TestClie let user_agent_parser = create_user_agent_parser(); + let license = License::new( + "test_customer".to_string(), + true, + // Some(Utc.with_ymd_and_hms(2030, 1, 1, 0, 0, 0).unwrap()), + // Permanent license + None, + ); + + set_cached_license(Some(license)); + let client_state = ClientState::new( pool.clone(), worker_state.clone(), diff --git a/web/src/components/AppLoader.tsx b/web/src/components/AppLoader.tsx index 0e87e4a4d..c0a4726cf 100644 --- a/web/src/components/AppLoader.tsx +++ b/web/src/components/AppLoader.tsx @@ -28,6 +28,7 @@ export const AppLoader = () => { const appSettings = useAppStore((state) => state.settings); const { getAppInfo, + getEnterpriseStatus, user: { getMe }, settings: { getEssentialSettings }, } = useApi(); @@ -67,6 +68,19 @@ export const AppLoader = () => { enabled: !isUndefined(currentUser), }); + useQuery([QueryKeys.FETCH_ENTERPRISE_STATUS], getEnterpriseStatus, { + onSuccess: (status) => { + setAppStore({ enterprise_enabled: status.enabled }); + }, + onError: (err) => { + // FIXME: Add a proper error message + toaster.error(LL.messages.errorVersion()); + console.error(err); + }, + refetchOnWindowFocus: false, + retry: false, + }); + const { isLoading: settingsLoading, data: essentialSettings } = useQuery( [QueryKeys.FETCH_ESSENTIAL_SETTINGS], getEssentialSettings, diff --git a/web/src/i18n/en/index.ts b/web/src/i18n/en/index.ts index b8254aa62..cc514323b 100644 --- a/web/src/i18n/en/index.ts +++ b/web/src/i18n/en/index.ts @@ -33,6 +33,7 @@ const en: BaseTranslation = { success: 'Operation succeeded', errorVersion: 'Failed to get application version.', insecureContext: 'Context is not secure.', + details: 'Details:', clipboard: { error: 'Clipboard is not accessible.', success: 'Content copied to clipboard.', @@ -896,6 +897,11 @@ const en: BaseTranslation = { editSuccess: 'Settings updated', challengeSuccess: 'Challenge message changed', }, + enterpriseOnly: { + title: 'This feature is available only in Defguard Enterprise.', + subtitle: 'To learn more, visit our ', + website: 'website', + }, ldapSettings: { title: 'LDAP Settings', form: { @@ -1042,6 +1048,28 @@ const en: BaseTranslation = { `, }, + license: { + header: 'Enterprise', + helpers: { + enterpriseHeader: { + text: 'Here you can manage your Defguard Enterprise version license.', + link: 'To learn more about Defguard Enterprise, visit our webiste.', + }, + licenseKey: { + text: 'Enter your Defguard Enterprise license key below. You should receive it via email after purchasing the license.', + link: 'You can purchase the license here.', + }, + }, + form: { + title: 'License', + fields: { + key: { + label: 'License key', + placeholder: 'Your Defguard license key', + }, + }, + }, + }, smtp: { form: { title: 'SMTP configuration', diff --git a/web/src/i18n/i18n-types.ts b/web/src/i18n/i18n-types.ts index 8971bb54f..3f502de04 100644 --- a/web/src/i18n/i18n-types.ts +++ b/web/src/i18n/i18n-types.ts @@ -117,6 +117,10 @@ type RootTranslation = { * C​o​n​t​e​x​t​ ​i​s​ ​n​o​t​ ​s​e​c​u​r​e​. */ insecureContext: string + /** + * D​e​t​a​i​l​s​: + */ + details: string clipboard: { /** * C​l​i​p​b​o​a​r​d​ ​i​s​ ​n​o​t​ ​a​c​c​e​s​s​i​b​l​e​. @@ -2205,6 +2209,20 @@ type RootTranslation = { */ challengeSuccess: string } + enterpriseOnly: { + /** + * T​h​i​s​ ​f​e​a​t​u​r​e​ ​i​s​ ​a​v​a​i​l​a​b​l​e​ ​o​n​l​y​ ​i​n​ ​D​e​f​g​u​a​r​d​ ​E​n​t​e​r​p​r​i​s​e​. + */ + title: string + /** + * T​o​ ​l​e​a​r​n​ ​m​o​r​e​,​ ​v​i​s​i​t​ ​o​u​r​ + */ + subtitle: string + /** + * w​e​b​s​i​t​e + */ + website: string + } ldapSettings: { /** * L​D​A​P​ ​S​e​t​t​i​n​g​s @@ -2526,6 +2544,52 @@ type RootTranslation = { */ helper: RequiredParams<'documentationLink'> } + license: { + /** + * E​n​t​e​r​p​r​i​s​e + */ + header: string + helpers: { + enterpriseHeader: { + /** + * H​e​r​e​ ​y​o​u​ ​c​a​n​ ​m​a​n​a​g​e​ ​y​o​u​r​ ​D​e​f​g​u​a​r​d​ ​E​n​t​e​r​p​r​i​s​e​ ​v​e​r​s​i​o​n​ ​l​i​c​e​n​s​e​. + */ + text: string + /** + * T​o​ ​l​e​a​r​n​ ​m​o​r​e​ ​a​b​o​u​t​ ​D​e​f​g​u​a​r​d​ ​E​n​t​e​r​p​r​i​s​e​,​ ​v​i​s​i​t​ ​o​u​r​ ​w​e​b​i​s​t​e​. + */ + link: string + } + licenseKey: { + /** + * E​n​t​e​r​ ​y​o​u​r​ ​D​e​f​g​u​a​r​d​ ​E​n​t​e​r​p​r​i​s​e​ ​l​i​c​e​n​s​e​ ​k​e​y​ ​b​e​l​o​w​.​ ​Y​o​u​ ​s​h​o​u​l​d​ ​r​e​c​e​i​v​e​ ​i​t​ ​v​i​a​ ​e​m​a​i​l​ ​a​f​t​e​r​ ​p​u​r​c​h​a​s​i​n​g​ ​t​h​e​ ​l​i​c​e​n​s​e​. + */ + text: string + /** + * Y​o​u​ ​c​a​n​ ​p​u​r​c​h​a​s​e​ ​t​h​e​ ​l​i​c​e​n​s​e​ ​h​e​r​e​. + */ + link: string + } + } + form: { + /** + * L​i​c​e​n​s​e + */ + title: string + fields: { + key: { + /** + * L​i​c​e​n​s​e​ ​k​e​y + */ + label: string + /** + * Y​o​u​r​ ​D​e​f​g​u​a​r​d​ ​l​i​c​e​n​s​e​ ​k​e​y + */ + placeholder: string + } + } + } + } smtp: { form: { /** @@ -4129,6 +4193,10 @@ export type TranslationFunctions = { * Context is not secure. */ insecureContext: () => LocalizedString + /** + * Details: + */ + details: () => LocalizedString clipboard: { /** * Clipboard is not accessible. @@ -6197,6 +6265,20 @@ export type TranslationFunctions = { */ challengeSuccess: () => LocalizedString } + enterpriseOnly: { + /** + * This feature is available only in Defguard Enterprise. + */ + title: () => LocalizedString + /** + * To learn more, visit our + */ + subtitle: () => LocalizedString + /** + * website + */ + website: () => LocalizedString + } ldapSettings: { /** * LDAP Settings @@ -6515,6 +6597,52 @@ export type TranslationFunctions = { */ helper: (arg: { documentationLink: string }) => LocalizedString } + license: { + /** + * Enterprise + */ + header: () => LocalizedString + helpers: { + enterpriseHeader: { + /** + * Here you can manage your Defguard Enterprise version license. + */ + text: () => LocalizedString + /** + * To learn more about Defguard Enterprise, visit our webiste. + */ + link: () => LocalizedString + } + licenseKey: { + /** + * Enter your Defguard Enterprise license key below. You should receive it via email after purchasing the license. + */ + text: () => LocalizedString + /** + * You can purchase the license here. + */ + link: () => LocalizedString + } + } + form: { + /** + * License + */ + title: () => LocalizedString + fields: { + key: { + /** + * License key + */ + label: () => LocalizedString + /** + * Your Defguard license key + */ + placeholder: () => LocalizedString + } + } + } + } smtp: { form: { /** diff --git a/web/src/i18n/pl/index.ts b/web/src/i18n/pl/index.ts index 58c00f6d5..1ca5148c8 100644 --- a/web/src/i18n/pl/index.ts +++ b/web/src/i18n/pl/index.ts @@ -32,6 +32,7 @@ const pl: Translation = { error: 'Wystąpił błąd.', success: 'Operacja zakończyła się sukcesem', errorVersion: 'Nie udało się uzyskać wersji aplikacji.', + details: 'Szczegóły:', clipboard: { success: 'Skopiowano do schowka', error: 'Schowek nie jest dostępny', @@ -883,6 +884,11 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe editSuccess: 'Ustawienia zaktualizowane.', challengeSuccess: 'Zmieniono wiadomość do podpisu.', }, + enterpriseOnly: { + title: 'Ta funkcja jest dostępna tylko w wersji Defguard Enterprise', + subtitle: 'Aby uzyskać więcej informacji, odwiedź naszą ', + website: 'stronę internetową', + }, ldapSettings: { title: 'Ustawienia LDAP', form: { @@ -1030,6 +1036,28 @@ Uwaga, podane tutaj konfiguracje nie posiadają klucza prywatnego. Musisz uzupe `, }, + license: { + header: 'Funkcje enterprise', + helpers: { + enterpriseHeader: { + text: 'Tutaj możesz zarządzać swoją licencją Defguard Enterprise.', + link: 'By dowiedzieć się więcej, odwiedź naszą stronę.', + }, + licenseKey: { + text: 'Wprowadź poniżej klucz licencyjny Defguard Enterprise. Powinieneś otrzymać go na swoją skrzynkę e-mailową po zakupie licencji.', + link: 'Licencję możesz zakupić tutaj.', + }, + }, + form: { + title: 'Licencja', + fields: { + key: { + label: 'Klucz licencji', + placeholder: 'Klucz licencji dla twojej instancji Defguard', + }, + }, + }, + }, smtp: { form: { title: 'Ustawienia', diff --git a/web/src/pages/auth/AuthPage.tsx b/web/src/pages/auth/AuthPage.tsx index 950934b20..4055645b8 100644 --- a/web/src/pages/auth/AuthPage.tsx +++ b/web/src/pages/auth/AuthPage.tsx @@ -49,6 +49,8 @@ export const AuthPage = () => { const setAppStore = useAppStore((state) => state.setState); + const enterpriseEnabled = useAppStore((state) => state.enterprise_enabled); + const [params] = useSearchParams(); const redirectUrl = params.get('r'); @@ -153,7 +155,7 @@ export const AuthPage = () => { } /> } /> } /> - } /> + {enterpriseEnabled && } />} } /> diff --git a/web/src/pages/auth/Login/Login.tsx b/web/src/pages/auth/Login/Login.tsx index 56c28aa4e..fc3ed40d7 100644 --- a/web/src/pages/auth/Login/Login.tsx +++ b/web/src/pages/auth/Login/Login.tsx @@ -15,6 +15,7 @@ import { ButtonStyleVariant, } from '../../../shared/defguard-ui/components/Layout/Button/types'; import { LoaderSpinner } from '../../../shared/defguard-ui/components/Layout/LoaderSpinner/LoaderSpinner'; +import { useAppStore } from '../../../shared/hooks/store/useAppStore'; import { useAuthStore } from '../../../shared/hooks/store/useAuthStore'; import useApi from '../../../shared/hooks/useApi'; import { useToaster } from '../../../shared/hooks/useToaster'; @@ -40,7 +41,9 @@ export const Login = () => { } = useApi(); const toaster = useToaster(); + const enterpriseEnabled = useAppStore((state) => state.enterprise_enabled); const { data: openIdInfo, isLoading: openIdLoading } = useQuery({ + enabled: enterpriseEnabled, queryKey: [QueryKeys.FETCH_OPENID_INFO], queryFn: getOpenidInfo, refetchOnMount: true, @@ -103,7 +106,7 @@ export const Login = () => { return (
- {!openIdLoading ? ( + {!enterpriseEnabled || !openIdLoading ? ( <>

{LL.loginPage.pageTitle()}

@@ -130,7 +133,9 @@ export const Login = () => { text={LL.form.login()} data-testid="login-form-submit" /> - {openIdInfo && } + {enterpriseEnabled && openIdInfo && ( + + )} ) : ( diff --git a/web/src/pages/settings/SettingsPage.tsx b/web/src/pages/settings/SettingsPage.tsx index 8c2b8e1af..c66e05973 100644 --- a/web/src/pages/settings/SettingsPage.tsx +++ b/web/src/pages/settings/SettingsPage.tsx @@ -47,8 +47,8 @@ export const SettingsPage = () => { refetchOnWindowFocus: false, }); - const tabs = useMemo( - (): CardTabsData[] => [ + const tabs = useMemo((): CardTabsData[] => { + return [ { key: 0, content: LL.settingsPage.tabs.global(), @@ -73,9 +73,8 @@ export const SettingsPage = () => { active: activeCard === 3, onClick: () => setActiveCard(3), }, - ], - [LL.settingsPage.tabs, activeCard], - ); + ]; + }, [LL.settingsPage.tabs, activeCard]); // set store useEffect(() => { diff --git a/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx b/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx index d64119973..6025d59c0 100644 --- a/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx +++ b/web/src/pages/settings/components/GlobalSettings/GlobalSettings.tsx @@ -1,4 +1,5 @@ import { BrandingSettings } from './components/BrandingSettings/BrandingSettings'; +import { LicenseSettings } from './components/LicenseSettings/LicenseSettings'; import { ModulesSettings } from './components/ModulesSettings/ModulesSettings'; import { Web3Settings } from './components/Web3Settings/Web3Settings'; @@ -9,6 +10,7 @@ export const GlobalSettings = () => (
+
diff --git a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx new file mode 100644 index 000000000..bfe0af118 --- /dev/null +++ b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/LicenseSettings.tsx @@ -0,0 +1,137 @@ +import './styles.scss'; + +import { zodResolver } from '@hookform/resolvers/zod'; +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { AxiosError } from 'axios'; +import { useEffect, useMemo } from 'react'; +import { SubmitHandler, useForm } from 'react-hook-form'; +import { useBreakpoint } from 'use-breakpoint'; +import { z } from 'zod'; + +import { useI18nContext } from '../../../../../../i18n/i18n-react'; +import IconCheckmarkWhite from '../../../../../../shared/components/svg/IconCheckmarkWhite'; +import { deviceBreakpoints } from '../../../../../../shared/constants'; +import { FormInput } from '../../../../../../shared/defguard-ui/components/Form/FormInput/FormInput'; +import { Button } from '../../../../../../shared/defguard-ui/components/Layout/Button/Button'; +import { + ButtonSize, + ButtonStyleVariant, +} from '../../../../../../shared/defguard-ui/components/Layout/Button/types'; +import { Card } from '../../../../../../shared/defguard-ui/components/Layout/Card/Card'; +import { Helper } from '../../../../../../shared/defguard-ui/components/Layout/Helper/Helper'; +import useApi from '../../../../../../shared/hooks/useApi'; +import { useToaster } from '../../../../../../shared/hooks/useToaster'; +import { QueryKeys } from '../../../../../../shared/queries'; +import { Settings } from '../../../../../../shared/types'; +import { useSettingsPage } from '../../../../hooks/useSettingsPage'; + +type FormFields = { + license: string; +}; + +type LicenseErrorResponse = { + msg: string; +}; + +export const LicenseSettings = () => { + const { LL } = useI18nContext(); + const toaster = useToaster(); + const { + settings: { patchSettings }, + } = useApi(); + + const settings = useSettingsPage((state) => state.settings); + + const queryClient = useQueryClient(); + const { breakpoint } = useBreakpoint(deviceBreakpoints); + + const { mutate, isLoading } = useMutation(patchSettings, { + onSuccess: () => { + toaster.success(LL.settingsPage.messages.editSuccess()); + queryClient.invalidateQueries([QueryKeys.FETCH_SETTINGS]); + queryClient.invalidateQueries([QueryKeys.FETCH_ENTERPRISE_STATUS]); + }, + onError: (err: AxiosError) => { + const errorResponse = err.response?.data as LicenseErrorResponse; + toaster.error( + `${LL.messages.error()} ${LL.messages.details()} ${errorResponse.msg}`, + ); + console.error(err); + }, + }); + + const zodSchema = useMemo( + () => + z.object({ + license: z.string(), + }), + [], + ); + + const defaultValues = useMemo((): FormFields => { + return { + license: settings?.license || '', + }; + }, [settings?.license]); + + const { control, handleSubmit, reset } = useForm({ + defaultValues, + mode: 'all', + resolver: zodResolver(zodSchema), + }); + + useEffect(() => { + reset(); + }, [reset, defaultValues]); + + const onSubmit: SubmitHandler = (submitted) => { + mutate(submitted); + }; + + return ( +
+
+

{LL.settingsPage.license.header()}

+ +

{LL.settingsPage.license.helpers.enterpriseHeader.text()}

+ + {LL.settingsPage.license.helpers.enterpriseHeader.link()} + +
+
+ +
+
+

{LL.settingsPage.license.form.title()}:

+ +

{LL.settingsPage.license.helpers.licenseKey.text()}

+ + {LL.settingsPage.license.helpers.licenseKey.link()} + +
+
+
+
+ + +
+
+ ); +}; diff --git a/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss new file mode 100644 index 000000000..772a40350 --- /dev/null +++ b/web/src/pages/settings/components/GlobalSettings/components/LicenseSettings/styles.scss @@ -0,0 +1,18 @@ +#license-settings { + & > .card { + display: flex; + flex-flow: column; + row-gap: 16px; + + @include media-breakpoint-up(lg) { + padding: 16px 15px; + } + } +} + +.controls > .header { + display: flex; + justify-content: space-between; + align-items: center; + gap: 10px; +} diff --git a/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx b/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx index b4a1b4d0d..014327dfc 100644 --- a/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx +++ b/web/src/pages/settings/components/OpenIdSettings/OpenIdSettings.tsx @@ -1,11 +1,33 @@ import './style.scss'; +import { useI18nContext } from '../../../../i18n/i18n-react'; +import { useAppStore } from '../../../../shared/hooks/store/useAppStore'; import { OpenIdGeneralSettings } from './components/OpenIdGeneralSettings'; import { OpenIdSettingsForm } from './components/OpenIdSettingsForm'; export const OpenIdSettings = () => { + const enterpriseEnabled = useAppStore((state) => state.enterprise_enabled); + const { LL } = useI18nContext(); + const localLL = LL.settingsPage.enterpriseOnly; + return ( <> + {!enterpriseEnabled && ( +
+
+
+

{localLL.title()}

+

+ {localLL.subtitle()}{' '} + + {localLL.website()} + + . +

+
+
+
+ )}
diff --git a/web/src/pages/settings/components/OpenIdSettings/components/OpenIdGeneralSettings.tsx b/web/src/pages/settings/components/OpenIdSettings/components/OpenIdGeneralSettings.tsx index f3d0a600c..94a9b5fe1 100644 --- a/web/src/pages/settings/components/OpenIdSettings/components/OpenIdGeneralSettings.tsx +++ b/web/src/pages/settings/components/OpenIdSettings/components/OpenIdGeneralSettings.tsx @@ -6,6 +6,7 @@ import parse from 'html-react-parser'; import { useI18nContext } from '../../../../../i18n/i18n-react'; import { Helper } from '../../../../../shared/defguard-ui/components/Layout/Helper/Helper'; import { LabeledCheckbox } from '../../../../../shared/defguard-ui/components/Layout/LabeledCheckbox/LabeledCheckbox'; +import { useAppStore } from '../../../../../shared/hooks/store/useAppStore'; import useApi from '../../../../../shared/hooks/useApi'; import { useToaster } from '../../../../../shared/hooks/useToaster'; import { MutationKeys } from '../../../../../shared/mutations'; @@ -21,6 +22,7 @@ export const OpenIdGeneralSettings = () => { } = useApi(); const settings = useSettingsPage((state) => state.settings); + const enterpriseEnabled = useAppStore((state) => state.enterprise_enabled); const queryClient = useQueryClient(); @@ -47,7 +49,7 @@ export const OpenIdGeneralSettings = () => {
diff --git a/web/src/pages/settings/components/OpenIdSettings/components/OpenIdSettingsForm.tsx b/web/src/pages/settings/components/OpenIdSettings/components/OpenIdSettingsForm.tsx index e027f861b..956786021 100644 --- a/web/src/pages/settings/components/OpenIdSettings/components/OpenIdSettingsForm.tsx +++ b/web/src/pages/settings/components/OpenIdSettings/components/OpenIdSettingsForm.tsx @@ -22,6 +22,7 @@ import { SelectSelectedValue, SelectSizeVariant, } from '../../../../../shared/defguard-ui/components/Layout/Select/types'; +import { useAppStore } from '../../../../../shared/hooks/store/useAppStore'; import useApi from '../../../../../shared/hooks/useApi'; import { useToaster } from '../../../../../shared/hooks/useToaster'; import { QueryKeys } from '../../../../../shared/queries'; @@ -36,6 +37,7 @@ export const OpenIdSettingsForm = () => { const queryClient = useQueryClient(); const docsLink = 'https://defguard.gitbook.io/defguard/admin-and-features/external-openid-providers'; + const enterpriseEnabled = useAppStore((state) => state.enterprise_enabled); const { settings: { fetchOpenIdProviders, addOpenIdProvider, deleteOpenIdProvider }, @@ -50,6 +52,7 @@ export const OpenIdSettingsForm = () => { setCurrentProvider(provider); }, retry: false, + enabled: enterpriseEnabled, }); const toaster = useToaster(); @@ -198,6 +201,7 @@ export const OpenIdSettingsForm = () => { loading={isLoading} form="openid-settings-form" icon={} + disabled={!enterpriseEnabled} />
@@ -220,17 +224,19 @@ export const OpenIdSettingsForm = () => { onChangeSingle={(res) => handleChange(res)} label={localLL.form.labels.provider.label()} labelExtras={{parse(localLL.form.labels.provider.helper())}} + disabled={!enterpriseEnabled} /> {parse(localLL.form.labels.base_url.helper())}} - disabled={currentProvider?.name === 'Google'} + disabled={currentProvider?.name === 'Google' || !enterpriseEnabled} /> {parse(localLL.form.labels.client_id.helper())}} + disabled={!enterpriseEnabled} /> { {parse(localLL.form.labels.client_secret.helper())} } type="password" + disabled={!enterpriseEnabled} /> diff --git a/web/src/pages/settings/components/OpenIdSettings/style.scss b/web/src/pages/settings/components/OpenIdSettings/style.scss index e69de29bb..475fc4d20 100644 --- a/web/src/pages/settings/components/OpenIdSettings/style.scss +++ b/web/src/pages/settings/components/OpenIdSettings/style.scss @@ -0,0 +1,23 @@ +.settings-card { + position: relative; +} + +.enterprise-info { + position: absolute; + inset: 0; + display: flex; + justify-content: center; + align-items: center; + backdrop-filter: blur(1.5px); + z-index: 100; + border-radius: 15px; + border-top-left-radius: 0px; + background-color: rgba(#f9f9f9, 0.75); +} + +.enterprise-info > div { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; +} diff --git a/web/src/shared/hooks/store/useAppStore.ts b/web/src/shared/hooks/store/useAppStore.ts index af24661b0..c97897575 100644 --- a/web/src/shared/hooks/store/useAppStore.ts +++ b/web/src/shared/hooks/store/useAppStore.ts @@ -9,6 +9,7 @@ const defaultValues: StoreValues = { settings: undefined, language: undefined, appInfo: undefined, + enterprise_enabled: false, }; const persistKeys: Array = ['language']; @@ -35,6 +36,7 @@ type StoreValues = { settings?: SettingsEssentials; language?: Locales; appInfo?: AppInfo; + enterprise_enabled?: boolean; }; type StoreMethods = { diff --git a/web/src/shared/hooks/useApi.tsx b/web/src/shared/hooks/useApi.tsx index 2202f1cab..7b66824ce 100644 --- a/web/src/shared/hooks/useApi.tsx +++ b/web/src/shared/hooks/useApi.tsx @@ -360,6 +360,8 @@ const useApi = (props?: HookProps): ApiHook => { const editSettings = async (settings: Settings) => client.put('/settings', settings).then(unpackRequest); + const getEnterpriseStatus = () => client.get('/enterprise_status').then(unpackRequest); + const mfaEnable = () => client.put('/auth/mfa').then(unpackRequest); const recovery: ApiHook['auth']['mfa']['recovery'] = (data) => @@ -494,6 +496,7 @@ const useApi = (props?: HookProps): ApiHook => { return { getAppInfo, changePasswordSelf, + getEnterpriseStatus, oAuth: { consent: oAuthConsent, }, diff --git a/web/src/shared/queries.ts b/web/src/shared/queries.ts index 1087fcbb5..7834db9ad 100644 --- a/web/src/shared/queries.ts +++ b/web/src/shared/queries.ts @@ -28,4 +28,5 @@ export const QueryKeys = { FETCH_AUTHENTICATION_KEYS_INFO: 'FETCH_AUTHENTICATION_KEYS_INFO', FETCH_OPENID_PROVIDERS: 'FETCH_OPENID_PROVIDERS', FETCH_OPENID_INFO: 'FETCH_OPENID_INFO', + FETCH_ENTERPRISE_STATUS: 'FETCH_ENTERPRISE_STATUS', }; diff --git a/web/src/shared/types.ts b/web/src/shared/types.ts index 4c1f5634d..a89624e15 100644 --- a/web/src/shared/types.ts +++ b/web/src/shared/types.ts @@ -433,9 +433,14 @@ export type AuthenticationKey = { key: string; }; +export type EnterpriseStatusResponse = { + enabled: boolean; +}; + export interface ApiHook { getAppInfo: () => Promise; changePasswordSelf: (data: ChangePasswordSelfRequest) => Promise; + getEnterpriseStatus: () => Promise; oAuth: { consent: (params: unknown) => Promise; }; @@ -804,7 +809,8 @@ export type Settings = SettingsModules & SettingsEnrollment & SettingsBranding & SettingsLDAP & - SettingsOpenID; + SettingsOpenID & + SettingsLicense; // essentials for core frontend, includes only those that are required for frontend operations export type SettingsEssentials = SettingsModules & SettingsBranding; @@ -861,6 +867,10 @@ export type SettingsOpenID = { openid_create_account: boolean; }; +export type SettingsLicense = { + license: string; +}; + export interface Webhook { id: string; url: string;