···7878 UrlKey { Url = "url" }
7979 CiLogsKey { Host = "host", Port = "port", Repo = "repo", Sha = "sha" }
8080 GreetingKey { User = "user", Knot = "knot" }
8181+ AuthorizedKey { Authorized = "authorized" }
8182 CountKey { Count = "count" }
8283 RefKey { Ref = "ref" }
8384 ErrorKey { Error = "error" }
···148149 "This knot serves git over ssh, so there's no shell here. :P",
149150 "Clone repo with: git clone {knot}:<repoDID>"
150151 ],
152152+ greeting_unknown: Lines<KnotKey> = [
153153+ "Hi there! This is the {knot} knot.",
154154+ "This knot serves git over ssh, so there's no shell here. :P",
155155+ "Clone repo with: git clone {knot}:<repoDID>",
156156+ "Publish your ssh key to your atproto account so this knot can identify your pushes.",
157157+ "Put your handle in the url, as in yourhandle@{knot}:<repoDID>, so your ssh client can find your registered key on its own."
158158+ ],
151159 unsupported_command: Line<NoKeys> = "knot: unsupported command",
152160 too_many_operations: Line<NoKeys> = "knot: too many concurrent operations from your address, try again shortly",
153161 repo_not_found: Line<NoKeys> = "knot: repository not found",
154162 index_warming: Line<NoKeys> = "knot: repository index is warming, retry shortly",
155163 lfs_disabled: Line<NoKeys> = "knot: LFS isn't enabled on this knot",
156156- key_not_registered: Line<NoKeys> = "knot: your ssh key isn't registered to a user authorized to push here. If you offer several keys, make sure the registered one is offered first.",
164164+ key_not_registered: Line<AuthorizedKey> = "knot: this ssh key doesn't match any key published by the accounts that may push here. Authorized: {authorized}. If your agent offers several keys, add -o IdentitiesOnly=yes so it offers your registered key.",
165165+ identity_unavailable: Line<NoKeys> = "knot: couldn't read the account records needed to check your ssh key, retry shortly",
157166 push_denied: Line<NoKeys> = "knot: you aren't authorized to push to this repository.",
158167 shutting_down: Line<NoKeys> = "knot: server is shutting down",
159168 archive_malformed: Line<NoKeys> = "knot: malformed upload-archive request",
···304313 });
305314 assert!(lines[0].contains("@nel.pet"));
306315 assert!(lines.iter().any(|line| line.contains("oyster.cafe")));
316316+ }
317317+318318+ #[test]
319319+ fn an_unidentified_visitor_is_greeted_and_shown_what_a_push_needs() {
320320+ let catalog = Catalog::defaults();
321321+ let lines = catalog
322322+ .ssh
323323+ .greeting_unknown
324324+ .lines(|KnotKey::Knot| "oyster.cafe".to_string());
325325+ assert!(lines[0].contains("oyster.cafe"));
326326+ assert!(
327327+ lines.iter().any(|line| line.contains("ssh key")),
328328+ "a visitor the knot can't identify learns what a push needs: {lines:?}"
329329+ );
330330+331331+ let denial = catalog
332332+ .ssh
333333+ .key_not_registered
334334+ .line(|AuthorizedKey::Authorized| "@nel.pet".to_string());
335335+ assert!(
336336+ denial.contains("@nel.pet"),
337337+ "the denial lists who may push instead: {denial}"
338338+ );
307339 }
308340309341 #[test]
···516516# Default value: ["Hi {user}! You're authenticated to {knot} knot.", "This knot serves git over ssh, so there's no shell here. :P", "Clone repo with: git clone {knot}:<repoDID>"]
517517#greeting = ["Hi {user}! You're authenticated to {knot} knot.", "This knot serves git over ssh, so there's no shell here. :P", "Clone repo with: git clone {knot}:<repoDID>"]
518518519519+# Default value: ["Hi there! This is the {knot} knot.", "This knot serves git over ssh, so there's no shell here. :P", "Clone repo with: git clone {knot}:<repoDID>", "Publish your ssh key to your atproto account so this knot can identify your pushes.", "Put your handle in the url, as in yourhandle@{knot}:<repoDID>, so your ssh client can find your registered key on its own."]
520520+#greeting_unknown = ["Hi there! This is the {knot} knot.", "This knot serves git over ssh, so there's no shell here. :P", "Clone repo with: git clone {knot}:<repoDID>", "Publish your ssh key to your atproto account so this knot can identify your pushes.", "Put your handle in the url, as in yourhandle@{knot}:<repoDID>, so your ssh client can find your registered key on its own."]
521521+519522# Default value: "knot: unsupported command"
520523#unsupported_command = "knot: unsupported command"
521524···531534# Default value: "knot: LFS isn't enabled on this knot"
532535#lfs_disabled = "knot: LFS isn't enabled on this knot"
533536534534-# Default value: "knot: your ssh key isn't registered to a user authorized to push here. If you offer several keys, make sure the registered one is offered first."
535535-#key_not_registered = "knot: your ssh key isn't registered to a user authorized to push here. If you offer several keys, make sure the registered one is offered first."
537537+# Default value: "knot: this ssh key doesn't match any key published by the accounts that may push here. Authorized: {authorized}. If your agent offers several keys, add -o IdentitiesOnly=yes so it offers your registered key."
538538+#key_not_registered = "knot: this ssh key doesn't match any key published by the accounts that may push here. Authorized: {authorized}. If your agent offers several keys, add -o IdentitiesOnly=yes so it offers your registered key."
539539+540540+# Default value: "knot: couldn't read the account records needed to check your ssh key, retry shortly"
541541+#identity_unavailable = "knot: couldn't read the account records needed to check your ssh key, retry shortly"
536542537543# Default value: "knot: you aren't authorized to push to this repository."
538544#push_denied = "knot: you aren't authorized to push to this repository."