chadtmiller.com/knotless
git that lives in your Atmosphere account
1
10
A Cargo registry says at its me what a token is, where cargo login points
crates/knotless-serve/src/web/cargo.rs+19−0
| @@ -285,6 +285,25 @@ pub(super) async fn config( | ||
Ok(axum::Json(body).into_response()) | ||
} | ||
| ||
/// `me`, where `cargo login` sends its user for a token: what one is. | ||
pub(super) async fn me( | ||
State(app): State<Arc<App>>, | ||
Path((did, key)): Path<(String, String)>, | ||
) -> Answer { | ||
opened(&app, &did, &key)?; | ||
let body = format!( | ||
"The token for this registry is a handle and an app password, \ | ||
written <handle>:<app password>, such as alice.example.com:abcd-efgh-ijkl-mnop.\n\n\ | ||
Only {did}, the repository's owner, publishes and yanks here. \ | ||
Make an app password in your PDS's settings (in Bluesky, \ | ||
Settings, then Privacy and security, then App passwords), \ | ||
then give the token to cargo login.\n\n\ | ||
Reading the registry needs no token.\n" | ||
); | ||
let kind = (header::CONTENT_TYPE, "text/plain; charset=utf-8"); | ||
Ok(([kind], body).into_response()) | ||
} | ||
| ||
/// A crate's file of the index, asked again each time, at the cost of a 304. | ||
pub(super) async fn index( | ||
State(app): State<Arc<App>>, | ||
crates/knotless-serve/src/web.rs+1−0
| @@ -276,6 +276,7 @@ pub fn routes() -> Router<Arc<App>> { | ||
get(releases::download), | ||
) | ||
.route("/cargo/{did}/{key}/config.json", get(cargo::config)) | ||
.route("/cargo/{did}/{key}/me", get(cargo::me)) | ||
.route("/cargo/{did}/{key}/api/v1/crates", get(cargo::search)) | ||
.route( | ||
"/cargo/{did}/{key}/api/v1/crates/new", | ||
crates/knotless-serve/tests/web.rs+6−0
| @@ -3366,6 +3366,12 @@ fn a_cargo_registry() { | ||
format!("{}{here}/dl/{{crate}}/{{version}}/download", site.base) | ||
); | ||
| ||
// Where cargo login sends its user, what the token is. | ||
let (status, page) = site.status(&format!("{here}/me")); | ||
assert_eq!(status, 200); | ||
assert!(page.contains("<handle>:<app password>"), "{page}"); | ||
assert!(page.contains(&did), "{page}"); | ||
| ||
let root = owner.path("cargo"); | ||
let home = root.join("home"); | ||
std::fs::create_dir_all(&home).unwrap(); | ||
docs/reference/api.md+1−0
| @@ -524,6 +524,7 @@ password>`, which logs in to the owner's PDS. | ||
| Route | | | ||
| --- | --- | | ||
| `GET config.json` | `{dl, api}`, at the request's origin | | ||
| `GET me` | what a token is, as text: where `cargo login` sends its user | | ||
| `GET <index path>` | a crate's file of the index, by Cargo's layout (`1/a`, `2/ab`, `3/a/abc`, `ab/cd/abcd`): a line per version, the oldest first, `no-cache`, with an `ETag`; 304 to one seen, 404 for none | | ||
| `GET dl/<name>/<version>/download` | the `.crate`, as a release's files are sent | | ||
| `PUT api/v1/crates/new` | as Cargo publishes: the crate uploaded to the owner's PDS and its release made, at most 64 MiB. 400 for a body that is not one, a name or version a release does not take, a `Cargo.toml` missing, over 1 MiB or saying otherwise, an index line over 100,000 bytes, or a version published already. Once the release is made it answers 200, even should reading it back or indexing it fail, as the feed indexes it soon after | | ||