website/pkg/config/config.go
Noah Petherbridge 4f04323d5a Public Avatar Consent Page
The nonshy website is changing the policy on profile pictures. From August 30,
the square cropped avatar images will need to be publicly viewable to everyone.

This implements the first pass of the rollout:

* Add the Public Avatar Consent Page which explains the change to users and
  asks for their acknowledgement. The link is available from their User Settings
  page, near their Certification Photo link.
* When users (with non-public avatars) accept the change: their square cropped
  avatar will become visible to everybody, instead of showing a placeholder
  avatar.
* Users can change their mind and opt back out, which will again show the
  placeholder avatar.
* The Certification Required middleware will automatically enforce the consent
  page once the scheduled go-live date arrives.

Next steps are:

1. Post an announcement on the forum about the upcoming change and link users
   to the consent form if they want to check it out early.
2. Update the nonshy site to add banners to places like the User Dashboard for
   users who will be affected by the change, to link them to the forum post
   and the consent page.
2024-06-29 16:44:18 -07:00

166 lines
5.1 KiB
Go

// Package config holds some (mostly static) configuration for the app.
package config
import (
"regexp"
"time"
)
// Branding
const (
Title = "nonshy"
Subtitle = "A social network for nudists and exhibitionists."
)
// Paths and layouts
const (
TemplatePath = "./web/templates"
StaticPath = "./web/static"
SettingsPath = "./settings.json"
// Web path where photos are kept. Photos in DB store only their filenames, this
// is the base URL that goes in front. TODO: support setting a CDN URL prefix.
JpegQuality = 90
PhotoWebPath = "/static/photos"
PhotoDiskPath = "./web/static/photos"
)
// Security
const (
BcryptCost = 14
SessionCookieName = "session_id"
CSRFCookieName = "xsrf_token"
CSRFInputName = "_csrf" // html input name
SessionCookieMaxAge = 60 * 60 * 24 * 30
SessionRedisKeyFormat = "session/%s"
MaxBodySize = 1024 * 1024 * 8 // max upload file (e.g., 8 MB gifs)
MultipartMaxMemory = 1024 * 1024 * 1024 * 20 // 20 MB
TwoFactorBackupCodeCount = 12
TwoFactorBackupCodeLength = 8 // characters a-z0-9
)
// Authentication
const (
// Skip the email verification step. The signup page will directly ask for
// email+username+password rather than only email and needing verification.
SkipEmailVerification = false
SignupTokenRedisKey = "signup-token/%s"
ResetPasswordRedisKey = "reset-password/%s"
ChangeEmailRedisKey = "change-email/%s"
SignupTokenExpires = 24 * time.Hour // used for all tokens so far
// Rate limits
RateLimitRedisKey = "rate-limit/%s/%s" // namespace, id
LoginRateLimitWindow = 1 * time.Hour
LoginRateLimit = 10 // 10 failed login attempts = locked for full hour
LoginRateLimitCooldownAt = 3 // 3 failed attempts = start throttling
LoginRateLimitCooldown = 30 * time.Second
// Contact form rate limits for logged-out users to curb spam robots:
// - One message can be submitted every 2 minutes
// - If they post 10 minutes in an hour they are paused for one hour.
ContactRateLimitWindow = 1 * time.Hour
ContactRateLimit = 10
ContactRateLimitCooldownAt = 1
ContactRateLimitCooldown = 2 * time.Minute
// "Mark Explicit" rate limit to curb a mischievous user just bulk marking the
// whole gallery as explicit.
MarkExplicitRateLimitWindow = 1 * time.Hour
MarkExplicitRateLimit = 20 // 10 failed MarkExplicit attempts = locked for full hour
MarkExplicitRateLimitCooldownAt = 10 // 10 photos in an hour, start throttling.
MarkExplicitRateLimitCooldown = time.Minute
// How frequently to refresh LastLoginAt since sessions are long-lived.
LastLoginAtCooldown = time.Hour
// Chat room status refresh interval.
ChatStatusRefreshInterval = 30 * time.Second
)
var (
UsernameRegexp = regexp.MustCompile(`^[a-z0-9_.-]{3,32}$`)
ReservedUsernames = []string{
"admin",
"admins",
"administrator",
"moderator",
"support",
"staff",
"nonshy",
"here",
"all",
"everyone",
"everybody",
}
)
// Photo Galleries
const (
MaxPhotoWidth = 1280
ProfilePhotoWidth = 512
AltTextMaxLength = 5000
// Quotas for uploaded photos.
PhotoQuotaUncertified = 6
PhotoQuotaCertified = 100
// Min number of public photos for inner circle members to see the prompt to invite.
InnerCircleMinimumPublicPhotos = 5
// Rate limit for too many Site Gallery pictures.
// Some users sign up and immediately max out their gallery and spam
// the Site Gallery page. These limits can ensure only a few Site Gallery
// pictures can be posted per day.
SiteGalleryRateLimitMax = 5
SiteGalleryRateLimitInterval = 24 * time.Hour
)
// Profile photo "public square cropped version" migration controls.
// Previously: a Private or Friends-only profile picture would show a placeholder avatar to users
// who couldn't see the full size version. In migration, these square cropped images will move to
// be always public (the full-size versions can remain private).
// NOTE: search code base for PublicAvatar or "public avatar" for related feature code.
var (
PublicAvatarEnforcementDate = time.Date(2024, time.August, 30, 12, 0, 0, 0, time.UTC)
)
// Forum settings
const (
// Only ++ the Views count per user per thread within a small
// window of time - if a user keeps reloading the same thread
// rapidly it does not increment the view counter more.
ThreadViewDebounceRedisKey = "debounce-view/user=%d/thr=%d"
ThreadViewDebounceCooldown = 1 * time.Hour
)
// Poll settings
var (
// Max number of responses to accept for a poll (how many form
// values the app will read in). NOTE: also enforced in frontend
// UX in new_post.html, update there if you change this.
PollMaxAnswers = 100
// Poll color CSS classes (Bulma). Plugged in to templates like:
// <progress class="$CLASS">
// Values will wrap around for long polls.
PollProgressBarClasses = []string{
"progress is-success",
"progress is-link",
"progress is-warning",
"progress is-danger",
"progress is-primary",
"progress is-info",
}
)
// Variables set by main.go to make them readily available.
var (
RuntimeVersion string
RuntimeBuild string
RuntimeBuildDate string
Debug bool // app is in debug mode
)