From 792e6818ab33c5bef80327ec265aaa84cf2f16b9 Mon Sep 17 00:00:00 2001 From: jonaro00 <54029719+jonaro00@users.noreply.github.com> Date: Fri, 8 Nov 2024 13:21:19 +0100 Subject: [PATCH] feat(cargo-shuttle): automatic login via console, login --prompt (#1913) * feat(cargo-shuttle): automatic login, login --input * feat: use callbackPort instead * feat: fix cors * feat: new ws-based auth flow * chore: update some deps * fix: args, print token * clippy * fix: websocket reading logic, ping loop * refa: common ws read function * nit: clean up ws code * nit * --input -> --prompt --- Cargo.lock | 363 ++++++++++++++++++----------------- Cargo.toml | 2 +- admin/src/args.rs | 4 +- api-client/src/lib.rs | 15 +- api-client/src/util.rs | 4 +- cargo-shuttle/Cargo.toml | 9 +- cargo-shuttle/src/args.rs | 32 +-- cargo-shuttle/src/config.rs | 4 +- cargo-shuttle/src/lib.rs | 308 ++++++++++++++++------------- cargo-shuttle/src/util.rs | 15 ++ common/src/constants.rs | 17 +- common/src/models/auth.rs | 11 ++ common/src/models/mod.rs | 1 + resources/persist/Cargo.toml | 2 +- service/src/builder.rs | 2 + 15 files changed, 449 insertions(+), 340 deletions(-) create mode 100644 common/src/models/auth.rs diff --git a/Cargo.lock b/Cargo.lock index 9bb35867a..445738ccd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -159,7 +159,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.67", "time", ] @@ -232,7 +232,7 @@ dependencies = [ "reqwest 0.12.9", "serde", "serde_json", - "thiserror", + "thiserror 1.0.67", "tokio", ] @@ -274,7 +274,7 @@ dependencies = [ "serde_qs 0.10.1", "smart-default", "smol_str", - "thiserror", + "thiserror 1.0.67", "tokio", ] @@ -880,7 +880,7 @@ dependencies = [ "serde_json", "serde_repr", "serde_urlencoded", - "thiserror", + "thiserror 1.0.67", "tokio", "tokio-util", "url", @@ -1066,7 +1066,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -1613,7 +1613,7 @@ checksum = "658bce805d770f407bc62102fca7c2c64ceef2fbcb2b8bd19d2765ce093980de" dependencies = [ "console", "shell-words", - "thiserror", + "thiserror 1.0.67", "zeroize", ] @@ -1765,6 +1765,9 @@ name = "faster-hex" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2a2b11eda1d40935b26cf18f6833c526845ae8c41e58d09af6adeb6f0269183" +dependencies = [ + "serde", +] [[package]] name = "fastrand" @@ -2017,9 +2020,9 @@ dependencies = [ [[package]] name = "gix" -version = "0.66.0" +version = "0.67.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9048b8d1ae2104f045cb37e5c450fc49d5d8af22609386bfc739c11ba88995eb" +checksum = "c7d3e78ddac368d3e3bfbc2862bc2aafa3d89f1b15fed898d9761e1ec6f3f17f" dependencies = [ "gix-actor", "gix-attributes", @@ -2064,28 +2067,28 @@ dependencies = [ "gix-worktree-state", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-actor" -version = "0.32.0" +version = "0.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc19e312cd45c4a66cd003f909163dc2f8e1623e30a0c0c6df3776e89b308665" +checksum = "59226ef06661c756e664b46b1d3b2c198f6adc5407a484c086d0171108a70027" dependencies = [ "bstr", "gix-date", "gix-utils", "itoa", - "thiserror", + "thiserror 1.0.67", "winnow 0.6.20", ] [[package]] name = "gix-attributes" -version = "0.22.5" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebccbf25aa4a973dd352564a9000af69edca90623e8a16dad9cbc03713131311" +checksum = "31a102d201ef0e5a848458a82292581e7641e52f0f52e693b6cbdd05a652c029" dependencies = [ "bstr", "gix-glob", @@ -2094,7 +2097,7 @@ dependencies = [ "gix-trace", "kstring", "smallvec", - "thiserror", + "thiserror 1.0.67", "unicode-bom", ] @@ -2104,7 +2107,7 @@ version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10f78312288bd02052be5dbc2ecbc342c9f4eb791986d86c0a5c06b92dc72efa" dependencies = [ - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2113,7 +2116,7 @@ version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c28b58ba04f0c004722344390af9dbc85888fbb84be1981afb934da4114d4cf" dependencies = [ - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2130,23 +2133,23 @@ dependencies = [ [[package]] name = "gix-commitgraph" -version = "0.24.3" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133b06f67f565836ec0c473e2116a60fb74f80b6435e21d88013ac0e3c60fc78" +checksum = "41db900b189e62dc61575f06fdf1a3b6901d264a99be9d32b286af6b2e3984e1" dependencies = [ "bstr", "gix-chunk", "gix-features", "gix-hash", "memmap2", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-config" -version = "0.40.0" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78e797487e6ca3552491de1131b4f72202f282fb33f198b1c34406d765b42bb0" +checksum = "0bedd1bf1c7b994be9d57207e8e0de79016c05e2e8701d3015da906e65ac445e" dependencies = [ "bstr", "gix-config-value", @@ -2158,7 +2161,7 @@ dependencies = [ "memchr", "once_cell", "smallvec", - "thiserror", + "thiserror 1.0.67", "unicode-bom", "winnow 0.6.20", ] @@ -2173,14 +2176,14 @@ dependencies = [ "bstr", "gix-path", "libc", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-credentials" -version = "0.24.5" +version = "0.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce391d305968782f1ae301c4a3d42c5701df7ff1d8bc03740300f6fd12bce78" +checksum = "d713bac4bf7df5801012285366dae6625d675baec4ba6e443d64e83559bec068" dependencies = [ "bstr", "gix-command", @@ -2190,7 +2193,7 @@ dependencies = [ "gix-sec", "gix-trace", "gix-url", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2202,26 +2205,26 @@ dependencies = [ "bstr", "itoa", "jiff", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-diff" -version = "0.46.0" +version = "0.47.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92c9afd80fff00f8b38b1c1928442feb4cd6d2232a6ed806b6b193151a3d336c" +checksum = "c9850fd0c15af113db6f9e130d13091ba0d3754e570a2afdff9e2f3043da260e" dependencies = [ "bstr", "gix-hash", "gix-object", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-discover" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0577366b9567376bc26e815fd74451ebd0e6218814e242f8e5b7072c58d956d2" +checksum = "c522e31f458f50af09dfb014e10873c5378f702f8049c96f508989aad59671f6" dependencies = [ "bstr", "dunce", @@ -2230,14 +2233,14 @@ dependencies = [ "gix-path", "gix-ref", "gix-sec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-features" -version = "0.38.2" +version = "0.39.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac7045ac9fe5f9c727f38799d002a7ed3583cd777e3322a7c4b43e3cf437dc69" +checksum = "8e0eb9efdf96c35c0bed7596d1bef2d4ce6360a1d09738001f9d3e402aa7ba3e" dependencies = [ "bytes", "crc32fast", @@ -2249,15 +2252,15 @@ dependencies = [ "once_cell", "prodash", "sha1_smol", - "thiserror", + "thiserror 1.0.67", "walkdir", ] [[package]] name = "gix-filter" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4121790ae140066e5b953becc72e7496278138d19239be2e63b5067b0843119e" +checksum = "6b37f82359a4485770ed8993ae715ced1bf674f2a63e45f5a0786d38310665ea" dependencies = [ "bstr", "encoding_rs", @@ -2271,14 +2274,14 @@ dependencies = [ "gix-trace", "gix-utils", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-fs" -version = "0.11.3" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2bfe6249cfea6d0c0e0990d5226a4cb36f030444ba9e35e0639275db8f98575" +checksum = "34740384d8d763975858fa2c176b68652a6fcc09f616e24e3ce967b0d370e4d8" dependencies = [ "fastrand 2.1.1", "gix-features", @@ -2287,9 +2290,9 @@ dependencies = [ [[package]] name = "gix-glob" -version = "0.16.5" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74908b4bbc0a0a40852737e5d7889f676f081e340d5451a16e5b4c50d592f111" +checksum = "254b5101cf7facc00d9b5ff564cf46302ca76695cca23d33bc958a707b6fc857" dependencies = [ "bitflags 2.6.0", "bstr", @@ -2299,19 +2302,19 @@ dependencies = [ [[package]] name = "gix-hash" -version = "0.14.2" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93d7df7366121b5018f947a04d37f034717e113dcf9ccd85c34b58e57a74d5e" +checksum = "952c3a29f1bc1007cc901abce7479943abfa42016db089de33d0a4fa3c85bfe8" dependencies = [ "faster-hex", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-hashtable" -version = "0.5.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ddf80e16f3c19ac06ce415a38b8591993d3f73aede049cb561becb5b3a8e242" +checksum = "0ef65b256631078ef733bc5530c4e6b1c2e7d5c2830b75d4e9034ab3997d18fe" dependencies = [ "gix-hash", "hashbrown 0.14.5", @@ -2320,9 +2323,9 @@ dependencies = [ [[package]] name = "gix-ignore" -version = "0.11.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e447cd96598460f5906a0f6c75e950a39f98c2705fc755ad2f2020c9e937fab7" +checksum = "ba55a9b582dc26a639875497615959a8127ac5c37b2426dc50f037fada33a4b7" dependencies = [ "bstr", "gix-glob", @@ -2333,9 +2336,9 @@ dependencies = [ [[package]] name = "gix-index" -version = "0.35.0" +version = "0.36.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cd4203244444017682176e65fd0180be9298e58ed90bd4a8489a357795ed22d" +checksum = "27619009ca1ea33fd885041273f5fa5a09163a5c1d22a913b28d7b985e66fe29" dependencies = [ "bitflags 2.6.0", "bstr", @@ -2356,25 +2359,25 @@ dependencies = [ "memmap2", "rustix", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-lock" -version = "14.0.0" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bc7fe297f1f4614774989c00ec8b1add59571dc9b024b4c00acb7dedd4e19d" +checksum = "5102acdf4acae2644e38dbbd18cdfba9597a218f7d85f810fe5430207e03c2de" dependencies = [ "gix-tempfile", "gix-utils", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-negotiate" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4063bf329a191a9e24b6f948a17ccf6698c0380297f5e169cee4f1d2ab9475b" +checksum = "414806291838c3349ea939c6d840ff854f84cd29bd3dde8f904f60b0e5b7d0bd" dependencies = [ "bitflags 2.6.0", "gix-commitgraph", @@ -2383,53 +2386,55 @@ dependencies = [ "gix-object", "gix-revwalk", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-object" -version = "0.44.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f5b801834f1de7640731820c2df6ba88d95480dc4ab166a5882f8ff12b88efa" +checksum = "2a77b6e7753d298553d9ae8b1744924481e7a49170983938bb578dccfbc6fc1a" dependencies = [ "bstr", "gix-actor", "gix-date", "gix-features", "gix-hash", + "gix-hashtable", "gix-utils", "gix-validate", "itoa", "smallvec", - "thiserror", + "thiserror 1.0.67", "winnow 0.6.20", ] [[package]] name = "gix-odb" -version = "0.63.0" +version = "0.64.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3158068701c17df54f0ab2adda527f5a6aca38fd5fd80ceb7e3c0a2717ec747" +checksum = "0bb86aadf7f1b2f980601b4fc94309706f9700f8008f935dc512d556c9e60f61" dependencies = [ "arc-swap", "gix-date", "gix-features", "gix-fs", "gix-hash", + "gix-hashtable", "gix-object", "gix-pack", "gix-path", "gix-quote", "parking_lot", "tempfile", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-pack" -version = "0.53.0" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3223aa342eee21e1e0e403cad8ae9caf9edca55ef84c347738d10681676fd954" +checksum = "363e6e59a855ba243672408139db68e2478126cdcfeabb420777df4a1f20026b" dependencies = [ "clru", "gix-chunk", @@ -2442,31 +2447,31 @@ dependencies = [ "memmap2", "parking_lot", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-packetline" -version = "0.17.6" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c43ef4d5fe2fa222c606731c8bdbf4481413ee4ef46d61340ec39e4df4c5e49" +checksum = "5f14a110eb16e27b4ebdae4ca8b389df3ad637d3020077e6b606b1d078745b65" dependencies = [ "bstr", "faster-hex", "gix-trace", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-packetline-blocking" -version = "0.17.5" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9802304baa798dd6f5ff8008a2b6516d54b74a69ca2d3a2b9e2d6c3b5556b40" +checksum = "decace940e8ba8e29d29b73b843a6cbae67503887f3e5fb7e688d0f4f6ee0757" dependencies = [ "bstr", "faster-hex", "gix-trace", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2479,14 +2484,14 @@ dependencies = [ "gix-trace", "home", "once_cell", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-pathspec" -version = "0.7.7" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d23bf239532b4414d0e63b8ab3a65481881f7237ed9647bb10c1e3cc54c5ceb" +checksum = "70f02bf7625dbf15bf9fedbeace2ac1ce1c5177806bdbc24c441d664c75c00e4" dependencies = [ "bitflags 2.6.0", "bstr", @@ -2494,7 +2499,7 @@ dependencies = [ "gix-config-value", "gix-glob", "gix-path", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2507,14 +2512,14 @@ dependencies = [ "gix-config-value", "parking_lot", "rustix", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-protocol" -version = "0.45.3" +version = "0.46.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc43a1006f01b5efee22a003928c9eb83dde2f52779ded9d4c0732ad93164e3e" +checksum = "ac4ebf25f20ac6055728eaa80951acf2cf83948a64af6565b98e7d42b1ab6691" dependencies = [ "bstr", "gix-credentials", @@ -2524,7 +2529,7 @@ dependencies = [ "gix-transport", "gix-utils", "maybe-async", - "thiserror", + "thiserror 1.0.67", "winnow 0.6.20", ] @@ -2536,14 +2541,14 @@ checksum = "f89f9a1525dcfd9639e282ea939f5ab0d09d93cf2b90c1fc6104f1b9582a8e49" dependencies = [ "bstr", "gix-utils", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-ref" -version = "0.47.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae0d8406ebf9aaa91f55a57f053c5a1ad1a39f60fdf0303142b7be7ea44311e5" +checksum = "a47385e71fa2d9da8c35e642ef4648808ddf0a52bc93425879088c706dfeaea2" dependencies = [ "gix-actor", "gix-features", @@ -2556,43 +2561,44 @@ dependencies = [ "gix-utils", "gix-validate", "memmap2", - "thiserror", + "thiserror 1.0.67", "winnow 0.6.20", ] [[package]] name = "gix-refspec" -version = "0.25.0" +version = "0.26.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb005f82341ba67615ffdd9f7742c87787544441c88090878393d0682869ca6" +checksum = "0022038a09d80d9abf773be8efcbb502868d97f6972b8633bfb52ab6edaac442" dependencies = [ "bstr", "gix-hash", "gix-revision", "gix-validate", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-revision" -version = "0.29.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba4621b219ac0cdb9256883030c3d56a6c64a6deaa829a92da73b9a576825e1e" +checksum = "4ee8eb4088fece3562af4a5d751e069f90e93345524ad730512185234c4b55f1" dependencies = [ "bstr", + "gix-commitgraph", "gix-date", "gix-hash", "gix-object", "gix-revwalk", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-revwalk" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b41e72544b93084ee682ef3d5b31b1ba4d8fa27a017482900e5e044d5b1b3984" +checksum = "e6c9a9496da98d36ff19063a8576bf09a87425583b709a56dc5594fffa9d39b2" dependencies = [ "gix-commitgraph", "gix-date", @@ -2600,7 +2606,7 @@ dependencies = [ "gix-hashtable", "gix-object", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -2617,9 +2623,9 @@ dependencies = [ [[package]] name = "gix-submodule" -version = "0.14.0" +version = "0.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "529d0af78cc2f372b3218f15eb1e3d1635a21c8937c12e2dd0b6fc80c2ca874b" +checksum = "3ed099621873cd36c580fc822176a32a7e50fef15a5c2ed81aaa087296f0497a" dependencies = [ "bstr", "gix-config", @@ -2627,14 +2633,14 @@ dependencies = [ "gix-pathspec", "gix-refspec", "gix-url", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-tempfile" -version = "14.0.2" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "046b4927969fa816a150a0cda2e62c80016fe11fb3c3184e4dddf4e542f108aa" +checksum = "2feb86ef094cc77a4a9a5afbfe5de626897351bbbd0de3cb9314baf3049adb82" dependencies = [ "gix-fs", "libc", @@ -2651,9 +2657,9 @@ checksum = "04bdde120c29f1fc23a24d3e115aeeea3d60d8e65bab92cc5f9d90d9302eb952" [[package]] name = "gix-transport" -version = "0.42.3" +version = "0.43.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421dcccab01b41a15d97b226ad97a8f9262295044e34fbd37b10e493b0a6481f" +checksum = "4c485a345f41b8c0256cb86e95ed93e0692d203fd6c769b0433f7352c13608ad" dependencies = [ "base64 0.22.1", "bstr", @@ -2665,14 +2671,14 @@ dependencies = [ "gix-sec", "gix-url", "reqwest 0.12.9", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-traverse" -version = "0.41.0" +version = "0.42.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "030da39af94e4df35472e9318228f36530989327906f38e27807df305fccb780" +checksum = "f20f1b13cc4fa6ba92b24e6aa0c2fb6a34beb4458ef88c6300212db504e818df" dependencies = [ "bitflags 2.6.0", "gix-commitgraph", @@ -2682,20 +2688,19 @@ dependencies = [ "gix-object", "gix-revwalk", "smallvec", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-url" -version = "0.27.5" +version = "0.28.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd280c5e84fb22e128ed2a053a0daeacb6379469be6a85e3d518a0636e160c89" +checksum = "33e7c297c3265015c133a2c02199610b6e1373a09dc4be057d0c1b5285737f06" dependencies = [ "bstr", "gix-features", "gix-path", - "home", - "thiserror", + "thiserror 1.0.67", "url", ] @@ -2716,14 +2721,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e187b263461bc36cea17650141567753bc6207d036cedd1de6e81a52f277ff68" dependencies = [ "bstr", - "thiserror", + "thiserror 1.0.67", ] [[package]] name = "gix-worktree" -version = "0.36.0" +version = "0.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c312ad76a3f2ba8e865b360d5cb3aa04660971d16dec6dd0ce717938d903149a" +checksum = "0d345e5b523550fe4fa0e912bf957de752011ccfc87451968fda1b624318f29c" dependencies = [ "bstr", "gix-attributes", @@ -2740,9 +2745,9 @@ dependencies = [ [[package]] name = "gix-worktree-state" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b05c4b313fa702c0bacd5068dd3e01671da73b938fade97676859fee286de43" +checksum = "5e72b00e02f3bd737caae9c20a98e70749f42ae18c8f0b68aac3210b42a0b8da" dependencies = [ "bstr", "gix-features", @@ -2755,7 +2760,7 @@ dependencies = [ "gix-path", "gix-worktree", "io-close", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -3307,7 +3312,7 @@ dependencies = [ "ring 0.16.20", "serde", "serde_json", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -3404,7 +3409,7 @@ dependencies = [ "combine", "jni-sys", "log", - "thiserror", + "thiserror 1.0.67", "walkdir", "windows-sys 0.45.0", ] @@ -3640,15 +3645,6 @@ dependencies = [ "libc", ] -[[package]] -name = "memoffset" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" -dependencies = [ - "autocfg", -] - [[package]] name = "mime" version = "0.3.17" @@ -3740,7 +3736,7 @@ dependencies = [ "stringprep", "strsim 0.10.0", "take_mut", - "thiserror", + "thiserror 1.0.67", "tokio", "tokio-rustls 0.24.1", "tokio-util", @@ -3759,16 +3755,13 @@ checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" [[package]] name = "nix" -version = "0.25.1" +version = "0.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4" +checksum = "2eb04e9c688eff1c89d72b407f168cf79bb9e867a9d3323ed6c01519eb9cc053" dependencies = [ - "autocfg", - "bitflags 1.3.2", + "bitflags 2.6.0", "cfg-if", "libc", - "memoffset", - "pin-utils", ] [[package]] @@ -3947,7 +3940,7 @@ dependencies = [ "percent-encoding", "pin-project", "rand 0.8.5", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -3962,7 +3955,7 @@ dependencies = [ "js-sys", "once_cell", "pin-project-lite", - "thiserror", + "thiserror 1.0.67", "urlencoding", ] @@ -3993,7 +3986,7 @@ dependencies = [ "opentelemetry 0.12.0", "opentelemetry-http 0.1.0", "rmp", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -4005,7 +3998,7 @@ dependencies = [ "async-trait", "http 0.2.12", "opentelemetry 0.12.0", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -4037,7 +4030,7 @@ dependencies = [ "opentelemetry_sdk", "prost 0.11.9", "reqwest 0.11.27", - "thiserror", + "thiserror 1.0.67", "tokio", "tonic 0.9.2", ] @@ -4081,7 +4074,7 @@ dependencies = [ "percent-encoding", "rand 0.8.5", "serde_json", - "thiserror", + "thiserror 1.0.67", "tokio", "tokio-stream", ] @@ -4321,7 +4314,7 @@ dependencies = [ "chrono", "serde", "serde_json", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -4411,9 +4404,13 @@ dependencies = [ [[package]] name = "prodash" -version = "28.0.0" +version = "29.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744a264d26b88a6a7e37cbad97953fa233b94d585236310bcbc88474b4092d79" +checksum = "a266d8d6020c61a437be704c5e618037588e1985c7dbb7bf8d265db84cffe325" +dependencies = [ + "log", + "parking_lot", +] [[package]] name = "proptest" @@ -4509,7 +4506,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "socket2 0.5.7", - "thiserror", + "thiserror 1.0.67", "tokio", "tracing", ] @@ -4526,7 +4523,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "slab", - "thiserror", + "thiserror 1.0.67", "tinyvec", "tracing", ] @@ -4669,7 +4666,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -4817,7 +4814,7 @@ dependencies = [ "reqwest 0.11.27", "serde", "task-local-extensions", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -4832,15 +4829,15 @@ dependencies = [ [[package]] name = "rexpect" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ff60778f96fb5a48adbe421d21bf6578ed58c0872d712e7e08593c195adff8" +checksum = "c020234fb542618dc3e3d43724e9d93f87e1db74040a76a8c4e830220fb9b20d" dependencies = [ "comma", "nix", "regex", "tempfile", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -5269,7 +5266,7 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -5280,7 +5277,7 @@ checksum = "8cac3f1e2ca2fe333923a1ae72caca910b98ed0630bb35ef6f8c8517d6e81afa" dependencies = [ "percent-encoding", "serde", - "thiserror", + "thiserror 1.0.67", ] [[package]] @@ -5535,7 +5532,7 @@ dependencies = [ "shuttle-common", "shuttle-common-tests", "sqlx", - "thiserror", + "thiserror 2.0.0", "tokio", "tower", "tracing", @@ -5581,7 +5578,7 @@ dependencies = [ "sqlx", "strum 0.26.3", "test-context", - "thiserror", + "thiserror 2.0.0", "tokio", "tonic 0.10.2", "tower", @@ -5638,7 +5635,7 @@ dependencies = [ "serde_json", "sqlx", "strum 0.26.3", - "thiserror", + "thiserror 2.0.0", "tonic 0.10.2", "tower", "tracing", @@ -5702,7 +5699,7 @@ dependencies = [ "strum 0.26.3", "tar", "tempfile", - "thiserror", + "thiserror 2.0.0", "tokio", "tokio-stream", "toml", @@ -5765,7 +5762,7 @@ dependencies = [ "tar", "tempfile", "test-context", - "thiserror", + "thiserror 2.0.0", "tokio", "tonic 0.10.2", "tower", @@ -5797,7 +5794,7 @@ dependencies = [ "shuttle-common-tests", "shuttle-proto", "sqlx", - "thiserror", + "thiserror 2.0.0", "tokio", "tokio-stream", "tonic 0.10.2", @@ -5845,7 +5842,7 @@ dependencies = [ "shuttle-common-tests", "shuttle-proto", "sqlx", - "thiserror", + "thiserror 2.0.0", "tokio", "tonic 0.10.2", "tracing", @@ -5869,7 +5866,7 @@ dependencies = [ "shuttle-proto", "sqlx", "strum 0.26.3", - "thiserror", + "thiserror 2.0.0", "tokio", "tonic 0.10.2", "tracing", @@ -5914,7 +5911,7 @@ dependencies = [ "shuttle-common", "shuttle-proto", "strfmt", - "thiserror", + "thiserror 2.0.0", "tokio", "toml", "tracing", @@ -5974,7 +5971,7 @@ checksum = "adc4e5204eb1910f40f9cfa375f6f05b68c3abac4b6fd879c8ff5e7ae8a0a085" dependencies = [ "num-bigint", "num-traits", - "thiserror", + "thiserror 1.0.67", "time", ] @@ -6019,7 +6016,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec62a949bda7f15800481a711909f946e1204f2460f89210eaf7f57730f88f86" dependencies = [ - "thiserror", + "thiserror 1.0.67", "unicode_categories", ] @@ -6126,7 +6123,7 @@ dependencies = [ "sha2", "smallvec", "sqlformat", - "thiserror", + "thiserror 1.0.67", "tokio", "tokio-stream", "tracing", @@ -6212,7 +6209,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.67", "tracing", "uuid", "whoami", @@ -6252,7 +6249,7 @@ dependencies = [ "smallvec", "sqlx-core", "stringprep", - "thiserror", + "thiserror 1.0.67", "tracing", "uuid", "whoami", @@ -6549,7 +6546,16 @@ version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3c6efbfc763e64eb85c11c25320f0737cb7364c4b6336db90aa9ebe27a0bbd" dependencies = [ - "thiserror-impl", + "thiserror-impl 1.0.67", +] + +[[package]] +name = "thiserror" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15291287e9bff1bc6f9ff3409ed9af665bec7a5fc8ac079ea96be07bca0e2668" +dependencies = [ + "thiserror-impl 2.0.0", ] [[package]] @@ -6563,6 +6569,17 @@ dependencies = [ "syn 2.0.87", ] +[[package]] +name = "thiserror-impl" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22efd00f33f93fa62848a7cab956c3d38c8d43095efda1decfc2b3a5dc0b8972" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.87", +] + [[package]] name = "thread_local" version = "1.1.8" @@ -6993,7 +7010,7 @@ dependencies = [ "log", "rand 0.8.5", "smallvec", - "thiserror", + "thiserror 1.0.67", "tinyvec", "tokio", "url", @@ -7014,7 +7031,7 @@ dependencies = [ "parking_lot", "resolv-conf", "smallvec", - "thiserror", + "thiserror 1.0.67", "tokio", "trust-dns-proto", ] @@ -7064,7 +7081,7 @@ dependencies = [ "rand 0.8.5", "rustls 0.21.12", "sha1", - "thiserror", + "thiserror 1.0.67", "url", "utf-8", ] @@ -7821,7 +7838,7 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.67", "time", ] @@ -7920,7 +7937,7 @@ dependencies = [ "pbkdf2 0.12.2", "rand 0.8.5", "sha1", - "thiserror", + "thiserror 1.0.67", "time", "zeroize", "zopfli", diff --git a/Cargo.toml b/Cargo.toml index d0bf8551d..88715ad87 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -93,7 +93,7 @@ strum = { version = "0.26.1", features = ["derive"] } tar = "0.4.38" tempfile = "3.4.0" test-context = "0.3.0" -thiserror = "1.0.37" +thiserror = "2" tokio = "1.22.0" tokio-stream = "0.1.11" tokio-tungstenite = { version = "0.20.1", features = [ diff --git a/admin/src/args.rs b/admin/src/args.rs index c5b96c3e8..ef2871f17 100644 --- a/admin/src/args.rs +++ b/admin/src/args.rs @@ -2,14 +2,14 @@ use std::{fs, io, path::PathBuf}; use clap::{Error, Parser, Subcommand}; use shuttle_common::{ - constants::API_URL_PRODUCTION, + constants::API_URL_RS, models::{project::ComputeTier, user::UserId}, }; #[derive(Parser, Debug)] pub struct Args { /// run this command against the api at the supplied url - #[arg(long, default_value = API_URL_PRODUCTION, env = "SHUTTLE_API")] + #[arg(long, default_value = API_URL_RS, env = "SHUTTLE_API")] pub api_url: String, #[command(subcommand)] diff --git a/api-client/src/lib.rs b/api-client/src/lib.rs index 66639a9fa..9c086fb39 100644 --- a/api-client/src/lib.rs +++ b/api-client/src/lib.rs @@ -82,6 +82,12 @@ impl ShuttleApiClient { .context("parsing API version info") } + pub async fn get_device_auth_ws(&self) -> Result>> { + self.ws_get("/device-auth/ws".to_owned()) + .await + .with_context(|| "failed to connect to auth endpoint") + } + pub async fn check_project_name(&self, project_name: &str) -> Result { let url = format!("{}/projects/name/{project_name}", self.api_url); @@ -483,14 +489,17 @@ impl ShuttleApiClient { pub async fn ws_get(&self, path: String) -> Result>> { let ws_url = self.api_url.clone().replace("http", "ws"); let url = format!("{ws_url}{path}"); - let mut request = url.into_client_request()?; + let mut req = url.into_client_request()?; + + #[cfg(feature = "tracing")] + debug!("WS Request: {} {}", req.method(), req.uri()); if let Some(ref api_key) = self.api_key { let auth_header = Authorization::bearer(api_key.as_ref())?; - request.headers_mut().typed_insert(auth_header); + req.headers_mut().typed_insert(auth_header); } - let (stream, _) = connect_async(request).await.with_context(|| { + let (stream, _) = connect_async(req).await.with_context(|| { #[cfg(feature = "tracing")] error!("failed to connect to websocket"); "could not connect to websocket" diff --git a/api-client/src/util.rs b/api-client/src/util.rs index 84a02b570..486c6b845 100644 --- a/api-client/src/util.rs +++ b/api-client/src/util.rs @@ -19,7 +19,7 @@ impl ToJson for reqwest::Response { .unwrap_or_else(|_| format!("[{} bytes]", bytes.len())); #[cfg(feature = "tracing")] - tracing::trace!(response = %string, "Parsing response to JSON"); + tracing::trace!(response = %string, "Parsing response as JSON"); if matches!( status_code, @@ -28,7 +28,7 @@ impl ToJson for reqwest::Response { serde_json::from_str(&string).context("failed to parse a successful response") } else { #[cfg(feature = "tracing")] - tracing::trace!("Parsing response to common error"); + tracing::trace!("Parsing response as API error"); let res: ApiError = match serde_json::from_str(&string) { Ok(res) => res, diff --git a/cargo-shuttle/Cargo.toml b/cargo-shuttle/Cargo.toml index 945881569..17a578b14 100644 --- a/cargo-shuttle/Cargo.toml +++ b/cargo-shuttle/Cargo.toml @@ -29,13 +29,18 @@ dunce = { workspace = true } flate2 = { workspace = true } futures = { workspace = true } git2 = { version = "0.19.0", default-features = false } -gix = { version = "0.66.0", default-features = false, features = [ +gix = { version = "0.67.0", default-features = false, features = [ "blocking-http-transport-reqwest-rust-tls", "worktree-mutation", ] } globset = "0.4.13" headers = { workspace = true } home = { workspace = true } +# TODO: make local provisioner server use these: +# http = "1" +# http-body-util = "0.1" +# hyper-1 = { package = "hyper", version = "1.0", features = ["full"] } +# hyper-util = { version = "0.1.10", features = ["full"] } hyper = { workspace = true } ignore = "0.4.20" indicatif = "0.17.3" @@ -69,6 +74,6 @@ zip = "2.2.0" [dev-dependencies] assert_cmd = "2.0.6" -rexpect = "0.5.0" +rexpect = "0.6.0" # Publication of this crate will fail if this is changed to a workspace dependency shuttle-common-tests = { path = "../common-tests" } diff --git a/cargo-shuttle/src/args.rs b/cargo-shuttle/src/args.rs index 140ed6d98..68551815d 100644 --- a/cargo-shuttle/src/args.rs +++ b/cargo-shuttle/src/args.rs @@ -12,12 +12,13 @@ use clap::{ Args, Parser, Subcommand, ValueEnum, }; use clap_complete::Shell; -use shuttle_common::constants::{DEFAULT_IDLE_MINUTES, EXAMPLES_REPO}; +use shuttle_common::constants::{DEFAULT_IDLE_MINUTES, EXAMPLES_REPO, SHUTTLE_CONSOLE_URL}; use shuttle_common::resource; #[derive(Parser)] #[command( version, + next_help_heading = "Global options", // Cargo passes in the subcommand name to the invoked executable. Use a // hidden, optional positional argument to deal with it. arg(clap::Arg::new("dummy") @@ -26,10 +27,8 @@ use shuttle_common::resource; .hide(true)) )] pub struct ShuttleArgs { - #[command(flatten)] - pub project_args: ProjectArgs, /// URL for the Shuttle API to target (mainly for development) - #[arg(global = true, long, env = "SHUTTLE_API")] + #[arg(global = true, long, env = "SHUTTLE_API", hide = true)] pub api_url: Option, /// Disable network requests that are not strictly necessary. Limits some features. #[arg(global = true, long, env = "SHUTTLE_OFFLINE")] @@ -40,6 +39,8 @@ pub struct ShuttleArgs { /// Target Shuttle's development environment #[arg(global = true, long, env = "SHUTTLE_BETA", hide = true)] pub beta: bool, + #[command(flatten)] + pub project_args: ProjectArgs, #[command(subcommand)] pub cmd: Command, @@ -51,7 +52,7 @@ pub struct ProjectArgs { /// Specify the working directory #[arg(global = true, long, visible_alias = "wd", default_value = ".", value_parser = OsStringValueParser::new().try_map(parse_path))] pub working_directory: PathBuf, - /// Specify the name or id of the project (overrides crate name) + /// Specify the name or id of the project #[arg(global = true, long = "name", visible_alias = "id")] // in alpha mode, this is always a name pub name_or_id: Option, @@ -93,10 +94,9 @@ impl ProjectArgs { } } -/// A cargo command for the Shuttle platform (https://www.shuttle.rs/) +/// CLI for the Shuttle platform (https://www.shuttle.dev/) /// -/// See the CLI docs (https://docs.shuttle.rs/getting-started/shuttle-commands) -/// for more information. +/// See the CLI docs for more information: https://docs.shuttle.dev/guides/cli #[derive(Subcommand)] pub enum Command { /// Generate a Shuttle project from a template @@ -160,6 +160,7 @@ pub enum GenerateCommand { } #[derive(Args)] +#[command(next_help_heading = "Table options")] pub struct TableArgs { /// Output tables without borders #[arg(long, default_value_t = false)] @@ -197,12 +198,12 @@ pub enum ResourceCommand { /// List the resources for a project #[command(visible_alias = "ls")] List { - #[command(flatten)] - table: TableArgs, - /// Show secrets from resources (e.g. a password in a connection string) #[arg(long, default_value_t = false)] show_secrets: bool, + + #[command(flatten)] + table: TableArgs, }, /// Delete a resource #[command(visible_alias = "rm")] @@ -307,10 +308,17 @@ pub struct ProjectStartArgs { } #[derive(Args, Clone, Debug, Default)] +#[command(next_help_heading = "Login options")] pub struct LoginArgs { - /// API key for the Shuttle platform + /// Prompt to paste the API key instead of opening the browser + #[arg(long, conflicts_with = "api_key", alias = "input")] + pub prompt: bool, + /// Log in with this Shuttle API key #[arg(long)] pub api_key: Option, + /// URL to the Shuttle Console for automatic login + #[arg(long, env = "SHUTTLE_CONSOLE", default_value = SHUTTLE_CONSOLE_URL, hide_default_value = true)] + pub console_url: String, } #[derive(Args, Clone, Debug)] diff --git a/cargo-shuttle/src/config.rs b/cargo-shuttle/src/config.rs index 675348ed2..52e6f2bcf 100644 --- a/cargo-shuttle/src/config.rs +++ b/cargo-shuttle/src/config.rs @@ -4,8 +4,8 @@ use std::path::{Path, PathBuf}; use anyhow::{anyhow, Context, Result}; use serde::{Deserialize, Serialize}; -use shuttle_common::constants::API_URL_BETA; use shuttle_common::constants::API_URL_DEFAULT; +use shuttle_common::constants::API_URL_DEFAULT_BETA; use tracing::trace; use crate::args::ProjectArgs; @@ -423,7 +423,7 @@ impl RequestContext { } else if let Some(api_url) = self.global.as_ref().unwrap().api_url() { api_url } else if beta { - API_URL_BETA.to_string() + API_URL_DEFAULT_BETA.to_string() } else { API_URL_DEFAULT.to_string() } diff --git a/cargo-shuttle/src/lib.rs b/cargo-shuttle/src/lib.rs index fe0b9142a..0d80c69f1 100644 --- a/cargo-shuttle/src/lib.rs +++ b/cargo-shuttle/src/lib.rs @@ -22,7 +22,7 @@ use crossterm::style::Stylize; use dialoguer::{theme::ColorfulTheme, Confirm, Input, Password, Select}; use flate2::write::GzEncoder; use flate2::Compression; -use futures::{StreamExt, TryFutureExt}; +use futures::{SinkExt, StreamExt, TryFutureExt}; use git2::Repository; use globset::{Glob, GlobSetBuilder}; use ignore::overrides::OverrideBuilder; @@ -33,14 +33,15 @@ use reqwest::header::HeaderMap; use shuttle_api_client::ShuttleApiClient; use shuttle_common::{ constants::{ - headers::X_CARGO_SHUTTLE_VERSION, API_URL_BETA, API_URL_DEFAULT, DEFAULT_IDLE_MINUTES, - EXAMPLES_REPO, EXECUTABLE_DIRNAME, RESOURCE_SCHEMA_VERSION, RUNTIME_NAME, - SHUTTLE_IDLE_DOCS_URL, SHUTTLE_LOGIN_URL, SHUTTLE_LOGIN_URL_BETA, STORAGE_DIRNAME, + headers::X_CARGO_SHUTTLE_VERSION, API_URL_DEFAULT, API_URL_DEFAULT_BETA, + DEFAULT_IDLE_MINUTES, EXAMPLES_REPO, EXECUTABLE_DIRNAME, RESOURCE_SCHEMA_VERSION, + RUNTIME_NAME, SHUTTLE_IDLE_DOCS_URL, SHUTTLE_LEGACY_NEW_PROJECT, STORAGE_DIRNAME, TEMPLATES_SCHEMA_VERSION, }, deployment::{DeploymentStateBeta, DEPLOYER_END_MESSAGES_BAD, DEPLOYER_END_MESSAGES_GOOD}, log::LogsRange, models::{ + auth::{KeyMessage, TokenMessage}, deployment::{ deployments_table_beta, get_deployments_table, BuildArgsBeta, BuildArgsRustBeta, BuildMetaBeta, DeploymentRequest, DeploymentRequestBeta, @@ -52,7 +53,7 @@ use shuttle_common::{ resource::{get_certificates_table_beta, get_resource_tables, get_resource_tables_beta}, }, resource::{self, ResourceInput, ShuttleResourceOutput}, - semvers_are_compatible, ApiKey, DatabaseResource, DbInput, LogItem, LogItemBeta, VersionInfo, + semvers_are_compatible, DatabaseResource, DbInput, LogItem, LogItemBeta, VersionInfo, }; use shuttle_proto::{ provisioner::{provisioner_server::Provisioner, DatabaseRequest}, @@ -67,6 +68,7 @@ use tar::Builder; use tokio::io::{AsyncBufReadExt, BufReader}; use tokio::process::Child; use tokio::time::{sleep, Duration}; +use tokio_tungstenite::tungstenite::Message; use tonic::{Request, Status}; use tracing::{debug, error, info, trace}; use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter}; @@ -84,7 +86,7 @@ use crate::provisioner_server::beta::{ProvApiState, ProvisionerServerBeta}; use crate::provisioner_server::LocalProvisioner; use crate::util::{ check_and_warn_runtime_version, generate_completions, generate_manpage, get_templates_schema, - is_dirty, open_gh_issue, update_cargo_shuttle, + is_dirty, open_gh_issue, read_ws_until_text, update_cargo_shuttle, }; const VERSION: &str = env!("CARGO_PKG_VERSION"); @@ -206,7 +208,8 @@ impl Shuttle { } } if let Some(ref url) = args.api_url { - if (!self.beta && url != API_URL_DEFAULT) || (self.beta && url != API_URL_BETA) { + if (!self.beta && url != API_URL_DEFAULT) || (self.beta && url != API_URL_DEFAULT_BETA) + { eprintln!( "{}", format!("INFO: Targeting non-default API: {url}").yellow(), @@ -967,20 +970,29 @@ impl Shuttle { let api_key = match login_args.api_key { Some(api_key) => api_key, None => { - if !offline { - let url = if self.beta { - SHUTTLE_LOGIN_URL_BETA - } else { - SHUTTLE_LOGIN_URL - }; - let _ = webbrowser::open(url); - println!("If your browser did not automatically open, go to {url}"); - } + if login_args.prompt || !self.beta { + // manual input requested (always the case on shuttle.rs) + + if !login_args.prompt && !self.beta { + // if !beta, open console + let url = SHUTTLE_LEGACY_NEW_PROJECT; + let _ = webbrowser::open(url); + println!("If your browser did not automatically open, go to {url}"); + } - Password::with_theme(&ColorfulTheme::default()) - .with_prompt("API key") - .validate_with(|input: &String| ApiKey::parse(input).map(|_| ())) - .interact()? + Password::with_theme(&ColorfulTheme::default()) + .with_prompt("API key") + .validate_with(|input: &String| { + if input.is_empty() { + return Err("Empty API key was provided"); + } + Ok(()) + }) + .interact()? + } else { + // device auth flow via Shuttle Console + self.device_auth(login_args.console_url).await? + } } }; @@ -1005,13 +1017,59 @@ impl Shuttle { Ok(()) } + async fn device_auth(&self, console_url: String) -> Result { + let client = self.client.as_ref().unwrap(); + + // should not have trailing slash + if console_url.ends_with('/') { + eprintln!("WARNING: Console URL is probably incorrect. Ends with '/': {console_url}"); + } + + let (mut tx, mut rx) = client.get_device_auth_ws().await?.split(); + + // keep the socket alive with ping/pong + tokio::spawn(async move { + loop { + tx.send(Message::Ping(Vec::new())).await.unwrap(); + sleep(Duration::from_secs(20)).await; + } + }); + + let token = read_ws_until_text(&mut rx).await?; + let Some(token) = token else { + bail!("Did not receive device auth token over websocket"); + }; + let token = serde_json::from_str::(&token)?.token; + + let url = &format!("{}/device-auth?token={}", console_url, token); + let _ = webbrowser::open(url); + println!("Complete login in Shuttle Console to authenticate CLI."); + println!("If your browser did not automatically open, go to {url}"); + println!(); + println!("{}", format!("Token: {token}").bold()); + println!(); + + let key = read_ws_until_text(&mut rx).await?; + let Some(key) = key else { + bail!("Failed to receive API key over websocket"); + }; + let key = serde_json::from_str::(&key)?.api_key; + + Ok(key) + } + async fn logout(&mut self, logout_args: LogoutArgs) -> Result<()> { if logout_args.reset_api_key { self.reset_api_key() .await .map_err(suggestions::api_key::reset_api_key_failed)?; println!("Successfully reset the API key."); - println!(" -> Go to {SHUTTLE_LOGIN_URL} to get a new one.\n"); + if self.beta { + println!(" -> Use `shuttle login` to get a new one.") + } else { + println!(" -> Go to {SHUTTLE_LEGACY_NEW_PROJECT} to get a new one."); + } + println!(); } self.ctx.clear_api_key()?; println!("Successfully logged out."); @@ -1221,27 +1279,25 @@ impl Shuttle { suggestions::logs::get_logs_failure(err, "Connecting to the logs stream failed") })?; - while let Some(Ok(msg)) = stream.next().await { - if let tokio_tungstenite::tungstenite::Message::Text(line) = msg { - match serde_json::from_str::(&line) { - Ok(log) => { - if args.raw { - println!("{}", log.get_raw_line()) - } else { - println!("{log}") - } + while let Ok(Some(s)) = read_ws_until_text(&mut stream).await { + match serde_json::from_str::(&s) { + Ok(log) => { + if args.raw { + println!("{}", log.get_raw_line()) + } else { + println!("{log}") } - Err(err) => { - debug!(error = %err, "failed to parse message into log item"); + } + Err(err) => { + debug!(error = %err, "failed to parse message into log item"); - let message = if let Ok(err) = serde_json::from_str::(&line) { - err.to_string() - } else { - "failed to parse logs, is your cargo-shuttle outdated?".to_string() - }; + let message = if let Ok(err) = serde_json::from_str::(&s) { + err.to_string() + } else { + "failed to parse logs, is your cargo-shuttle outdated?".to_string() + }; - bail!(message); - } + bail!(message); } } } @@ -2566,46 +2622,44 @@ impl Shuttle { let mut deployer_version_checked = false; let mut runtime_version_checked = false; - loop { - if let Some(Ok(msg)) = stream.next().await { - if let tokio_tungstenite::tungstenite::Message::Text(line) = msg { - let log_item = match serde_json::from_str::(&line) { - Ok(log_item) => log_item, - Err(err) => { - debug!(error = %err, "failed to parse message into log item"); - - let message = if let Ok(err) = serde_json::from_str::(&line) { - err.to_string() - } else { - "failed to parse logs, is your cargo-shuttle outdated?".to_string() - }; - - bail!(message); - } + while let Ok(Some(s)) = read_ws_until_text(&mut stream).await { + let log_item = match serde_json::from_str::(&s) { + Ok(log_item) => log_item, + Err(err) => { + debug!(error = %err, "failed to parse message into log item"); + + let message = if let Ok(err) = serde_json::from_str::(&s) { + err.to_string() + } else { + "failed to parse logs, is your cargo-shuttle outdated?".to_string() }; - if args.raw { - println!("{}", log_item.get_raw_line()) - } else { - println!("{log_item}") - } + bail!(message); + } + }; - // Detect versions of deployer and runtime, and print warnings of outdated. - if !deployer_version_checked - && self.version_info.is_some() - && log_item.line.contains("Deployer version: ") - { - deployer_version_checked = true; - let my_version = &log_item - .line - .split_once("Deployer version: ") - .unwrap() - .1 - .parse::() - .context("parsing deployer version in log stream")?; - let latest_version = &self.version_info.as_ref().unwrap().deployer; - if latest_version > my_version { - self.version_warnings.push( + if args.raw { + println!("{}", log_item.get_raw_line()) + } else { + println!("{log_item}") + } + + // Detect versions of deployer and runtime, and print warnings of outdated. + if !deployer_version_checked + && self.version_info.is_some() + && log_item.line.contains("Deployer version: ") + { + deployer_version_checked = true; + let my_version = &log_item + .line + .split_once("Deployer version: ") + .unwrap() + .1 + .parse::() + .context("parsing deployer version in log stream")?; + let latest_version = &self.version_info.as_ref().unwrap().deployer; + if latest_version > my_version { + self.version_warnings.push( formatdoc! {" Warning: A newer version of shuttle-deployer is available ({latest_version}). @@ -2614,28 +2668,28 @@ impl Shuttle { .yellow() .to_string(), ) - } - } - if !runtime_version_checked - && self.version_info.is_some() - && log_item - .line - .contains("shuttle-runtime executable started (version ") - { - runtime_version_checked = true; - let my_version = &log_item - .line - .split_once("shuttle-runtime executable started (version ") - .unwrap() - .1 - .split_once(')') - .unwrap() - .0 - .parse::() - .context("parsing runtime version in log stream")?; - let latest_version = &self.version_info.as_ref().unwrap().runtime; - if latest_version > my_version { - self.version_warnings.push( + } + } + if !runtime_version_checked + && self.version_info.is_some() + && log_item + .line + .contains("shuttle-runtime executable started (version ") + { + runtime_version_checked = true; + let my_version = &log_item + .line + .split_once("shuttle-runtime executable started (version ") + .unwrap() + .1 + .split_once(')') + .unwrap() + .0 + .parse::() + .context("parsing runtime version in log stream")?; + let latest_version = &self.version_info.as_ref().unwrap().runtime; + if latest_version > my_version { + self.version_warnings.push( formatdoc! {" Warning: A newer version of shuttle-runtime is available ({latest_version}). @@ -2644,45 +2698,29 @@ impl Shuttle { .yellow() .to_string(), ) - } - } + } + } - // Determine when to stop listening to the log stream - if DEPLOYER_END_MESSAGES_BAD - .iter() - .any(|m| log_item.line.contains(m)) - { - println!(); - println!("{}", "Deployment crashed".red()); - println!(); - println!("Run the following for more details"); - println!(); - println!("cargo shuttle logs {}", &deployment.id); + // Determine when to stop listening to the log stream + if DEPLOYER_END_MESSAGES_BAD + .iter() + .any(|m| log_item.line.contains(m)) + { + println!(); + println!("{}", "Deployment crashed".red()); + println!(); + println!("Run the following for more details"); + println!(); + println!("cargo shuttle logs {}", &deployment.id); - bail!(""); - } - if DEPLOYER_END_MESSAGES_GOOD - .iter() - .any(|m| log_item.line.contains(m)) - { - debug!("received end message, breaking deployment stream"); - break; - } - } - } else { - eprintln!("--- Reconnecting websockets logging ---"); - // A wait time short enough for not much state to have changed, long enough that - // the terminal isn't completely spammed - sleep(Duration::from_millis(100)).await; - stream = client - .get_logs_ws(project_name, &deployment.id.to_string(), LogsRange::All) - .await - .map_err(|err| { - suggestions::deploy::deployment_setup_failure( - err, - "Connecting to the deployment logs failed", - ) - })?; + bail!(""); + } + if DEPLOYER_END_MESSAGES_GOOD + .iter() + .any(|m| log_item.line.contains(m)) + { + debug!("received end message, breaking deployment stream"); + break; } } diff --git a/cargo-shuttle/src/util.rs b/cargo-shuttle/src/util.rs index 9ada6b08f..ce38c34bb 100644 --- a/cargo-shuttle/src/util.rs +++ b/cargo-shuttle/src/util.rs @@ -11,6 +11,7 @@ use anyhow::{bail, Context, Result}; use clap::CommandFactory; use clap_complete::{generate, Shell}; use clap_mangen::Man; +use futures::StreamExt; use git2::{Repository, StatusOptions}; use indoc::writedoc; use shuttle_common::{ @@ -18,6 +19,7 @@ use shuttle_common::{ semvers_are_compatible, templates::TemplatesSchema, }; +use tokio_tungstenite::tungstenite::{self, Message}; use tracing::{debug, trace, warn}; use crate::{Binary, ShuttleArgs}; @@ -272,3 +274,16 @@ pub async fn update_cargo_shuttle(preview: bool) -> Result<()> { Ok(()) } + +pub async fn read_ws_until_text(rx: &mut T) -> Result> +where + T: StreamExt> + Unpin, +{ + while let Some(Ok(msg)) = rx.next().await { + if let Message::Text(s) = msg { + return Ok(Some(s)); + } + } + + Ok(None) +} diff --git a/common/src/constants.rs b/common/src/constants.rs index bb61ad382..902d54efc 100644 --- a/common/src/constants.rs +++ b/common/src/constants.rs @@ -7,20 +7,23 @@ pub const STORAGE_DIRNAME: &str = ".shuttle-storage"; // URLs pub const API_URL_LOCAL: &str = "http://localhost:8001"; -pub const API_URL_PRODUCTION: &str = "https://api.shuttle.rs"; -pub const API_URL_BETA: &str = "https://api.shuttle.dev"; +pub const API_URL_RS: &str = "https://api.shuttle.rs"; +pub const API_URL_DEFAULT_BETA: &str = "https://api.shuttle.dev"; #[cfg(debug_assertions)] pub const API_URL_DEFAULT: &str = API_URL_LOCAL; #[cfg(not(debug_assertions))] -pub const API_URL_DEFAULT: &str = API_URL_PRODUCTION; +pub const API_URL_DEFAULT: &str = API_URL_RS; pub const SHUTTLE_STATUS_URL: &str = "https://status.shuttle.rs"; -pub const SHUTTLE_LOGIN_URL: &str = "https://console.shuttle.rs/new-project"; -pub const SHUTTLE_LOGIN_URL_BETA: &str = "https://console.shuttle.dev/new-project"; + +pub const SHUTTLE_LEGACY_NEW_PROJECT: &str = "https://console.shuttle.rs/new-project"; +pub const SHUTTLE_CONSOLE_URL: &str = "https://console.shuttle.dev"; + +pub const SHUTTLE_INSTALL_DOCS_URL: &str = "https://docs.shuttle.dev/getting-started/installation"; +pub const SHUTTLE_IDLE_DOCS_URL: &str = "https://docs.shuttle.rs/getting-started/idle-projects"; + pub const SHUTTLE_GH_REPO_URL: &str = "https://github.com/shuttle-hq/shuttle"; pub const SHUTTLE_GH_ISSUE_URL: &str = "https://github.com/shuttle-hq/shuttle/issues/new/choose"; -pub const SHUTTLE_INSTALL_DOCS_URL: &str = "https://docs.shuttle.rs/getting-started/installation"; -pub const SHUTTLE_IDLE_DOCS_URL: &str = "https://docs.shuttle.rs/getting-started/idle-projects"; pub const EXAMPLES_REPO: &str = "https://github.com/shuttle-hq/shuttle-examples"; pub const EXAMPLES_README: &str = "https://github.com/shuttle-hq/shuttle-examples#how-to-clone-run-and-deploy-an-example"; diff --git a/common/src/models/auth.rs b/common/src/models/auth.rs new file mode 100644 index 000000000..f8a6b8a08 --- /dev/null +++ b/common/src/models/auth.rs @@ -0,0 +1,11 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Deserialize, Serialize)] +pub struct TokenMessage { + pub token: String, +} + +#[derive(Deserialize, Serialize)] +pub struct KeyMessage { + pub api_key: String, +} diff --git a/common/src/models/mod.rs b/common/src/models/mod.rs index 03e6aba1a..b8164a166 100644 --- a/common/src/models/mod.rs +++ b/common/src/models/mod.rs @@ -1,4 +1,5 @@ pub mod admin; +pub mod auth; pub mod deployment; pub mod error; pub mod project; diff --git a/resources/persist/Cargo.toml b/resources/persist/Cargo.toml index a4a72e3e8..72d9628dd 100644 --- a/resources/persist/Cargo.toml +++ b/resources/persist/Cargo.toml @@ -12,4 +12,4 @@ async-trait = "0.1.56" bincode = "1.2.1" serde = { version = "1", features = ["derive"] } shuttle-service = { path = "../../service", version = "0.48.0" } -thiserror = "1.0.32" +thiserror = "2" diff --git a/service/src/builder.rs b/service/src/builder.rs index 7c29e3e0c..2dd5d229d 100644 --- a/service/src/builder.rs +++ b/service/src/builder.rs @@ -212,6 +212,8 @@ async fn compile( } let target_path = target_path.into(); + // TODO?: Use https://crates.io/crates/escargot instead + let mut cmd = tokio::process::Command::new("cargo"); cmd.arg("build") .arg("--manifest-path")