mirror of
https://github.com/projectsend/projectsend.git
synced 2026-09-18 09:35:07 +00:00
85b1650ef0
The dashboard's System card now says so when no scanner is configured at all, not only when a configured one is failing: "Anything uploaded here — by staff, by clients, or through an upload link — is passed on unchecked", with a link to set it up. Said only where somebody can act on it. Connecting a scanner is a new capability, scanning.connect, community only — on a hosted installation the scanner is infrastructure the platform runs, so its address is not a tenant's to set and its absence is not a tenant's to fix. The two policies stay on both editions, because what to do with a file nobody could scan is a decision about somebody's own files. An edition difference through the registry, never an edition check. Also: PROJECTSEND_SCANNER_DEFAULT_ADDRESS, seeded into the settings on first boot by the command that already does this for two-factor enforcement. It is the opposite of PROJECTSEND_SCANNER_ADDRESS — a starting value rather than a policy, so a Docker install that brings up the optional scanner container arrives configured while the address and the switch stay on the settings screen. Both are seeded together or neither: an address with scanning off would look configured and check nothing. Nothing changes for an existing installation on upgrade: scanning stays off, existing files are marked "never scanned", and the scanner container is still opt-in.
266 lines
12 KiB
PHP
266 lines
12 KiB
PHP
<?php
|
|
|
|
use App\Modules\Platform\Capabilities\Edition;
|
|
use App\Support\EnvFlag;
|
|
|
|
return [
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Edition
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Which edition this installation runs as. Edition is configuration, not a
|
|
| code branch: every behavioural difference between editions must flow
|
|
| through the capability registry, never through ad-hoc edition checks.
|
|
|
|
|
| Supported: "community", "cloud"
|
|
|
|
|
*/
|
|
|
|
'edition' => Edition::from((string) env('PROJECTSEND_EDITION', 'community')),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Uploads
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Where a chunked upload's parts wait while the transfer is running,
|
|
| before they are assembled onto the storage disk. Leave this unset:
|
|
| it exists so the test suite can give each parallel worker its own
|
|
| directory, since parts are real files on a real path rather than a
|
|
| faked disk, and session ids restart at 1 in every worker's database.
|
|
|
|
|
*/
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Platform seats
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| How many staff accounts and how many clients this installation may
|
|
| hold. Unset means unlimited, which is every self-hosted install: this
|
|
| exists for a managed one, where the operator sold a number and the
|
|
| application is the only process that can actually count against it.
|
|
|
|
|
| An operator stating the installation's own limit is not the same as
|
|
| the application inventing a plan tier — the distinction config/api.php
|
|
| draws when it declines to key a rate limit off billing. Nothing here
|
|
| knows what a plan is; it accepts a number and refuses to exceed it.
|
|
|
|
|
*/
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Capabilities this installation has been told it may not use
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Comma-separated capability keys, subtracted from what the edition
|
|
| grants. Only ever subtracted: nothing here can switch a capability on,
|
|
| because a variable that could would put the hosted edition's screens
|
|
| one line of .env away on every self-hosted install.
|
|
|
|
|
| For a managed installation whose plan does not include something its
|
|
| edition otherwise has -- branding.customize on a free plan is the case
|
|
| this was built for. Unknown keys are ignored rather than fatal: the
|
|
| variable outlives both the plan that wrote it and the release that
|
|
| named the key, and an instance refusing to boot over a stale one would
|
|
| be an outage on upgrade day.
|
|
|
|
|
*/
|
|
|
|
'capabilities_disabled' => env('PROJECTSEND_CAPABILITIES_DISABLED'),
|
|
|
|
'platform' => [
|
|
'max_staff_users' => env('PROJECTSEND_PLATFORM_MAX_STAFF_USERS'),
|
|
'max_clients' => env('PROJECTSEND_PLATFORM_MAX_CLIENTS'),
|
|
|
|
// Seeded into Setting::TwoFactorEnforcement on first boot and never
|
|
// afterwards — see SeedSettingsCommand. Here rather than read from
|
|
// env() at the point of use, because config:cache stops .env being
|
|
// read at all and that is how TRUSTED_PROXIES came to silently do
|
|
// nothing.
|
|
'two_factor_enforcement' => env('PROJECTSEND_TWO_FACTOR_ENFORCEMENT'),
|
|
|
|
// A floor under what a client with no quota of their own gets, in
|
|
// megabytes. Not a setting, for the same reason the seat caps above
|
|
// are not: it is the shape of what the platform sold rather than a
|
|
// preference the installation's administrator is expressing, and an
|
|
// administrator who has chosen a number keeps it — see
|
|
// ClientStorageUsage::defaultQuotaMb().
|
|
//
|
|
// It exists because the setting's own default is 0, and 0 means
|
|
// unlimited. On an installation a platform runs for other people
|
|
// that is one account away from unmetered hosting, and the account
|
|
// does not have to be one the platform created.
|
|
'default_client_quota_mb' => env('PROJECTSEND_PLATFORM_DEFAULT_CLIENT_QUOTA_MB'),
|
|
],
|
|
|
|
'uploads' => [
|
|
'parts_path' => env('UPLOAD_PARTS_PATH'),
|
|
|
|
// How many resumable uploads one account may have in flight.
|
|
//
|
|
// A session holds room on the temporary volume from the moment it
|
|
// is created until it completes, is cancelled, or is swept — and
|
|
// for an account with no storage quota to spend, this number is
|
|
// the only thing bounding how much room that is. The browser
|
|
// uploads a few files at once, so this is far above anything a
|
|
// person does by hand.
|
|
'max_open_sessions' => 25,
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| How downloads leave the server
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Uploads live outside the web root, so PHP authorizes every download
|
|
| before any byte moves. What differs is what happens next: PHP can
|
|
| stream the file itself, or hand the web server a header naming the
|
|
| file and let it do the work. The header is faster and each server
|
|
| spells it differently — a server that does not recognise the one it
|
|
| is sent serves the empty body instead, which is a 0-byte download.
|
|
|
|
|
| 'auto' (the default) uses nginx's X-Accel-Redirect when the server
|
|
| says it is nginx, and PHP streaming otherwise. 'nginx', 'xsendfile'
|
|
| (Apache with mod_xsendfile, or LiteSpeed) and 'php' state it
|
|
| outright. Read here rather than through env() elsewhere, so that
|
|
| `php artisan config:cache` does not silently blank it.
|
|
|
|
|
*/
|
|
|
|
'file_delivery' => env('PROJECTSEND_FILE_DELIVERY', 'auto'),
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Chunked upload part size (MB)
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Each resumable-upload part travels as one request of this size;
|
|
| web-server/PHP body limits only need to cover a single part.
|
|
|
|
|
*/
|
|
|
|
'upload_part_size_mb' => 20,
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| CAPTCHA
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Two things live here rather than in the settings store, for two
|
|
| different reasons.
|
|
|
|
|
| "disabled" is an escape hatch: a wrong secret key cannot lock anybody
|
|
| out (see CaptchaResult), but an operator who has managed it some other
|
|
| way needs a fix that touches no database and needs no working login.
|
|
|
|
|
| The managed keys are the platform's own, applied to every tenant on
|
|
| cloud and absent everywhere else. In config rather than the tenant
|
|
| database so a database dump never carries our credential, and so
|
|
| rotating it is one fleet-wide change instead of a migration. They do
|
|
| nothing without Capability::CaptchaManagedKeys.
|
|
|
|
|
*/
|
|
|
|
'captcha' => [
|
|
// Read strictly rather than cast: `env()` returns anything it does
|
|
// not recognise as the string it was, and every non-empty string
|
|
// is truthy — so `(bool)` would read `PROJECTSEND_CAPTCHA_DISABLED=no`
|
|
// as "yes, disabled" and quietly take the bot protection off the
|
|
// login and registration forms. See App\Support\EnvFlag.
|
|
'disabled' => EnvFlag::isTrue(env('PROJECTSEND_CAPTCHA_DISABLED', false)),
|
|
|
|
'managed' => [
|
|
'provider' => env('PROJECTSEND_CAPTCHA_MANAGED_PROVIDER'),
|
|
'site_key' => env('PROJECTSEND_CAPTCHA_MANAGED_SITE_KEY'),
|
|
'secret_key' => env('PROJECTSEND_CAPTCHA_MANAGED_SECRET_KEY'),
|
|
'score_threshold' => (float) env('PROJECTSEND_CAPTCHA_MANAGED_SCORE_THRESHOLD', 0.5),
|
|
],
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Virus scanning
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Naming an address here makes scanning *managed*: that scanner is used,
|
|
| scanning cannot be switched off from the settings screen, and the
|
|
| connection fields are hidden. It is how a hosted fleet points every
|
|
| site at one scanning service, and a self-hosted operator who would
|
|
| rather configure this in the environment than in the database can use
|
|
| it too. Everything else — what to do with files that cannot be scanned,
|
|
| and what to do while the scanner is down — stays a setting either way,
|
|
| because those are the site's decisions rather than the platform's.
|
|
|
|
|
| Format: unix:///var/run/clamav/clamd.sock, or tcp://host:3310.
|
|
|
|
|
*/
|
|
|
|
'scanning' => [
|
|
'address' => env('PROJECTSEND_SCANNER_ADDRESS'),
|
|
|
|
// The other way to point an installation at a scanner, and the
|
|
// opposite of the one above: written into the settings table on
|
|
// first boot and then owned by whoever administers the
|
|
// installation, who can change it or switch scanning off like any
|
|
// other setting. It is what a self-hosted operator who brings up
|
|
// the optional scanner container wants — the site arrives
|
|
// configured, without the platform taking the switch away. Ignored
|
|
// on any boot where the setting already has a value.
|
|
'default_address' => env('PROJECTSEND_SCANNER_DEFAULT_ADDRESS'),
|
|
|
|
// How long to wait for the socket, and then for each reply. A scan
|
|
// streams the whole file before the reply comes, so the second one
|
|
// has to allow for the largest file this installation accepts.
|
|
'connect_timeout' => (int) env('PROJECTSEND_SCANNER_CONNECT_TIMEOUT', 5),
|
|
'reply_timeout' => (int) env('PROJECTSEND_SCANNER_REPLY_TIMEOUT', 600),
|
|
],
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Release identity
|
|
|--------------------------------------------------------------------------
|
|
|
|
|
| Per-release facts that ship with the code. Not settings: they never
|
|
| vary per install or tenant.
|
|
|
|
|
*/
|
|
|
|
// How long a request waits for another one that is already rendering
|
|
// the same thumbnail or preview, before giving up rather than
|
|
// decoding the same image a second time. See ThumbnailGenerator.
|
|
// A slow disk or a large source wants longer than the default 15.
|
|
'rendition_lock_wait_seconds' => env('PROJECTSEND_RENDITION_LOCK_WAIT_SECONDS'),
|
|
|
|
'version' => '2.4.1',
|
|
|
|
/*
|
|
|--------------------------------------------------------------------------
|
|
| Official links
|
|
|--------------------------------------------------------------------------
|
|
*/
|
|
|
|
// Read through App\Modules\Platform\OfficialLinks rather than
|
|
// directly: which of the two front doors "website" means, and whether
|
|
// the donation link is offered at all, both depend on the edition.
|
|
'links' => [
|
|
'website' => 'https://www.projectsend.org/',
|
|
// The hosted service's own front door. A managed installation
|
|
// links here instead — including from the "Powered by" line on
|
|
// client-facing pages and outgoing email.
|
|
'website_cloud' => 'https://www.projectsend.cloud/',
|
|
// Where this code lives, and the same repository
|
|
// CheckForUpdatesCommand asks for the latest release. v1 remains
|
|
// available at github.com/projectsend/legacy.
|
|
'source' => 'https://github.com/projectsend/projectsend',
|
|
'open_collective' => 'https://opencollective.com/projectsend',
|
|
// Kept identical to the invitation update.sh prints when an update
|
|
// finishes — the two are the same offer, made in the terminal and
|
|
// then again on the screen the administrator lands on.
|
|
'discord' => 'https://discord.gg/VT9n6cyvXT',
|
|
],
|
|
|
|
];
|