* fix: Resolve _FILE env secrets lazily to avoid clobbering third-party variables
The Docker-style secrets support added in #11906 eagerly copied every
*_FILE environment variable into its base variable at boot. This broke
AWS SDK credential refresh on EKS Pod Identity: the rotating token in
AWS_CONTAINER_AUTHORIZATION_TOKEN_FILE was frozen into the static
AWS_CONTAINER_AUTHORIZATION_TOKEN variable, which the SDK prefers and
never re-reads, so S3 access failed once the boot-time token expired.
It similarly resolved the standard OpenSSL SSL_CERT_FILE CA bundle into
Outline's SSL_CERT setting, failing validation at startup.
File secrets are now resolved lazily through a proxy when a variable is
read off the environment export, which limits resolution to variables
declared on the Environment classes, and SSL_CERT_FILE is explicitly
reserved for OpenSSL.
Fixes#12885
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqP3Gb29iG5bJmhYuEAAjF
* refactor: Generalize reserved file variable documentation
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqP3Gb29iG5bJmhYuEAAjF
* refactor: Clear SSL_CERT_FILE in test environment instead of reserving it
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqP3Gb29iG5bJmhYuEAAjF
* docs: Trim withFileSecrets JSDoc
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MqP3Gb29iG5bJmhYuEAAjF
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: support presigned PUT uploads for S3-compatible storage
Add `AWS_S3_UPLOAD_METHOD` config ("post" default / "put") so providers
that do not implement presigned POST (e.g. Cloudflare R2) can use
presigned PUT instead.
- BaseStorage.getPresignedPut() returns undefined by default; S3Storage
overrides with PutObjectCommand + getSignedUrl.
- Content-Length is signed into the presigned PUT URL so S3 rejects
uploads that do not match the declared size.
- API route and MCP tool branch on the config: only one upload method
is returned per request.
- Frontend uses existing presignedPutUrl presence check — unchanged.
- When put is configured but unsupported (e.g. LocalStorage), a clear
InvalidRequestError is returned.
Defaults to "post" — zero behavior change for existing deployments.
* refactor: return explicit upload mode instead of inferring from fields
Address review feedback from @tommoor: the client should not need to
infer the upload method from the presence of presigned-PUT-specific
fields. The API now returns an explicit `mode` ("put" | "post"), and the
PUT branch uses generic `url` / `headers` fields so the client has no
special knowledge of "presigned puts".
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* refactor: use this.getBucket() in presigned post/put methods
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* feat(s3): add optional CloudFront support for signed attachment URLs
Serve attachment downloads through CloudFront when configured, while keeping
uploads on the direct S3 endpoint. Signed URLs require a key pair; missing or
invalid signing config falls back to S3 presigned URLs instead of unsigned CDN
links. CloudFront secrets are kept server-side only.
Co-authored-by: Cursor <cursoragent@cursor.com>
* Update .env.sample
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* Update server/env.ts
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* fix(s3): address CloudFront PR review feedback"
---------
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* feat: Add support for Docker Swarm style secrets
* fix: Handle empty-string env values and bare _FILE key in resolveFileSecrets
Use undefined check instead of truthiness so empty-string values are
treated as "already set" and not overridden by _FILE variants. Skip
processing when the key is exactly "_FILE" to avoid creating an
empty-key entry.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* feat: Add support for configurable proxy IP header in environment settings
* Update server/env.ts
Remove mention of Koa from docs
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* Update .env.sample
Remove mention of Koa from env sample.
Co-authored-by: Tom Moor <tom.moor@gmail.com>
---------
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* OAuth
* store logo
* unfurl support
* refresh token
* support for list
* embed list
* mention menu for all embeds in a list
* multi-level list
* logo
* account level connection
* tsc
* Update Icon.tsx
* coderabbit feedback
* RFC 6749 suggestion
---------
Co-authored-by: Tom Moor <tom@getoutline.com>
* Add SMTP_SERVICE environment variable for well-known services
* Fix PR #8777: Restore code in teams.ts and users.ts
* The rest of the work
* fix validation
---------
Co-authored-by: codegen-sh[bot] <131295404+codegen-sh[bot]@users.noreply.github.com>
Co-authored-by: Tom Moor <tom.moor@gmail.com>
* Add Discord Provider Prototype
* Add Discord Logo
* Add Plugin to Plugin Manager
* fixed discord auth support and added icon
* add csv role verification
* grab discord server icon and test server id and roles
* subdomain derived from server name
* use discord server specific nickname if available
* Cleanup and comment
* move discord api types to dev deps
* cleanup of server vs default params
* remove commented out lines
* revert envv.development
* revert in vscode
* update yarn lock
* add gif support for discord server icon
* add comment with docs link
* add env section for discord
* fix errors and clarify env
* add new cannot use without
* fix suggestions
* Separate environment configs
* wip
* wip
* test
* plugins
* test
* test
* .sequelizerc, unfortunately can't go through /utils/environment due to not supporting TS
* docker-compose -> docker compose
* fix: .local wipes .development
* Add custom validation message for invalid SECRET_KEY (often confused)
* feat: Put request rate limit at application server
This PR contains implementation for a blanket rate limiter at
application server level. Currently the allowed throughput is set high
only to be changed later as per the actual data gathered.
* Simplify implementation
1. Remove shutdown handler to purge rate limiter keys
2. Have separate keys for default and custom(route-based) rate limiters
3. Do not kill default rate limiter because it is not needed anymore due
to (2) above
* Set 60s as default for rate limiting window
* Fix env types
Fixes#3412
Previously the only way to restrict the domains for a Team were with the ALLOWED_DOMAINS environment variable for self hosted instances.
This PR migrates this to be a database backed setting on the Team object. This is done through the creation of a TeamDomain model that is associated with the Team and contains the domain name
This settings is updated on the Security Tab. Here domains can be added or removed from the Team.
On the server side, we take the code paths that previously were using ALLOWED_DOMAINS and switched them to use the Team allowed domains instead