feat(rsocials): add Listmonk newsletter page + legacy domain redirect
- Add /newsletter-list route embedding Listmonk via iframe - Add LISTMONK_URL env var to docker-compose - Add Traefik redirect: social.jeffemmett.com → demo.rspace.online/rsocials - Add backlog task for linked wallets security hardening (TASK-HIGH.5) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
bc810d34e4
commit
0e9d00d2ac
|
|
@ -0,0 +1,42 @@
|
|||
---
|
||||
id: TASK-HIGH.5
|
||||
title: Link External Wallets to EncryptID + Security Hardening
|
||||
status: Done
|
||||
assignee: []
|
||||
created_date: '2026-03-10 01:07'
|
||||
updated_date: '2026-03-10 01:08'
|
||||
labels: []
|
||||
dependencies: []
|
||||
parent_task_id: TASK-HIGH
|
||||
---
|
||||
|
||||
## Description
|
||||
|
||||
<!-- SECTION:DESCRIPTION:BEGIN -->
|
||||
Implemented EIP-6963 wallet discovery, SIWE ownership verification, server-side AES-256-GCM encrypted storage, and Safe owner addition flow. Full security audit addressed 16 findings across Critical, High, Medium, Low, and Informational categories.
|
||||
<!-- SECTION:DESCRIPTION:END -->
|
||||
|
||||
## Acceptance Criteria
|
||||
<!-- AC:BEGIN -->
|
||||
- [x] #1 EIP-6963 provider discovery for browser wallets
|
||||
- [x] #2 SIWE (Sign-In with Ethereum) ownership verification
|
||||
- [x] #3 Server-side AES-256-GCM encryption at rest for linked wallet data
|
||||
- [x] #4 Safe add-owner-proposal with threshold validation
|
||||
- [x] #5 Security: real encryption replaces Base64 (C-1)
|
||||
- [x] #6 Security: XSS-safe token name escaping (H-1)
|
||||
- [x] #7 Security: salted address hashes (H-2)
|
||||
- [x] #8 Security: rate limiting on nonce endpoint (H-3)
|
||||
- [x] #9 Security: sender verified against JWT (H-4)
|
||||
- [x] #10 Security: icon URI sanitization (M-1)
|
||||
- [x] #11 Security: threshold bounds checking (M-2)
|
||||
- [x] #12 Security: SSRF prevention via address validation (M-3)
|
||||
- [x] #13 Security: no cleartext sessionStorage cache (M-4)
|
||||
- [x] #14 Security: low-severity hardening (L-1 through L-7)
|
||||
- [x] #15 Security: headers and EIP-712 fixes (I-1, I-9)
|
||||
<!-- AC:END -->
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
<!-- SECTION:NOTES:BEGIN -->
|
||||
Implemented across 5 commits (c789481, d861c0a, 45f5cea, 92fde65, bc810d3). New files: eip6963.ts, external-signer.ts, linked-wallets.ts. Modified: server.ts, db.ts, session.ts, schema.sql, mod.ts, folk-wallet-viewer.ts. Full security audit: 16 findings (1C, 4H, 4M, 7L, 9I) — all actionable items resolved.
|
||||
<!-- SECTION:NOTES:END -->
|
||||
|
|
@ -48,6 +48,7 @@ services:
|
|||
- INFISICAL_AI_CLIENT_SECRET=${INFISICAL_AI_CLIENT_SECRET}
|
||||
- INFISICAL_AI_PROJECT_SLUG=claude-ops
|
||||
- INFISICAL_AI_SECRET_PATH=/ai
|
||||
- LISTMONK_URL=https://newsletter.cosmolocal.world
|
||||
depends_on:
|
||||
rspace-db:
|
||||
condition: service_healthy
|
||||
|
|
@ -151,6 +152,15 @@ services:
|
|||
- "traefik.http.routers.rspace-rsocials.entrypoints=web"
|
||||
- "traefik.http.routers.rspace-rsocials.priority=120"
|
||||
- "traefik.http.routers.rspace-rsocials.service=rspace-online"
|
||||
# ── Legacy redirect: social.jeffemmett.com → demo.rspace.online/rsocials ──
|
||||
- "traefik.http.routers.rspace-social-redirect.rule=Host(`social.jeffemmett.com`)"
|
||||
- "traefik.http.routers.rspace-social-redirect.entrypoints=web"
|
||||
- "traefik.http.routers.rspace-social-redirect.priority=130"
|
||||
- "traefik.http.middlewares.social-redirect.redirectregex.regex=^https?://social\\.jeffemmett\\.com(.*)"
|
||||
- "traefik.http.middlewares.social-redirect.redirectregex.replacement=https://demo.rspace.online/rsocials$${1}"
|
||||
- "traefik.http.middlewares.social-redirect.redirectregex.permanent=true"
|
||||
- "traefik.http.routers.rspace-social-redirect.middlewares=social-redirect"
|
||||
- "traefik.http.routers.rspace-social-redirect.service=rspace-online"
|
||||
# Service configuration
|
||||
- "traefik.http.services.rspace-online.loadbalancer.server.port=3000"
|
||||
- "traefik.docker.network=traefik-public"
|
||||
|
|
|
|||
|
|
@ -576,6 +576,10 @@ function renderDemoFeedHTML(): string {
|
|||
// The /scheduler route renders a full-page iframe shell.
|
||||
const POSTIZ_URL = process.env.POSTIZ_URL || "https://demo.rsocials.online";
|
||||
|
||||
// ── Listmonk newsletter — embedded via iframe ──
|
||||
// Listmonk admin at newsletter.cosmolocal.world (not behind CF Access).
|
||||
const LISTMONK_URL = process.env.LISTMONK_URL || "https://newsletter.cosmolocal.world";
|
||||
|
||||
routes.get("/scheduler", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
const dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
|
|
@ -590,6 +594,19 @@ routes.get("/scheduler", (c) => {
|
|||
}));
|
||||
});
|
||||
|
||||
routes.get("/newsletter-list", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
return c.html(renderExternalAppShell({
|
||||
title: `Newsletter List — rSocials | rSpace`,
|
||||
moduleId: "rsocials",
|
||||
spaceSlug: space,
|
||||
modules: getModuleInfoList(),
|
||||
theme: "dark",
|
||||
appName: "Listmonk",
|
||||
appUrl: LISTMONK_URL,
|
||||
}));
|
||||
});
|
||||
|
||||
routes.get("/feed", (c) => {
|
||||
const space = c.req.param("space") || "demo";
|
||||
const dataSpace = (c.get("effectiveSpace" as any) as string) || space;
|
||||
|
|
@ -670,6 +687,13 @@ routes.get("/", (c) => {
|
|||
<p>Compose and preview tweet threads with live card preview</p>
|
||||
</div>
|
||||
</a>
|
||||
<a href="${base}/newsletter-list">
|
||||
<span class="nav-icon">📧</span>
|
||||
<div class="nav-body">
|
||||
<h3>Newsletter List</h3>
|
||||
<p>Manage newsletter subscribers and send campaigns via Listmonk</p>
|
||||
</div>
|
||||
</a>
|
||||
</nav>
|
||||
</div>`,
|
||||
}));
|
||||
|
|
@ -740,5 +764,17 @@ export const socialsModule: RSpaceModule = {
|
|||
{ icon: "🖼️", title: "Share Images", text: "Auto-generate a branded share image of your thread for cross-posting." },
|
||||
],
|
||||
},
|
||||
{
|
||||
path: "newsletter-list",
|
||||
title: "Newsletter List",
|
||||
icon: "📧",
|
||||
tagline: "rSocials Tool",
|
||||
description: "Manage newsletter subscribers and send email campaigns via the embedded Listmonk interface.",
|
||||
features: [
|
||||
{ icon: "👥", title: "Subscriber Management", text: "View, import, and manage newsletter subscribers across multiple mailing lists." },
|
||||
{ icon: "📨", title: "Email Campaigns", text: "Compose and send email campaigns with templates and scheduling." },
|
||||
{ icon: "📊", title: "Analytics", text: "Track open rates, click-throughs, and subscriber engagement." },
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue