diff options
| author | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 16:15:55 +0000 |
|---|---|---|
| committer | DanConwayDev <DanConwayDev@protonmail.com> | 2025-12-03 16:15:55 +0000 |
| commit | dd1b44132199aa72c2b699e1160fbe6b885f0ef6 (patch) | |
| tree | a4f3ea50770f8ef22d5f5140e79bbfddec563b0d /src | |
| parent | 2591dbf7498e2300a42928ac9fbec454732e66f0 (diff) | |
landing page: display relay inforamtion document
Diffstat (limited to 'src')
| -rw-r--r-- | src/http/landing.rs | 133 | ||||
| -rw-r--r-- | src/http/nip11.rs | 8 |
2 files changed, 133 insertions, 8 deletions
diff --git a/src/http/landing.rs b/src/http/landing.rs index c76a7e6..8ab4a68 100644 --- a/src/http/landing.rs +++ b/src/http/landing.rs | |||
| @@ -398,7 +398,7 @@ fn generate_nip_cards(nip11: &RelayInformationDocument) -> String { | |||
| 398 | if let Some(meta) = metadata.get(nip) { | 398 | if let Some(meta) = metadata.get(nip) { |
| 399 | html.push_str(&format!( | 399 | html.push_str(&format!( |
| 400 | r#"<div class="card"> | 400 | r#"<div class="card"> |
| 401 | <div class="card-title"><span class="badge">NIP-{:02}</span> {}</div> | 401 | <div class="card-title"><span class="badge badge-nip">NIP-{:02}</span> {}</div> |
| 402 | <div class="card-desc">{}</div> | 402 | <div class="card-desc">{}</div> |
| 403 | </div>"#, | 403 | </div>"#, |
| 404 | nip, meta.title, meta.description | 404 | nip, meta.title, meta.description |
| @@ -407,7 +407,7 @@ fn generate_nip_cards(nip11: &RelayInformationDocument) -> String { | |||
| 407 | // Fallback for unknown NIPs - still show them | 407 | // Fallback for unknown NIPs - still show them |
| 408 | html.push_str(&format!( | 408 | html.push_str(&format!( |
| 409 | r#"<div class="card"> | 409 | r#"<div class="card"> |
| 410 | <div class="card-title"><span class="badge">NIP-{:02}</span></div> | 410 | <div class="card-title"><span class="badge badge-nip">NIP-{:02}</span></div> |
| 411 | </div>"#, | 411 | </div>"#, |
| 412 | nip | 412 | nip |
| 413 | )); | 413 | )); |
| @@ -418,6 +418,129 @@ fn generate_nip_cards(nip11: &RelayInformationDocument) -> String { | |||
| 418 | html | 418 | html |
| 419 | } | 419 | } |
| 420 | 420 | ||
| 421 | /// Escape HTML special characters | ||
| 422 | fn escape_html(s: &str) -> String { | ||
| 423 | s.replace('&', "&") | ||
| 424 | .replace('<', "<") | ||
| 425 | .replace('>', ">") | ||
| 426 | .replace('"', """) | ||
| 427 | .replace('\'', "'") | ||
| 428 | } | ||
| 429 | |||
| 430 | /// Generate table rows for NIP-11 relay information | ||
| 431 | fn generate_relay_info_rows(nip11: &RelayInformationDocument) -> String { | ||
| 432 | let mut html = String::new(); | ||
| 433 | |||
| 434 | // Follow NIP-11 document order: | ||
| 435 | // name | ||
| 436 | html.push_str(&format!( | ||
| 437 | r#"<tr><th>name</th><td>{}</td></tr>"#, | ||
| 438 | escape_html(&nip11.name) | ||
| 439 | )); | ||
| 440 | html.push('\n'); | ||
| 441 | |||
| 442 | // description | ||
| 443 | html.push_str(&format!( | ||
| 444 | r#"<tr><th>description</th><td>{}</td></tr>"#, | ||
| 445 | escape_html(&nip11.description) | ||
| 446 | )); | ||
| 447 | html.push('\n'); | ||
| 448 | |||
| 449 | // pubkey (if present) | ||
| 450 | if let Some(ref pubkey) = nip11.pubkey { | ||
| 451 | html.push_str(&format!( | ||
| 452 | r#"<tr><th>pubkey</th><td><code>{}</code></td></tr>"#, | ||
| 453 | escape_html(pubkey) | ||
| 454 | )); | ||
| 455 | html.push('\n'); | ||
| 456 | } | ||
| 457 | |||
| 458 | // contact (if present) | ||
| 459 | if let Some(ref contact) = nip11.contact { | ||
| 460 | html.push_str(&format!( | ||
| 461 | r#"<tr><th>contact</th><td>{}</td></tr>"#, | ||
| 462 | escape_html(contact) | ||
| 463 | )); | ||
| 464 | html.push('\n'); | ||
| 465 | } | ||
| 466 | |||
| 467 | // supported_nips | ||
| 468 | let nips_str = nip11 | ||
| 469 | .supported_nips | ||
| 470 | .iter() | ||
| 471 | .map(|n| n.to_string()) | ||
| 472 | .collect::<Vec<_>>() | ||
| 473 | .join(", "); | ||
| 474 | html.push_str(&format!( | ||
| 475 | r#"<tr><th>supported_nips</th><td>{}</td></tr>"#, | ||
| 476 | nips_str | ||
| 477 | )); | ||
| 478 | html.push('\n'); | ||
| 479 | |||
| 480 | // software | ||
| 481 | html.push_str(&format!( | ||
| 482 | r#"<tr><th>software</th><td><a href="{}">{}</a></td></tr>"#, | ||
| 483 | escape_html(&nip11.software), | ||
| 484 | escape_html(&nip11.software) | ||
| 485 | )); | ||
| 486 | html.push('\n'); | ||
| 487 | |||
| 488 | // version | ||
| 489 | html.push_str(&format!( | ||
| 490 | r#"<tr><th>version</th><td>{}</td></tr>"#, | ||
| 491 | escape_html(&nip11.version) | ||
| 492 | )); | ||
| 493 | html.push('\n'); | ||
| 494 | |||
| 495 | // icon (if present) | ||
| 496 | if let Some(ref icon) = nip11.icon { | ||
| 497 | html.push_str(&format!( | ||
| 498 | r#"<tr><th>icon</th><td><a href="{}">{}</a></td></tr>"#, | ||
| 499 | escape_html(icon), | ||
| 500 | escape_html(icon) | ||
| 501 | )); | ||
| 502 | html.push('\n'); | ||
| 503 | } | ||
| 504 | |||
| 505 | // GRASP-01 Extensions: | ||
| 506 | // supported_grasps | ||
| 507 | let grasps_str = nip11.supported_grasps.join(", "); | ||
| 508 | html.push_str(&format!( | ||
| 509 | r#"<tr><th>supported_grasps</th><td>{}</td></tr>"#, | ||
| 510 | escape_html(&grasps_str) | ||
| 511 | )); | ||
| 512 | html.push('\n'); | ||
| 513 | |||
| 514 | // repo_acceptance_criteria | ||
| 515 | html.push_str(&format!( | ||
| 516 | r#"<tr><th>repo_acceptance_criteria</th><td>{}</td></tr>"#, | ||
| 517 | escape_html(&nip11.repo_acceptance_criteria) | ||
| 518 | )); | ||
| 519 | html.push('\n'); | ||
| 520 | |||
| 521 | // curation (if present) | ||
| 522 | if let Some(ref curation) = nip11.curation { | ||
| 523 | html.push_str(&format!( | ||
| 524 | r#"<tr><th>curation</th><td>{}</td></tr>"#, | ||
| 525 | escape_html(curation) | ||
| 526 | )); | ||
| 527 | html.push('\n'); | ||
| 528 | } | ||
| 529 | |||
| 530 | html | ||
| 531 | } | ||
| 532 | |||
| 533 | /// Generate the relay icon HTML for the header | ||
| 534 | fn generate_relay_icon_html(nip11: &RelayInformationDocument) -> String { | ||
| 535 | match &nip11.icon { | ||
| 536 | Some(icon_url) => format!( | ||
| 537 | r#"<img src="{}" alt="Relay Icon" class="relay-icon">"#, | ||
| 538 | escape_html(icon_url) | ||
| 539 | ), | ||
| 540 | None => String::new(), | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 421 | /// Generate the HTML landing page | 544 | /// Generate the HTML landing page |
| 422 | pub fn get_html(config: &Config) -> String { | 545 | pub fn get_html(config: &Config) -> String { |
| 423 | // Get NIP-11 document for supported NIPs and GRASPs | 546 | // Get NIP-11 document for supported NIPs and GRASPs |
| @@ -430,6 +553,8 @@ pub fn get_html(config: &Config) -> String { | |||
| 430 | let hero_tags = generate_hero_tags(&nip11); | 553 | let hero_tags = generate_hero_tags(&nip11); |
| 431 | let grasp_cards = generate_grasp_cards(&nip11); | 554 | let grasp_cards = generate_grasp_cards(&nip11); |
| 432 | let nip_cards = generate_nip_cards(&nip11); | 555 | let nip_cards = generate_nip_cards(&nip11); |
| 556 | let relay_info_rows = generate_relay_info_rows(&nip11); | ||
| 557 | let relay_icon = generate_relay_icon_html(&nip11); | ||
| 433 | 558 | ||
| 434 | format!( | 559 | format!( |
| 435 | include_str!("../../templates/landing.html"), | 560 | include_str!("../../templates/landing.html"), |
| @@ -437,12 +562,16 @@ pub fn get_html(config: &Config) -> String { | |||
| 437 | relay_name = config.relay_name(), | 562 | relay_name = config.relay_name(), |
| 438 | relay_description = config.relay_description, | 563 | relay_description = config.relay_description, |
| 439 | version = get_version(), | 564 | version = get_version(), |
| 565 | nip11_version = escape_html(&nip11.version), | ||
| 440 | curation = curation, | 566 | curation = curation, |
| 567 | repo_acceptance_criteria = escape_html(&nip11.repo_acceptance_criteria), | ||
| 441 | theme_toggle = get_theme_toggle_html(), | 568 | theme_toggle = get_theme_toggle_html(), |
| 442 | theme_script = get_theme_script(), | 569 | theme_script = get_theme_script(), |
| 443 | hero_tags = hero_tags, | 570 | hero_tags = hero_tags, |
| 444 | grasp_cards = grasp_cards, | 571 | grasp_cards = grasp_cards, |
| 445 | nip_cards = nip_cards, | 572 | nip_cards = nip_cards, |
| 573 | relay_info_rows = relay_info_rows, | ||
| 574 | relay_icon = relay_icon, | ||
| 446 | ) | 575 | ) |
| 447 | } | 576 | } |
| 448 | 577 | ||
diff --git a/src/http/nip11.rs b/src/http/nip11.rs index 2a37385..1ed80de 100644 --- a/src/http/nip11.rs +++ b/src/http/nip11.rs | |||
| @@ -76,11 +76,7 @@ impl RelayInformationDocument { | |||
| 76 | 76 | ||
| 77 | // GRASP-01 Extensions | 77 | // GRASP-01 Extensions |
| 78 | supported_grasps: vec!["GRASP-01".to_string()], | 78 | supported_grasps: vec!["GRASP-01".to_string()], |
| 79 | repo_acceptance_criteria: format!( | 79 | repo_acceptance_criteria: "None".to_string(), |
| 80 | "Repositories must list this relay ({}) in both 'clone' and 'relays' tags of kind 30617 announcements. \ | ||
| 81 | All other events must reference accepted repositories or accepted events.", | ||
| 82 | config.domain | ||
| 83 | ), | ||
| 84 | curation: None, // Not a curated relay - only SPAM prevention via GRASP-01 policy | 80 | curation: None, // Not a curated relay - only SPAM prevention via GRASP-01 policy |
| 85 | } | 81 | } |
| 86 | } | 82 | } |
| @@ -118,7 +114,7 @@ mod tests { | |||
| 118 | assert!(doc.supported_nips.contains(&34)); | 114 | assert!(doc.supported_nips.contains(&34)); |
| 119 | assert!(doc.supported_nips.contains(&77)); | 115 | assert!(doc.supported_nips.contains(&77)); |
| 120 | assert_eq!(doc.supported_grasps, vec!["GRASP-01"]); | 116 | assert_eq!(doc.supported_grasps, vec!["GRASP-01"]); |
| 121 | assert!(doc.repo_acceptance_criteria.contains("relay.example.com")); | 117 | assert!(doc.repo_acceptance_criteria.contains("None")); |
| 122 | assert!(doc.curation.is_none()); | 118 | assert!(doc.curation.is_none()); |
| 123 | assert_eq!( | 119 | assert_eq!( |
| 124 | doc.icon, | 120 | doc.icon, |