⏺ Here's a breakdown of each directive:
┌─────────────────┬────────────────────────────────────────────────┬─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ Directive │ Value │ Purpose │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ default-src │ 'self' │ Fallback for any resource type not explicitly listed — only allow from the app's own origin │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ script-src │ 'self' │ JavaScript can only be loaded from the app's origin (no external scripts, no inline) │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ style-src │ 'self' 'unsafe-inline' https://rsms.me │ Stylesheets from the app's origin, inline styles (needed by LiveView), and the https://rsms.me/inter/ hosted on rsms.me │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ font-src │ 'self' https://rsms.me │ Font files from the app's origin and rsms.me (Inter font) │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ img-src │ 'self' data: https://lastfm.freetls.fastly.net │ Images from the app's origin, data: URIs (inline base64 images), and Last.fm's CDN for album/artist artwork │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ connect-src │ 'self' │ XHR/fetch/WebSocket connections only to the app's origin (covers LiveView's WebSocket) │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ frame-ancestors │ 'self' │ The app can only be embedded in iframes by itself (clickjacking protection) │
├─────────────────┼────────────────────────────────────────────────┼─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ base-uri │ 'self' │ Restricts <base> tag to the app's origin (prevents base tag injection attacks) │
└─────────────────┴────────────────────────────────────────────────┴─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Notable things not allowed by this policy:
- No inline <script> tags or eval()
- No external JavaScript from CDNs
- No embedding in third-party iframes
- No connections to external APIs from the browser (all external API calls go through the server)
- spec public functions (skipping controllers, views, live views and
components)
- use types instead of explanations in docs
- remove redundant docs
- fix typos