Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol. wisp.place

fix acceptable use

+559 -3
+552
apps/main-app/public/editor/acceptable-use.html
··· 1 + <!DOCTYPE html> 2 + <html lang="en"> 3 + <head> 4 + <meta charset="UTF-8"> 5 + <meta name="viewport" content="width=device-width, initial-scale=1.0"> 6 + <title>Acceptable Use Policy - wisp.place</title> 7 + <link rel="icon" type="image/x-icon" href="../favicon.ico"> 8 + <link rel="preconnect" href="https://fonts.googleapis.com"> 9 + <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> 10 + <link href="https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet"> 11 + <style> 12 + * { margin: 0; padding: 0; box-sizing: border-box; } 13 + 14 + :root { 15 + --bg: oklch(0.92 0.012 35); 16 + --bg-alt: oklch(0.88 0.01 35); 17 + --text: oklch(0.15 0.015 30); 18 + --text-muted: oklch(0.35 0.02 30); 19 + --text-subtle: oklch(0.50 0.02 30); 20 + --border: oklch(0.30 0.025 35); 21 + --border-light: oklch(0.65 0.02 30); 22 + --accent: oklch(0.65 0.18 345); 23 + --cta-bg: oklch(0.30 0.025 35); 24 + --cta-text: oklch(0.96 0.008 35); 25 + --code-bg: oklch(0.95 0.008 35); 26 + --success: oklch(0.65 0.20 145); 27 + --red: oklch(0.60 0.20 25); 28 + --yellow: oklch(0.70 0.15 85); 29 + --blue: oklch(0.60 0.15 240); 30 + } 31 + 32 + @media (prefers-color-scheme: dark) { 33 + :root { 34 + --bg: oklch(0.23 0.015 285); 35 + --bg-alt: oklch(0.20 0.015 285); 36 + --text: oklch(0.90 0.005 285); 37 + --text-muted: oklch(0.72 0.01 285); 38 + --text-subtle: oklch(0.55 0.01 285); 39 + --border: oklch(0.90 0.005 285); 40 + --border-light: oklch(0.38 0.02 285); 41 + --accent: oklch(0.85 0.08 5); 42 + --cta-bg: oklch(0.70 0.10 295); 43 + --cta-text: oklch(0.23 0.015 285); 44 + --code-bg: oklch(0.28 0.015 285); 45 + --success: oklch(0.65 0.20 145); 46 + --red: oklch(0.65 0.20 25); 47 + --yellow: oklch(0.75 0.15 85); 48 + --blue: oklch(0.65 0.18 240); 49 + } 50 + } 51 + 52 + body { 53 + font-family: "JetBrains Mono", monospace; 54 + background: var(--bg); 55 + color: var(--text); 56 + line-height: 1.6; 57 + min-height: 100vh; 58 + display: flex; 59 + flex-direction: column; 60 + } 61 + 62 + header { 63 + border-bottom: 1px solid var(--border-light); 64 + padding: 1rem 2rem; 65 + background: var(--bg); 66 + position: sticky; 67 + top: 0; 68 + z-index: 100; 69 + } 70 + 71 + .header-inner { 72 + max-width: 1100px; 73 + margin: 0 auto; 74 + display: flex; 75 + justify-content: space-between; 76 + align-items: center; 77 + } 78 + 79 + .logo { 80 + font-size: 1.125rem; 81 + font-weight: 700; 82 + color: var(--text); 83 + letter-spacing: -0.02em; 84 + display: flex; 85 + align-items: center; 86 + gap: 0.5rem; 87 + } 88 + 89 + .logo img { width: 2rem; height: 2rem; } 90 + 91 + .back-link { 92 + color: var(--text-muted); 93 + text-decoration: none; 94 + font-size: 0.875rem; 95 + } 96 + 97 + .back-link:hover { color: var(--text); } 98 + 99 + .hero { 100 + background: linear-gradient(to bottom, var(--code-bg), var(--bg)); 101 + border-bottom: 1px solid var(--border-light); 102 + padding: 4rem 1rem; 103 + text-align: center; 104 + } 105 + 106 + .hero-content { max-width: 900px; margin: 0 auto; } 107 + 108 + .hero-icon { 109 + display: inline-flex; 110 + align-items: center; 111 + justify-content: center; 112 + width: 4rem; 113 + height: 4rem; 114 + border-radius: 50%; 115 + background: var(--code-bg); 116 + margin-bottom: 1.5rem; 117 + } 118 + 119 + h1 { 120 + font-size: 2.5rem; 121 + margin-bottom: 1.5rem; 122 + color: var(--text); 123 + } 124 + 125 + .meta { 126 + display: flex; 127 + align-items: center; 128 + justify-content: center; 129 + gap: 1.5rem; 130 + font-size: 0.875rem; 131 + color: var(--text-muted); 132 + } 133 + 134 + .meta-divider { 135 + width: 1px; 136 + height: 1rem; 137 + background: var(--border-light); 138 + } 139 + 140 + .container { 141 + max-width: 900px; 142 + margin: 0 auto; 143 + padding: 3rem 1rem; 144 + } 145 + 146 + article { margin-bottom: 3rem; } 147 + 148 + section { margin-bottom: 3rem; } 149 + 150 + h2 { 151 + font-size: 1.875rem; 152 + margin-bottom: 1.5rem; 153 + color: var(--text); 154 + display: flex; 155 + align-items: center; 156 + gap: 0.75rem; 157 + } 158 + 159 + h3 { 160 + font-size: 1.5rem; 161 + margin-bottom: 1rem; 162 + color: var(--text); 163 + } 164 + 165 + p { 166 + color: var(--text-muted); 167 + margin-bottom: 1rem; 168 + font-size: 1rem; 169 + line-height: 1.7; 170 + } 171 + 172 + strong { color: var(--text); font-weight: 600; } 173 + 174 + .card { 175 + background: var(--bg-alt); 176 + border: 1px solid var(--border-light); 177 + border-radius: 0.5rem; 178 + padding: 1.5rem; 179 + margin-bottom: 2rem; 180 + } 181 + 182 + .card.success { 183 + background: color-mix(in oklch, var(--success) 5%, var(--bg-alt)); 184 + border-color: color-mix(in oklch, var(--success) 20%, transparent); 185 + } 186 + 187 + .card.danger { 188 + background: color-mix(in oklch, var(--red) 5%, var(--bg-alt)); 189 + border-color: color-mix(in oklch, var(--red) 30%, transparent); 190 + border-width: 2px; 191 + } 192 + 193 + .card.info { 194 + background: color-mix(in oklch, var(--blue) 5%, var(--bg-alt)); 195 + border-color: color-mix(in oklch, var(--blue) 20%, transparent); 196 + } 197 + 198 + .card.thick { border-width: 2px; } 199 + 200 + .card-flex { 201 + display: flex; 202 + gap: 1rem; 203 + align-items: start; 204 + } 205 + 206 + .card-icon { 207 + flex-shrink: 0; 208 + width: 2rem; 209 + height: 2rem; 210 + } 211 + 212 + ul { 213 + list-style: none; 214 + margin: 1rem 0; 215 + } 216 + 217 + li { 218 + display: flex; 219 + align-items: start; 220 + gap: 0.75rem; 221 + margin-bottom: 0.75rem; 222 + color: var(--text-muted); 223 + } 224 + 225 + .bullet { 226 + flex-shrink: 0; 227 + margin-top: 0.25rem; 228 + } 229 + 230 + .bullet.red { color: var(--red); } 231 + .bullet.green { color: var(--success); } 232 + .bullet.yellow { color: var(--yellow); } 233 + .bullet.accent { color: var(--accent); } 234 + 235 + .alert { 236 + background: var(--code-bg); 237 + border-left: 4px solid var(--red); 238 + padding: 1rem; 239 + border-radius: 0.25rem; 240 + margin: 1rem 0; 241 + } 242 + 243 + .alert p { margin: 0; } 244 + 245 + ol { 246 + list-style: none; 247 + counter-reset: item; 248 + margin: 1rem 0; 249 + } 250 + 251 + ol li { 252 + counter-increment: item; 253 + } 254 + 255 + ol li::before { 256 + content: counter(item) "."; 257 + font-weight: 700; 258 + color: var(--accent); 259 + margin-right: 0.75rem; 260 + } 261 + 262 + a { 263 + color: var(--accent); 264 + text-decoration: none; 265 + font-weight: 500; 266 + } 267 + 268 + a:hover { opacity: 0.8; } 269 + 270 + footer { 271 + border-top: 1px solid var(--border-light); 272 + background: var(--bg-alt); 273 + padding: 2rem 1rem; 274 + margin-top: auto; 275 + text-align: center; 276 + font-size: 0.875rem; 277 + color: var(--text-muted); 278 + } 279 + 280 + footer p { margin-bottom: 0.5rem; } 281 + 282 + @media (max-width: 768px) { 283 + h1 { font-size: 2rem; } 284 + h2 { font-size: 1.5rem; } 285 + h3 { font-size: 1.25rem; } 286 + .meta { flex-direction: column; gap: 0.5rem; } 287 + .meta-divider { display: none; } 288 + } 289 + </style> 290 + </head> 291 + <body> 292 + <header> 293 + <div class="header-inner"> 294 + <div class="logo"> 295 + <img src="/transparent-full-size-ico.png" alt="wisp.place"> 296 + <span>wisp.place</span> 297 + </div> 298 + <a href="/editor" class="back-link">← Back to Dashboard</a> 299 + </div> 300 + </header> 301 + 302 + <div class="hero"> 303 + <div class="hero-content"> 304 + <div class="hero-icon"> 305 + 🛡️ 306 + </div> 307 + <h1>Acceptable Use Policy</h1> 308 + <div class="meta"> 309 + <div><strong>Effective:</strong> November 10, 2025</div> 310 + <div class="meta-divider"></div> 311 + <div><strong>Last Updated:</strong> November 10, 2025</div> 312 + </div> 313 + </div> 314 + </div> 315 + 316 + <div class="container"> 317 + <article> 318 + <section> 319 + <h2>Our Philosophy</h2> 320 + <p> 321 + wisp.place exists to give you a corner of the internet that's truly yours—a place to create, experiment, and express yourself freely. We believe in the open web and the fundamental importance of free expression. We're not here to police your thoughts, moderate your aesthetics, or judge your taste. 322 + </p> 323 + <p> 324 + That said, we're also real people running real servers in real jurisdictions (the United States and the Netherlands), and there are legal and practical limits to what we can host. This policy aims to be as permissive as possible while keeping the lights on and staying on the right side of the law. 325 + </p> 326 + </section> 327 + 328 + <div class="card success"> 329 + <div class="card-flex"> 330 + <div class="card-icon">✓</div> 331 + <div> 332 + <h2 style="margin-top: 0;">What You Can Do</h2> 333 + <p> 334 + <strong>Almost anything.</strong> Seriously. Build weird art projects. Write controversial essays. Create spaces that would make corporate platforms nervous. Express unpopular opinions. Make things that are strange, provocative, uncomfortable, or just plain yours. 335 + </p> 336 + <p style="margin-bottom: 0;"> 337 + We support creative and personal expression in all its forms, including adult content, political speech, counter-cultural work, and experimental projects. 338 + </p> 339 + </div> 340 + </div> 341 + </div> 342 + 343 + <section> 344 + <h2>⚠️ What You Can't Do</h2> 345 + 346 + <div class="card thick"> 347 + <h3>Illegal Content</h3> 348 + <p> 349 + Don't host content that's illegal in the United States or the Netherlands. This includes but isn't limited to: 350 + </p> 351 + <ul> 352 + <li> 353 + <span class="bullet red">•</span> 354 + <span><strong>Child sexual abuse material (CSAM)</strong> involving real minors in any form</span> 355 + </li> 356 + <li> 357 + <span class="bullet red">•</span> 358 + <span><strong>Realistic or AI-generated depictions</strong> of minors in sexual contexts, including photorealistic renders, deepfakes, or AI-generated imagery</span> 359 + </li> 360 + <li> 361 + <span class="bullet red">•</span> 362 + <span><strong>Non-consensual intimate imagery</strong> (revenge porn, deepfakes, hidden camera footage, etc.)</span> 363 + </li> 364 + <li> 365 + <span class="bullet red">•</span> 366 + <span>Content depicting or facilitating human trafficking, sexual exploitation, or sexual violence</span> 367 + </li> 368 + <li> 369 + <span class="bullet red">•</span> 370 + <span>Instructions for manufacturing explosives, biological weapons, or other instruments designed for mass harm</span> 371 + </li> 372 + <li> 373 + <span class="bullet red">•</span> 374 + <span>Content that facilitates imminent violence or terrorism</span> 375 + </li> 376 + <li> 377 + <span class="bullet red">•</span> 378 + <span>Stolen financial information, credentials, or personal data used for fraud</span> 379 + </li> 380 + </ul> 381 + </div> 382 + 383 + <div class="card thick"> 384 + <h3>Intellectual Property Violations</h3> 385 + <p> 386 + Don't host content that clearly violates someone else's copyright, trademark, or other intellectual property rights. We're required to respond to valid DMCA takedown notices. 387 + </p> 388 + <p> 389 + We understand that copyright law is complicated and sometimes ridiculous. We're not going to proactively scan your site or nitpick over fair use. But if we receive a legitimate legal complaint, we'll have to act on it. 390 + </p> 391 + </div> 392 + 393 + <div class="card danger"> 394 + <h3>Hate Content</h3> 395 + <p> 396 + You can express controversial ideas. You can be offensive. You can make people uncomfortable. But pure hate—content that exists solely to dehumanize, threaten, or incite violence against people based on race, ethnicity, religion, gender, sexual orientation, disability, or similar characteristics—isn't welcome here. 397 + </p> 398 + <p> 399 + There's a difference between "I have deeply unpopular opinions about X" and "People like X should be eliminated." The former is protected expression. The latter isn't. 400 + </p> 401 + <div class="alert"> 402 + <p> 403 + <strong>A note on enforcement:</strong> While we're generally permissive and believe in giving people the benefit of the doubt, hate content is where we draw a hard line. I will be significantly more aggressive in moderating this type of content than anything else on this list. If your site exists primarily to spread hate or recruit people into hateful ideologies, you will be removed swiftly and without extensive appeals. This is non-negotiable. 404 + </p> 405 + </div> 406 + </div> 407 + 408 + <div class="card thick"> 409 + <h3>Adult Content Guidelines</h3> 410 + <p> 411 + Adult content is allowed. This includes sexually explicit material, erotica, adult artwork, and NSFW creative expression. 412 + </p> 413 + <p><strong>However:</strong></p> 414 + <ul> 415 + <li> 416 + <span class="bullet red">•</span> 417 + <span>No content involving real minors in any sexual context whatsoever</span> 418 + </li> 419 + <li> 420 + <span class="bullet red">•</span> 421 + <span>No photorealistic, AI-generated, or otherwise realistic depictions of minors in sexual contexts</span> 422 + </li> 423 + <li> 424 + <span class="bullet green">•</span> 425 + <span>Clearly stylized drawings and written fiction are permitted, provided they remain obviously non-photographic in nature</span> 426 + </li> 427 + <li> 428 + <span class="bullet red">•</span> 429 + <span>No non-consensual content (revenge porn, voyeurism, etc.)</span> 430 + </li> 431 + <li> 432 + <span class="bullet red">•</span> 433 + <span>No content depicting illegal sexual acts (bestiality, necrophilia, etc.)</span> 434 + </li> 435 + <li> 436 + <span class="bullet yellow">•</span> 437 + <span>Adult content should be clearly marked as such if discoverable through public directories or search</span> 438 + </li> 439 + </ul> 440 + </div> 441 + 442 + <div class="card thick"> 443 + <h3>Malicious Technical Activity</h3> 444 + <p>Don't use your site to:</p> 445 + <ul> 446 + <li> 447 + <span class="bullet red">•</span> 448 + <span>Distribute malware, viruses, or exploits</span> 449 + </li> 450 + <li> 451 + <span class="bullet red">•</span> 452 + <span>Conduct phishing or social engineering attacks</span> 453 + </li> 454 + <li> 455 + <span class="bullet red">•</span> 456 + <span>Launch DDoS attacks or network abuse</span> 457 + </li> 458 + <li> 459 + <span class="bullet red">•</span> 460 + <span>Mine cryptocurrency without explicit user consent</span> 461 + </li> 462 + <li> 463 + <span class="bullet red">•</span> 464 + <span>Scrape, spam, or abuse other services</span> 465 + </li> 466 + </ul> 467 + </div> 468 + </section> 469 + 470 + <section> 471 + <h2>⚖️ Our Approach to Enforcement</h2> 472 + <p> 473 + <strong>We actively monitor for obvious violations.</strong> Not to censor your creativity or police your opinions, but to catch the clear-cut stuff that threatens the service's existence and makes this a worse place for everyone. We're looking for the blatantly illegal, the obviously harmful—the stuff that would get servers seized and communities destroyed. 474 + </p> 475 + <p> 476 + We're not reading your blog posts looking for wrongthink. We're making sure this platform doesn't become a haven for the kind of content that ruins good things. 477 + </p> 478 + 479 + <div class="card"> 480 + <p style="font-weight: 600; margin-bottom: 1rem;">We take action when:</p> 481 + <ol> 482 + <li>We identify content that clearly violates this policy during routine monitoring</li> 483 + <li>We receive a valid legal complaint (DMCA, court order, etc.)</li> 484 + <li>Someone reports content that violates this policy and we can verify the violation</li> 485 + <li>Your site is causing technical problems for the service or other users</li> 486 + </ol> 487 + </div> 488 + 489 + <div class="card"> 490 + <p style="font-weight: 600; margin-bottom: 1rem;">When we do need to take action, we'll try to:</p> 491 + <ul> 492 + <li> 493 + <span class="bullet accent">•</span> 494 + <span>Contact you first when legally and practically possible</span> 495 + </li> 496 + <li> 497 + <span class="bullet accent">•</span> 498 + <span>Be transparent about what's happening and why</span> 499 + </li> 500 + <li> 501 + <span class="bullet accent">•</span> 502 + <span>Give you an opportunity to address the issue if appropriate</span> 503 + </li> 504 + </ul> 505 + </div> 506 + 507 + <p> 508 + For serious or repeated violations, we may suspend or terminate your account. 509 + </p> 510 + </section> 511 + 512 + <div class="card info"> 513 + <h2 style="margin-top: 0;">Regional Compliance</h2> 514 + <p style="margin-bottom: 0;"> 515 + Our servers are located in the United States and the Netherlands. Content hosted on wisp.place must comply with the laws of both jurisdictions. While we aim to provide broad creative freedom, these legal requirements are non-negotiable. 516 + </p> 517 + </div> 518 + 519 + <section> 520 + <h2>Changes to This Policy</h2> 521 + <p> 522 + We may update this policy as legal requirements or service realities change. If we make significant changes, we'll notify active users. 523 + </p> 524 + </section> 525 + 526 + <section> 527 + <h2>Questions or Reports</h2> 528 + <p> 529 + If you have questions about this policy or need to report a violation, contact us at <a href="mailto:contact@wisp.place">contact@wisp.place</a>. 530 + </p> 531 + </section> 532 + 533 + <div class="card thick" style="border-color: var(--accent);"> 534 + <p style="font-size: 1.125rem; line-height: 1.7; margin-bottom: 0;"> 535 + <strong>Remember:</strong> This policy exists to keep the service running and this community healthy, not to limit your creativity. When in doubt, ask yourself: "Is this likely to get real-world authorities knocking on doors or make this place worse for everyone?" If the answer is yes, it probably doesn't belong here. Everything else? Go wild. 536 + </p> 537 + </div> 538 + </article> 539 + </div> 540 + 541 + <footer> 542 + <p> 543 + Built by <a href="https://bsky.app/profile/nekomimi.pet" target="_blank">@nekomimi.pet</a> • 544 + Contact: <a href="mailto:contact@wisp.place">contact@wisp.place</a> • 545 + Legal/DMCA: <a href="mailto:legal@wisp.place">legal@wisp.place</a> 546 + </p> 547 + <p> 548 + <a href="/editor">Back to Dashboard</a> 549 + </p> 550 + </footer> 551 + </body> 552 + </html>
+7 -3
apps/main-app/src/index.ts
··· 225 225 }) 226 226 : (app) => app 227 227 ) 228 - // Redirect old acceptable-use URL to new SPA route 229 - .get('/acceptable-use', ({ set }) => { 230 - set.redirect = '/editor/acceptable-use' 228 + .get('/acceptable-use', async ({ set }) => { 229 + set.headers['Content-Type'] = 'text/html; charset=utf-8' 230 + return await Bun.file('./apps/main-app/public/editor/acceptable-use.html').text() 231 + }) 232 + .get('/editor/acceptable-use', async ({ set }) => { 233 + set.headers['Content-Type'] = 'text/html; charset=utf-8' 234 + return await Bun.file('./apps/main-app/public/editor/acceptable-use.html').text() 231 235 }) 232 236 .get('/onboarding', async ({ set }) => { 233 237 set.headers['Content-Type'] = 'text/html; charset=utf-8'