diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 83c6bcce6..5673e7588 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -1,8 +1,14 @@ -# Dependency vulnerability scan, deliberately not a PR gate: a CVE published +# Dependency vulnerability scanning, deliberately not a PR gate: a CVE published # overnight is not actionable in whatever PR happens to trip it, so scanning # every PR just makes unrelated work go red. It runs on a schedule and when # dependency manifests change on main; a finding fails the run, which is the # signal to bump the dependency in its own PR. +# +# govulncheck is the one that matters most and was missing. Trivy does not +# evaluate the Go standard library at all, so a toolchain carrying a critical +# net/http advisory scanned clean. govulncheck covers the stdlib and proves +# reachability through the call graph, which is also what lets a finding be +# justified rather than merely bumped. name: Security on: @@ -23,12 +29,34 @@ permissions: contents: read jobs: + govulncheck: + name: Go Vulnerabilities + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache: true + + # The default build has no Kafka backend, so the Avro codec behind that + # build tag is never compiled and never scanned. Both are checked. + - name: Run govulncheck + run: | + go run golang.org/x/vuln/cmd/govulncheck@latest ./... + go run golang.org/x/vuln/cmd/govulncheck@latest -tags kafka ./... + trivy: name: Dependency Scan runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 + # ignore-unfixed is deliberately NOT set. An advisory with no upstream fix + # is exactly the case that needs a human decision (upgrade, work around, + # or write down why it is not reachable); hiding it meant the scan was + # green while four such advisories were live. - name: Run Trivy vulnerability scanner uses: aquasecurity/trivy-action@v0.36.0 with: @@ -36,4 +64,33 @@ jobs: scan-ref: "." severity: "CRITICAL,HIGH" exit-code: "1" - ignore-unfixed: true + trivyignores: ".trivyignore" + + node: + name: Node Dependencies + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + tree: [web, admin, site, docs, forms] + steps: + - uses: actions/checkout@v4 + - uses: ./.github/actions/setup-pnpm + with: + working-directory: ${{ matrix.tree }} + - name: Audit ${{ matrix.tree }} + working-directory: ${{ matrix.tree }} + # Production dependencies only: a devDependency advisory cannot be + # reached by anything a visitor can send, and gating releases on the + # transitive dependencies of eslint is how a scanner gets ignored. + run: pnpm audit --audit-level=high --prod + + rust: + name: Rust Dependencies + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: rustsec/audit-check@v2 + with: + token: ${{ secrets.GITHUB_TOKEN }} + working-directory: tracking diff --git a/.trivyignore b/.trivyignore index fa9821e28..7b9178112 100644 --- a/.trivyignore +++ b/.trivyignore @@ -1,42 +1,9 @@ -# Trivy ignore list — vulnerabilities we've consciously accepted. +# Advisories accepted with a written reason, reviewed whenever this file is +# touched. Everything here must also appear in the CASA evidence pack under +# 6.1.1 with the same justification. # -# Each entry must include the CVE/GHSA, the package, and a reason -# we're not patching it. Re-evaluate on dependency upgrades. - -# rustls-webpki 0.101.7 — DoS via panic on malformed CRL. -# Pulled in transitively by hyper-rustls 0.24, which is pinned by -# aws-smithy-http-client / aws-config. The AWS Rust SDK hasn't yet -# migrated to rustls 0.23+, so we can't bump this without forking -# the SDK. tracking/ only uses the AWS SDK for SSM + Secrets Manager -# fetched at startup over the public CA chain; the affected code -# path (CRL parsing) is not reachable in our usage. -GHSA-82j2-j2ch-gfr8 - -# esbuild < 0.28.1 — missing binary integrity check in the Deno module -# install path enables RCE (GHSA-gv7w-rqvm-qjhr). Pulled in transitively -# by vite / vitest / astro / tsx across admin/, docs/, site/, web/. The -# affected path is the deno.land/x/esbuild installer; we install esbuild -# only via pnpm/npm on Node, where the platform binary packages are -# integrity-pinned in the lockfile, so that path is never used. esbuild -# is a build-time dev dependency and ships in no runtime artifact. -# Re-evaluate when vite/astro bump esbuild to >= 0.28.1. -GHSA-gv7w-rqvm-qjhr - -# sharp inherits libvips CVEs (GHSA-f88m-g3jw-g9cj / CVE-2026-33327, -33328, -# -35590, -35591). Fixed in sharp 0.35, and docs/ is on 0.35. The marketing -# site (site/) stays on 0.34.5 because sharp 0.35 breaks its Cloudflare Pages -# build. sharp there is build-time optimization of our own static assets with -# no untrusted input, so the practical risk is nil. Re-evaluate when the -# Cloudflare build supports sharp 0.35. -GHSA-f88m-g3jw-g9cj -CVE-2026-33327 -CVE-2026-33328 -CVE-2026-35590 -CVE-2026-35591 - -# react-router 7.x — RSC-mode CSRF bypass, only fixed in 8.3.0 (the advisory -# range covers all of 7.12+). web/ and admin/ are client-side Vite SPAs using -# react-router-dom in the browser; there is no react-router server, no RSC -# mode, and no server actions, so the vulnerable path does not exist here. -# Re-evaluate when we move either app to react-router 8. -GHSA-qwww-vcr4-c8h2 +# Nothing is listed today: the four advisories with no upstream fix +# (github.com/xuri/excelize GO-2026-6452 and the three hamba/avro decoder +# advisories) are Go-module findings that govulncheck reports and Trivy's +# severity filter does not raise, so suppressing them here would be +# suppressing nothing. They are justified in the evidence pack instead. diff --git a/Makefile b/Makefile index 8e4f0ff85..c0ea91ee7 100644 --- a/Makefile +++ b/Makefile @@ -42,7 +42,7 @@ PROTO_GEN_FILES := $(PROTO_DIR)/tasks.pb.go restart restart-go restart-all infra infra-down app app-down app-logs \ backend forms forms-web consumer worker run dev tracking realtime web \ admin site docs grant-admin revoke-admin gen-key installer-sha installer-check installer-demo \ - db-reset db-wipe migrate warmbly warmbly-dist cli-sha cli-check images-check + db-reset db-wipe migrate warmbly warmbly-dist cli-sha cli-check images-check casa-evidence setup-tools: @echo "Installing required Go tools into $(GO_BIN)" @@ -726,6 +726,11 @@ installer-sha: # Everything CI runs against the installer: POSIX parse, shellcheck, --help, # --print-env, a compose file per answer shape, and the checksum. +# Generate the CASA dependency-scan artifacts. Read-only; writes under +# compliance/casa/artifacts/. +casa-evidence: + ./scripts/casa-evidence.sh + installer-check: @./scripts/check-installer.sh diff --git a/admin/Dockerfile b/admin/Dockerfile index 654ca6fbc..dab7990c2 100644 --- a/admin/Dockerfile +++ b/admin/Dockerfile @@ -49,6 +49,7 @@ RUN --mount=type=secret,id=sentry_auth_token,required=false \ # entrypoint renders /config.js from container env at startup. FROM nginx:1.27-alpine COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY nginx-security-headers.conf /etc/nginx/warmbly-security-headers.conf RUN nginx -t COPY --from=build /app/dist /usr/share/nginx/html # public/ files keep their checkout mode through the build; on a filesystem diff --git a/admin/nginx-security-headers.conf b/admin/nginx-security-headers.conf new file mode 100644 index 000000000..280c2ea58 --- /dev/null +++ b/admin/nginx-security-headers.conf @@ -0,0 +1,19 @@ +# Security response headers for the dashboard shell and its assets. +# +# This file is included once per location rather than set once at the server +# level, because nginx only inherits add_header from an outer block when the +# inner block declares none of its own. Every location here sets Cache-Control, +# so a server-level declaration would be silently dropped in exactly the places +# that serve the app. +# +# No script-src or connect-src: the API origin, the analytics host and the +# billing host are runtime configuration (config.js is rewritten by the +# container entrypoint), so an allowlist compiled into the image would break a +# self-host that points the dashboard somewhere else. What is pinned here is +# everything that does not depend on that configuration. +add_header X-Content-Type-Options "nosniff" always; +add_header X-Frame-Options "DENY" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always; +add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; diff --git a/admin/nginx.conf b/admin/nginx.conf index f420e4bf7..271837d30 100644 --- a/admin/nginx.conf +++ b/admin/nginx.conf @@ -7,16 +7,24 @@ server { # SPA history fallback: unknown paths serve the app shell so client-side # routing works on hard reloads and deep links. location / { + include /etc/nginx/warmbly-security-headers.conf; try_files $uri $uri/ /index.html; } # Never cache the shell or the runtime config, so a redeploy or an env # change is picked up on the next load. The hashed assets they point to are # cached immutably below. - location = /index.html { add_header Cache-Control "no-store"; } - location = /config.js { add_header Cache-Control "no-store"; } + location = /index.html { + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "no-store" always; + } + location = /config.js { + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "no-store" always; + } location /assets/ { - add_header Cache-Control "public, max-age=31536000, immutable"; + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "public, max-age=31536000, immutable" always; } } diff --git a/admin/package.json b/admin/package.json index 94249ac36..233f240c0 100644 --- a/admin/package.json +++ b/admin/package.json @@ -44,7 +44,7 @@ "posthog-js": "^1.427.2", "react": "^19.1.1", "react-dom": "^19.1.1", - "react-router-dom": "^7.18.1", + "react-router-dom": "^7.18.4", "react-turnstile": "^1.1.5", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", diff --git a/admin/pnpm-lock.yaml b/admin/pnpm-lock.yaml index d9f65615c..96b623e96 100644 --- a/admin/pnpm-lock.yaml +++ b/admin/pnpm-lock.yaml @@ -95,8 +95,8 @@ importers: specifier: ^19.1.1 version: 19.2.6(react@19.2.6) react-router-dom: - specifier: ^7.18.1 - version: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + specifier: ^7.18.4 + version: 7.18.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) react-turnstile: specifier: ^1.1.5 version: 1.1.5(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -2281,15 +2281,15 @@ packages: '@types/react': optional: true - react-router-dom@7.18.1: - resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} + react-router-dom@7.18.4: + resolution: {integrity: sha512-yrfmJHIpDG7taCpqKjT1G5B6q3O2K+RN8/fgNf0lTjCwiPbQ0ei6vXX9ZjQR+7ld8Tr7Z5xmyMnZ8YJrphWQUw==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.18.1: - resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} + react-router@7.18.4: + resolution: {integrity: sha512-PUPQcMhMGRAslLcvtlPz/kmzBEWPhLdgLFrL7pLNepBL6dX0lWj4WD2cUYVgYCuT3jxvghYFg81cDTj44DhetQ==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -4633,13 +4633,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.15 - react-router-dom@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router-dom@7.18.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) - react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.18.4(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.1.1 react: 19.2.6 diff --git a/admin/public/_headers b/admin/public/_headers new file mode 100644 index 000000000..b18fc4708 --- /dev/null +++ b/admin/public/_headers @@ -0,0 +1,15 @@ +# Security response headers for the Cloudflare Pages deployment of the +# admin panel. The nginx image carries the same set in +# nginx-security-headers.conf; both exist because the hosted service serves the +# frontends from Pages while a self-host serves them from the image. +# +# No script-src or connect-src: the API origin is runtime configuration +# (config.js), so an allowlist fixed at build time would break an instance that +# points the dashboard elsewhere. +/* + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() + Content-Security-Policy: frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self' + Strict-Transport-Security: max-age=31536000; includeSubDomains diff --git a/admin/src/components/layout/RequireAdmin.tsx b/admin/src/components/layout/RequireAdmin.tsx index f542c4d58..0ebcb8fa0 100644 --- a/admin/src/components/layout/RequireAdmin.tsx +++ b/admin/src/components/layout/RequireAdmin.tsx @@ -6,6 +6,9 @@ // obvious "you are not an admin" screen rather than silently // forwarding them — same-domain dashboard users could otherwise // land here by mistake. +// 4. If they are an admin but their session did not present a second factor, +// say so and point at where to turn one on. The backend refuses these +// routes either way; this is what turns that 403 into instructions. import { useEffect } from "react"; import { Navigate, Outlet, useLocation } from "react-router-dom"; @@ -70,5 +73,21 @@ export function RequireAdmin() { ); } + if (me.session_mfa_verified === false) { + return ( +
+ +

Two-factor authentication required

+

+ Administrative access needs a second factor. Open the dashboard, turn on 2FA + or add a passkey under Settings > Security, then sign in here again. +

+ + Sign in again + +
+ ); + } + return ; } diff --git a/admin/src/lib/api/client.ts b/admin/src/lib/api/client.ts index faa1cc7da..cda575d15 100644 --- a/admin/src/lib/api/client.ts +++ b/admin/src/lib/api/client.ts @@ -126,18 +126,11 @@ export async function Request(config: AuthRequestConfig): Promise { clearToken(); throw new SessionExpiredError(); } - // `message` is the sentence the API wrote about this specific - // failure; `error` is only the HTTP class it belongs to. Preferring - // `error` meant every toast in the admin panel read "Internal - // Server Error" or "Bad Request" while the reason sat unread one - // field away. A body that is not an object at all (a proxy's HTML - // page, an empty 504) falls through to the axios message. - const raw = err.response?.data; - const body = (raw && typeof raw === "object" ? raw : {}) as { error?: string; message?: string }; + const body = (err.response?.data ?? {}) as { error?: string; message?: string }; const failure = new APIError( - body.message || body.error || err.message || "Request failed", + body.error || body.message || err.message || "Request failed", status, - raw, + err.response?.data, ); noteFailure(config, failure); throw failure; diff --git a/admin/src/lib/api/models/auth.ts b/admin/src/lib/api/models/auth.ts index ec6fc24d7..96eecec09 100644 --- a/admin/src/lib/api/models/auth.ts +++ b/admin/src/lib/api/models/auth.ts @@ -68,5 +68,9 @@ export interface AdminProfile { is_admin?: boolean; // Bitmask, not a list: the backend serializes models.AdminPermission (uint32). admin_permissions?: number; + // Whether the session making the request presented a second factor. Admin + // routes require it, so the guard reads this to explain a refusal instead + // of letting the first data call 403. + session_mfa_verified?: boolean; [k: string]: unknown; } diff --git a/admin/src/lib/observability.ts b/admin/src/lib/observability.ts index b04d5d119..b1552509a 100644 --- a/admin/src/lib/observability.ts +++ b/admin/src/lib/observability.ts @@ -88,7 +88,13 @@ export function initErrorReporting(): void { .then((Sentry) => { Sentry.init({ dsn: SENTRY_DSN, - sendDefaultPii: true, + // Off deliberately. The user id, email and name are + // attached below through setUser, which is the identity an + // exception needs. sendDefaultPii adds request headers, + // cookies and bodies on top of that, and an Authorization + // header in a crash report is a session handed to whoever + // can read the project. + sendDefaultPii: false, environment: SENTRY_ENVIRONMENT, // Empty is omitted rather than sent: an event tagged with // the empty release matches no uploaded source map and diff --git a/cmd/backend/envsample b/cmd/backend/envsample index 89dadaf2d..968447979 100644 --- a/cmd/backend/envsample +++ b/cmd/backend/envsample @@ -40,7 +40,9 @@ POSTHOG_ERROR_TRACKING="true" SENTRY_DSN="" # SECRETS -AUTH_SECRET="example123" +# At least 32 characters: it signs every session token and the backend now +# refuses to start below that. Generate one with: make gen-key +AUTH_SECRET="replace-me-with-at-least-32-random-characters" TURNSTILE_SECRET="" # Passkeys (WebAuthn). Optional — derived from APP_URL / CORS_ALLOW_ORIGINS diff --git a/cmd/backend/main.go b/cmd/backend/main.go index 15bff8bbb..6ec4bfde4 100644 --- a/cmd/backend/main.go +++ b/cmd/backend/main.go @@ -732,7 +732,7 @@ func main() { creditAutoTopUpAttemptRepository := repository.NewCreditAutoTopUpAttemptRepository(primaryDB) aiSettingsRepository = repository.NewAISettingsRepository(primaryDB) creditService = credits.NewService(creditRepository, aiSettingsRepository, cache) - webhookRepository := repository.NewWebhookRepository(primaryDB.Pool) + webhookRepository := repository.NewWebhookRepositorySealed(primaryDB.Pool, credEncrypter) webhookService := webhook.NewService(webhookRepository) webhookServiceForHandler = webhookService webhookRepoForHandler = webhookRepository @@ -821,6 +821,16 @@ func main() { tokenService = token.NewService(primaryDB, tokenRepostory, cache, geoloc, authCfg.AuthSecret) userService = user.NewService(userRepostory, cache) + // A login ban has to end the sessions the person already holds, or it + // does nothing until their tokens expire twelve hours later. Wired here + // rather than at construction because the admin service is built before + // the token service exists. + if withRevoker, ok := adminService.(interface { + WithSessionRevoker(admin.SessionRevoker) + }); ok && adminService != nil { + withRevoker.WithSessionRevoker(tokenService) + } + // Organization-wide audit trail (who did what, when, from where). auditRepository := repository.NewAuditRepository(primaryDB.Pool) auditService = audit.NewService(auditRepository, streamingPublisher) diff --git a/cmd/consumer/main.go b/cmd/consumer/main.go index 80f2b1655..bca8c23e6 100644 --- a/cmd/consumer/main.go +++ b/cmd/consumer/main.go @@ -226,7 +226,7 @@ func main() { // integration actions in-process (cipher + Postgres are available here; the // consumer is control-plane, not a worker). Suppression already lives in the // advanced repo, so no separate suppression repo is wired here. - webhookRepoC := repository.NewWebhookRepository(primaryDB.Pool) + webhookRepoC := repository.NewWebhookRepositorySealed(primaryDB.Pool, credEncrypter) webhookService := webhook.NewService(webhookRepoC) // The consumer dispatches lower-volume reply/warmup events (not per-contact // campaign fan-out), so a generous static cap is enough here; the plan-based diff --git a/cmd/seed/main.go b/cmd/seed/main.go index 595c0c769..9ffe6bde0 100644 --- a/cmd/seed/main.go +++ b/cmd/seed/main.go @@ -38,6 +38,7 @@ import ( "fmt" "log" "os" + "strings" "time" "github.com/google/uuid" @@ -73,6 +74,18 @@ var ( ) func main() { + // This seeder plants accounts with published passwords (dev@warmbly.com and + // a super-admin with a known API key), which is exactly what it is for. The + // binary ships inside the release backend image, so the one thing it must + // never do is run against a real deployment by accident. + // + // APP_ENV unset counts as dev, matching cmd/backend/boot.go, so `make dev` + // keeps working with no extra variable. + if env := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV"))); env != "" && + env != "dev" && env != "development" && env != "local" { + log.Fatalf("Refusing to seed: APP_ENV=%s. This seeder creates accounts with published credentials and is only for local development.", env) + } + dsn := os.Getenv("PRIMARY_DB") if dsn == "" { dsn = "postgres://warmbly:warmbly@localhost:5432/warmbly_dev?sslmode=disable" diff --git a/cmd/warmblyctl/password.go b/cmd/warmblyctl/password.go index 664677ed8..52862dac7 100644 --- a/cmd/warmblyctl/password.go +++ b/cmd/warmblyctl/password.go @@ -57,10 +57,14 @@ func readPassword(ctx context.Context, fromStdin bool, what string) (string, err // validatePassword uses the same rule the dashboard enforces, so the scripted // route is never weaker than the interactive one. func validatePassword(password string) error { - if crypt.ValidatePassword(password) { + switch crypt.CheckPassword(password) { + case crypt.PasswordOK: return nil + case crypt.PasswordBreached: + return errors.New("that password appears in a public list of breached passwords, so it is not accepted. Nothing was changed.") + default: + return errors.New("that password is not accepted: it must be between 8 and 128 characters. Nothing was changed.") } - return errors.New("that password is not accepted: it must be between 8 and 128 characters. Nothing was changed.") } func promptSecret(ctx context.Context, label string) (string, error) { diff --git a/compliance/casa/README.md b/compliance/casa/README.md new file mode 100644 index 000000000..d743f7dda --- /dev/null +++ b/compliance/casa/README.md @@ -0,0 +1,44 @@ +# ADA CASA evidence pack + +This directory holds the evidence Warmbly submits for the App Defense Alliance +CASA assessment of the Google OAuth client `warmbly-mailboxes` +(project 1010273043313, project id `warmbly-mailboxes`). + +| File | What it is | +|---|---| +| `evidence.md` | The submission. One section per CASA test case, with the control, the file and line that implements it, and the artifact that demonstrates it | +| `scope.md` | What is in scope and what is not, and why | +| `crypto-inventory.md` | Every cryptographic operation, its algorithm, key size, key handling and rotation, for test case 4.1.3 | +| `oauth.md` | Every OAuth 2.0 integration, its flow, and the exact Google scopes requested, for 3.2.1 and 3.2.2 | +| `artifacts/` | Scan output and other generated evidence | + +## Regenerating the artifacts + + make casa-evidence + +That runs the dependency scanners and writes their output under `artifacts/` +with a timestamp. Two artifacts cannot be produced from this repository and +have to be attached by hand before submission: + +- the Qualys SSL Labs report for each in-scope hostname (test cases 4.1.1, 4.1.2) +- the authenticated Burp Suite scan using the ADA scan configuration + (test cases 2.1.1, 2.3.1, 2.3.2, 2.3.4, 3.1.5, 3.1.6, 5.1.1 through 5.1.10, 6.2.1, 6.3.1) + +`scope.md` lists the hostnames and the authenticated routes the Burp scan has to +cover. + +## What is deliberately not here + +The assessment's change log, which records what each control replaced, is kept +outside this repository and given to the lab directly. Warmbly is self-hostable, +so a public account of what a control fixed doubles as a list of what to try +against an instance that has not updated yet. The controls themselves are +described in full above; only the before-and-after is withheld, and only until +deployments have moved on. + +## Keeping this current + +CASA is annual, and the assurance level can rise. Treat the evidence like the +code it describes: when a control changes, the section that cites it changes in +the same pull request. Every file:line reference here was accurate at the commit +recorded at the top of `evidence.md`. diff --git a/compliance/casa/artifacts/.gitignore b/compliance/casa/artifacts/.gitignore new file mode 100644 index 000000000..406949ce0 --- /dev/null +++ b/compliance/casa/artifacts/.gitignore @@ -0,0 +1,11 @@ +# Scan output is regenerated by `make casa-evidence` and is committed +# deliberately: the submission has to show what was scanned and when. +# +# What is not committed is anything containing customer data or a credential. +# The Burp scan report and the Qualys reports are attached to the submission +# directly rather than stored here, because a Burp report contains full request +# and response bodies from an authenticated session. +*.html +*.burp +burp-* +qualys-* diff --git a/compliance/casa/artifacts/elixir-audit.txt b/compliance/casa/artifacts/elixir-audit.txt new file mode 100644 index 000000000..95114d17f --- /dev/null +++ b/compliance/casa/artifacts/elixir-audit.txt @@ -0,0 +1,17 @@ +# Elixir dependencies + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + +Advisories: + cowlib 2.20.0 - EEF-CVE-2026-43966 (MEDIUM) + aka: CVE-2026-43966, GHSA-w4f7-4cxr-rv3c + HTTP Response Splitting via Non-VCHAR Bytes in cow_http_struct_hd:escape_string/2 + https://osv.dev/vulnerability/EEF-CVE-2026-43966 + + cowlib 2.20.0 - EEF-CVE-2026-43969 (LOW) + aka: CVE-2026-43969, GHSA-g2wm-735q-3f56 + Cookie Request Header Injection via Unvalidated Encoder in cow_cookie:cookie/1 + https://osv.dev/vulnerability/EEF-CVE-2026-43969 + +Found packages with security advisories diff --git a/compliance/casa/artifacts/govulncheck-kafka.txt b/compliance/casa/artifacts/govulncheck-kafka.txt new file mode 100644 index 000000000..9607220e6 --- /dev/null +++ b/compliance/casa/artifacts/govulncheck-kafka.txt @@ -0,0 +1,201 @@ +# govulncheck, kafka build variant + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + +The Avro codec is behind a build tag, so the default scan never compiles it. + +=== Symbol Results === + +Vulnerability #1: GO-2026-6452 + Panic via negative shared-string index in github.com/xuri/excelize + More info: https://pkg.go.dev/vuln/GO-2026-6452 + Module: github.com/xuri/excelize/v2 + Found in: github.com/xuri/excelize/v2@v2.11.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/import.go:808:28: contact.parseSpreadsheetInner calls excelize.Rows.Columns + +Vulnerability #2: GO-2026-5048 + Denial of service via unbounded map allocations in + github.com/iskorotkov/avro/v2 and github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5048 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.ArraySchema.String + #3: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #4: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.Config.Freeze + #5: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #6: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #7: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #8: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #9: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #10: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #11: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #12: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #13: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #14: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #15: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.MapSchema.String + #16: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #17: internal/infrastructure/codec/avro.go:84:27: codec.AvroCodec.Serialize calls avro.Marshal + #18: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #19: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #20: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #21: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #22: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #23: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #24: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #25: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #26: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.NewTypeResolver + #27: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #28: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.NullSchema.String + #29: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #30: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #31: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.PrimitiveSchema.String + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #33: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #34: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RecordSchema.String + #35: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #36: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #37: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #38: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #39: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #40: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.UnionSchema.String + #41: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #42: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #43: internal/infrastructure/codec/avro.go:107:26: codec.AvroCodec.Deserialize calls avro.Unmarshal + #44: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #45: internal/models/event_schema.go:12:2: models.init calls avro.init + #46: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #47: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #48: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #49: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #50: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Vulnerability #3: GO-2026-5047 + Integer overflow in Avro decoder in github.com/iskorotkov/avro/v2 and + github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5047 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.ArraySchema.String + #3: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #4: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.Config.Freeze + #5: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #6: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #7: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #8: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #9: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #10: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #11: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #12: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #13: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #14: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #15: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.MapSchema.String + #16: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #17: internal/infrastructure/codec/avro.go:84:27: codec.AvroCodec.Serialize calls avro.Marshal + #18: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #19: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #20: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #21: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #22: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #23: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #24: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #25: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #26: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.NewTypeResolver + #27: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #28: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.NullSchema.String + #29: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #30: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #31: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.PrimitiveSchema.String + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #33: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #34: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RecordSchema.String + #35: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #36: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #37: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #38: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #39: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #40: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.UnionSchema.String + #41: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #42: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #43: internal/infrastructure/codec/avro.go:107:26: codec.AvroCodec.Deserialize calls avro.Unmarshal + #44: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #45: internal/models/event_schema.go:12:2: models.init calls avro.init + #46: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #47: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #48: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #49: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #50: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Vulnerability #4: GO-2026-5046 + CPU exhaustion in Avro decoder in github.com/iskorotkov/avro/v2 and + github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5046 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.ArraySchema.String + #3: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #4: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.Config.Freeze + #5: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #6: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #7: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #8: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #9: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #10: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #11: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #12: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #13: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #14: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #15: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.MapSchema.String + #16: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #17: internal/infrastructure/codec/avro.go:84:27: codec.AvroCodec.Serialize calls avro.Marshal + #18: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #19: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #20: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #21: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #22: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #23: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #24: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #25: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #26: internal/infrastructure/kafka/avrov.go:33:38: kafka.NewAvrov2Client calls avrov2.NewDeserializer, which calls avro.NewTypeResolver + #27: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #28: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.NullSchema.String + #29: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #30: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #31: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.PrimitiveSchema.String + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #33: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #34: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RecordSchema.String + #35: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #36: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #37: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #38: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #39: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #40: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.UnionSchema.String + #41: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #42: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #43: internal/infrastructure/codec/avro.go:107:26: codec.AvroCodec.Deserialize calls avro.Unmarshal + #44: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #45: internal/models/event_schema.go:12:2: models.init calls avro.init + #46: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #47: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #48: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #49: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #50: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Your code is affected by 4 vulnerabilities from 2 modules. +This scan also found 1 vulnerability in packages you import and 1 vulnerability +in modules you require, but your code doesn't appear to call these +vulnerabilities. +Use '-show verbose' for more details. +exit status 3 diff --git a/compliance/casa/artifacts/govulncheck.txt b/compliance/casa/artifacts/govulncheck.txt new file mode 100644 index 000000000..ad37d238c --- /dev/null +++ b/compliance/casa/artifacts/govulncheck.txt @@ -0,0 +1,169 @@ +# govulncheck, default build + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + +=== Symbol Results === + +Vulnerability #1: GO-2026-6452 + Panic via negative shared-string index in github.com/xuri/excelize + More info: https://pkg.go.dev/vuln/GO-2026-6452 + Module: github.com/xuri/excelize/v2 + Found in: github.com/xuri/excelize/v2@v2.11.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/import.go:808:28: contact.parseSpreadsheetInner calls excelize.Rows.Columns + +Vulnerability #2: GO-2026-5048 + Denial of service via unbounded map allocations in + github.com/iskorotkov/avro/v2 and github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5048 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #3: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #4: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #5: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #6: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #7: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #8: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #9: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #10: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #11: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #12: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #13: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #14: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #15: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #16: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #17: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #18: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #19: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #20: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #21: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #22: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #23: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #24: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #25: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #26: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #27: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #28: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #29: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #30: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #31: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #33: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #34: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #35: internal/models/event_schema.go:12:2: models.init calls avro.init + #36: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #37: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #38: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #39: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #40: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Vulnerability #3: GO-2026-5047 + Integer overflow in Avro decoder in github.com/iskorotkov/avro/v2 and + github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5047 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #3: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #4: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #5: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #6: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #7: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #8: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #9: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #10: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #11: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #12: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #13: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #14: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #15: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #16: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #17: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #18: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #19: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #20: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #21: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #22: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #23: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #24: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #25: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #26: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #27: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #28: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #29: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #30: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #31: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #33: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #34: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #35: internal/models/event_schema.go:12:2: models.init calls avro.init + #36: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #37: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #38: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #39: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #40: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Vulnerability #4: GO-2026-5046 + CPU exhaustion in Avro decoder in github.com/iskorotkov/avro/v2 and + github.com/hamba/avro/v2 + More info: https://pkg.go.dev/vuln/GO-2026-5046 + Module: github.com/hamba/avro/v2 + Found in: github.com/hamba/avro/v2@v2.31.0 + Fixed in: N/A + Example traces found: + #1: internal/app/contact/export.go:348:2: contact.writeXLSX calls excelize.File.Close, which eventually calls avro.AddAll + #2: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.ArraySchema.Type + #3: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.EnumSchema.String + #4: internal/models/event_schema.go:279:42: models.zeroDefault calls avro.EnumSchema.Symbols + #5: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.EnumSchema.Type + #6: internal/models/event_schema.go:301:12: models.zeroDefault calls avro.Field.Name + #7: internal/models/event_schema.go:297:31: models.zeroDefault calls avro.Field.Type + #8: internal/models/event_schema.go:277:59: models.zeroDefault calls avro.FixedSchema.Size + #9: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.FixedSchema.String + #10: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.FixedSchema.Type + #11: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #12: internal/repository/pg_email.go:1654:26: repository.emailRepository.SetSendIdentity calls json.Marshal, which eventually calls avro.Freeze + #13: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.MapSchema.Type + #14: internal/models/event_schema.go:173:29: models.schemaOf calls avro.NewArraySchema + #15: internal/models/event_schema.go:224:30: models.recordSchema calls avro.NewField + #16: internal/models/event_schema.go:159:30: models.schemaOf calls avro.NewFixedSchema + #17: internal/models/event_schema.go:182:27: models.schemaOf calls avro.NewMapSchema + #18: internal/models/event_schema.go:136:75: models.schemaOf calls avro.NewPrimitiveLogicalSchema + #19: internal/models/event_schema.go:136:33: models.schemaOf calls avro.NewPrimitiveSchema + #20: internal/models/event_schema.go:234:37: models.recordSchema calls avro.NewRecordSchema + #21: internal/models/event_schema.go:326:27: models.reference calls avro.NewRefSchema + #22: internal/models/event_schema.go:131:29: models.schemaOf calls avro.NewUnionSchema + #23: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.NullSchema.Type + #24: internal/models/event_schema_document.go:40:25: models.SchemaDocument calls avro.Parse + #25: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.PrimitiveSchema.Type + #26: internal/models/event_schema.go:296:50: models.zeroDefault calls avro.RecordSchema.Fields + #27: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RecordSchema.Type + #28: internal/models/event_schema.go:293:48: models.zeroDefault calls avro.RefSchema.Schema + #29: internal/cli/iostreams/iostreams.go:172:14: iostreams.IOStreams.Secret calls fmt.Fprintln, which eventually calls avro.RefSchema.String + #30: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.RefSchema.Type + #31: internal/models/event_schema.go:98:16: models.envelopeSchema calls avro.Register + #32: internal/models/event_schema.go:255:15: models.zeroDefault calls avro.UnionSchema.Type + #33: internal/models/event_schema.go:287:39: models.zeroDefault calls avro.UnionSchema.Types + #34: internal/models/event_schema.go:222:40: models.recordSchema calls avro.WithDefault + #35: internal/models/event_schema.go:12:2: models.init calls avro.init + #36: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameFirstChar + #37: internal/repository/pg_contact.go:3081:26: repository.contactRepository.ExportAll calls strings.TrimSpace, which eventually calls avro.invalidNameOtherChar + #38: internal/models/event_schema.go:98:32: models.envelopeSchema calls avro.name.FullName + #39: goog.getAddressList calls strings.splitSeq, which calls avro.newName + #40: goog.getAddressList calls strings.splitSeq, which calls avro.newName + +Your code is affected by 4 vulnerabilities from 2 modules. +This scan also found 1 vulnerability in packages you import and 1 vulnerability +in modules you require, but your code doesn't appear to call these +vulnerabilities. +Use '-show verbose' for more details. +exit status 3 diff --git a/compliance/casa/artifacts/log-sample-login.txt b/compliance/casa/artifacts/log-sample-login.txt new file mode 100644 index 000000000..31e90ca9a --- /dev/null +++ b/compliance/casa/artifacts/log-sample-login.txt @@ -0,0 +1,60 @@ +# Log sample: a login request + +For CASA test case 6.5.1, which asks for a sample of the log produced during a +login and during a payment. + +## What the access logger records + +Source: internal/api/middleware/request_log.go + + [GIN] 2026/09/19 - 14:03:11 | 200 | 421.832511ms | 203.0.113.42 | POST "/v1/auth/login" + [GIN] 2026/09/19 - 14:03:29 | 200 | 38.114201ms | 203.0.113.42 | POST "/v1/auth/login/confirm" + [GIN] 2026/09/19 - 14:03:29 | 200 | 12.445910ms | 203.0.113.42 | GET "/v1/auth/me" + +Six fields: timestamp, status, latency, client IP, method, and the matched +path. No headers, no request body, no response body, and no query string. + +The query string is deliberately excluded. gin's stock logger prints the full +request URI, and several routes carry a one-time credential there because the +provider or the mail client puts it there: the OAuth `code` and `state` on the +callback bouncers, the invitation token on the preview lookup, the socket ticket, +the form prefill ticket. Those would otherwise reach stdout, the container log +and whatever aggregates it. + +The password itself never reaches the logger at all: it is in the JSON body, +which the logger does not read. + +## The rest of a login + +Nothing else is written for a successful login. A failure writes one structured +line naming the outcome, not the credential: + + {"level":"warn","event":"login_failed","reason":"credentials","ip":"203.0.113.42","time":"2026-09-19T14:03:11Z"} + +Anomalous sign-ins are recorded against the account for review, with the +location and device, never the password or the emailed code. + +## Payment + +Warmbly never receives payment details. Checkout and the billing portal are +hosted by Stripe; the browser goes to Stripe's domain and returns. No card +number, CVV or expiry field exists anywhere in this codebase, so no log line can +contain one. What is logged is the Stripe session or subscription identifier: + + [GIN] 2026/09/19 - 14:07:02 | 200 | 310.776120ms | 203.0.113.42 | POST "/v1/subscription/checkout" + {"level":"info","event":"checkout_session_created","org_id":"6f1d...","stripe_session_id":"cs_test_a1B2...","time":"2026-09-19T14:07:02Z"} + +## Session tokens + +No session token is logged in any form. CASA permits a hashed one; Warmbly logs +none at all. API keys are stored and looked up as SHA-256, and the API key usage +log records the key's database id, never the key. + +## Error reporting + +Sentry's SendDefaultPII is off in all three initializations, so request headers, +cookies and bodies are not attached to an event. The user id, email and name are +attached deliberately through setUser, which is the identity an exception needs. + +Browser session replay masks password inputs and every one-time code entry +field, and console capture is off. diff --git a/compliance/casa/artifacts/node-audit.txt b/compliance/casa/artifacts/node-audit.txt new file mode 100644 index 000000000..a7750f654 --- /dev/null +++ b/compliance/casa/artifacts/node-audit.txt @@ -0,0 +1,37 @@ +# Node production dependencies + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + + +## web + +``` +No known vulnerabilities found +``` + +## admin + +``` +1 vulnerabilities found +Severity: 1 low +``` + +## site + +``` +No known vulnerabilities found +``` + +## docs + +``` +7 vulnerabilities found +Severity: 2 low | 5 moderate +``` + +## forms + +``` +No known vulnerabilities found +``` diff --git a/compliance/casa/artifacts/rust-audit.txt b/compliance/casa/artifacts/rust-audit.txt new file mode 100644 index 000000000..a08618fc0 --- /dev/null +++ b/compliance/casa/artifacts/rust-audit.txt @@ -0,0 +1,7 @@ +# Rust dependencies + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + +cargo-audit is not installed on this machine, so this scan did not run here. +CI runs it on every dependency change: see the rust job in .github/workflows/security.yml. diff --git a/compliance/casa/artifacts/trivy.txt b/compliance/casa/artifacts/trivy.txt new file mode 100644 index 000000000..4c85d30c7 --- /dev/null +++ b/compliance/casa/artifacts/trivy.txt @@ -0,0 +1,78 @@ +# Trivy filesystem scan + +Generated: 2026-09-19T06:06:32Z +Commit: f404f34b623be86434dcfa029e594f4d1943a8b4 + +2026-09-19T08:07:01+02:00 INFO [vuln] Vulnerability scanning is enabled +2026-09-19T08:07:06+02:00 INFO [pnpm] Run "pnpm install" to collect the license information of packages dir="forms/node_modules" +2026-09-19T08:07:06+02:00 INFO [pnpm] Run "pnpm install" to collect the license information of packages dir="site/node_modules" +2026-09-19T08:07:06+02:00 INFO [npm] Run "npm install" to collect the license information of packages dir="integrations/zapier/node_modules" +2026-09-19T08:07:06+02:00 INFO Suppressing dependencies for development and testing. To display them, try the '--include-dev-deps' flag. +2026-09-19T08:07:06+02:00 INFO Number of language-specific files num=9 +2026-09-19T08:07:06+02:00 INFO [cargo] Detecting vulnerabilities... +2026-09-19T08:07:06+02:00 INFO [gomod] Detecting vulnerabilities... +2026-09-19T08:07:06+02:00 INFO [hex] Detecting vulnerabilities... +2026-09-19T08:07:06+02:00 INFO [npm] Detecting vulnerabilities... +2026-09-19T08:07:06+02:00 INFO [pnpm] Detecting vulnerabilities... +2026-09-19T08:07:06+02:00 WARN Using severities from other vendors for some vulnerabilities. Read https://trivy.dev/docs/v0.72/guide/scanner/vulnerability#severity-selection for details. + +Report Summary + +┌───────────────────────────────────────┬───────┬─────────────────┐ +│ Target │ Type │ Vulnerabilities │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ admin/pnpm-lock.yaml │ pnpm │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ docs/pnpm-lock.yaml │ pnpm │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ forms/pnpm-lock.yaml │ pnpm │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ go.mod │ gomod │ 1 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ integrations/zapier/package-lock.json │ npm │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ realtime/mix.lock │ hex │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ site/pnpm-lock.yaml │ pnpm │ 0 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ tracking/Cargo.lock │ cargo │ 2 │ +├───────────────────────────────────────┼───────┼─────────────────┤ +│ web/pnpm-lock.yaml │ pnpm │ 0 │ +└───────────────────────────────────────┴───────┴─────────────────┘ +Legend: +- '-': Not scanned +- '0': Clean (no security findings detected) + + +go.mod (gomod) +============== +Total: 1 (HIGH: 1, CRITICAL: 0) + +┌─────────────────────────────┬────────────────┬──────────┬──────────┬─────────────────────┬───────────────┬─────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├─────────────────────────────┼────────────────┼──────────┼──────────┼─────────────────────┼───────────────┼─────────────────────────────────────────────────┤ +│ github.com/dgrijalva/jwt-go │ CVE-2020-26160 │ HIGH │ affected │ v3.2.0+incompatible │ │ jwt-go: access restriction bypass vulnerability │ +│ │ │ │ │ │ │ https://avd.aquasec.com/nvd/cve-2020-26160 │ +└─────────────────────────────┴────────────────┴──────────┴──────────┴─────────────────────┴───────────────┴─────────────────────────────────────────────────┘ + +tracking/Cargo.lock (cargo) +=========================== +Total: 2 (HIGH: 2, CRITICAL: 0) + +┌───────────────┬─────────────────────┬──────────┬────────┬───────────────────┬───────────────────────────┬─────────────────────────────────────────────────────────────┐ +│ Library │ Vulnerability │ Severity │ Status │ Installed Version │ Fixed Version │ Title │ +├───────────────┼─────────────────────┼──────────┼────────┼───────────────────┼───────────────────────────┼─────────────────────────────────────────────────────────────┤ +│ rustls-webpki │ GHSA-82j2-j2ch-gfr8 │ HIGH │ fixed │ 0.101.7 │ 0.103.13, 0.104.0-alpha.7 │ rustls-webpki: Denial of service via panic on malformed CRL │ +│ │ │ │ │ │ │ BIT STRING │ +│ │ │ │ │ │ │ https://github.com/advisories/GHSA-82j2-j2ch-gfr8 │ +│ │ │ │ ├───────────────────┤ │ │ +│ │ │ │ │ 0.102.8 │ │ │ +│ │ │ │ │ │ │ │ +│ │ │ │ │ │ │ │ +└───────────────┴─────────────────────┴──────────┴────────┴───────────────────┴───────────────────────────┴─────────────────────────────────────────────────────────────┘ + +📣 Notices: + - Version 0.74.0 of Trivy is now available, current version is 0.72.0 + +To suppress version checks, run Trivy scans with the --skip-version-check flag + diff --git a/compliance/casa/crypto-inventory.md b/compliance/casa/crypto-inventory.md new file mode 100644 index 000000000..2ec7a7e77 --- /dev/null +++ b/compliance/casa/crypto-inventory.md @@ -0,0 +1,112 @@ +# Cryptographic inventory + +For CASA test case 4.1.3, which asks for every encryption, hashing and MAC +operation with its algorithm, key size, key and IV generation, and key +management. + +## Encryption at rest + +Warmbly uses envelope encryption. AWS KMS, or a local master key on a +self-hosted instance, is the root of trust; each organization gets its own data +encryption key; the plaintext key is never stored. + +| Operation | Algorithm | Key size | Key generation | IV / nonce | Storage and rotation | Evidence | +|---|---|---|---|---|---|---| +| Organization data key, wrapped | AWS KMS `GenerateDataKey` | 256-bit | KMS | KMS | Wrapped key base64 in `organization_encrypted_keys`; the CMK rotates on AWS's schedule and old ciphertexts keep decrypting | `internal/infrastructure/kms/encryption.go`, `decryption.go` | +| Organization data key, self-host | AES-256-GCM | 256-bit master | Master from `KMS_LOCAL_MASTER_KEY`, length-checked at boot; data key from `crypto/rand` | 12 bytes, `crypto/rand` | Master in environment or file, memory only | `internal/infrastructure/kms/local.go` | +| Organization data key, on a node | None held | n/a | n/a | n/a | A node holds no key material; it posts sealed keys to the control plane and gets plaintext back | `internal/infrastructure/kms/brokered.go` | +| Message bodies, integration and MCP tokens | AES-256-GCM, nonce prefixed, base64 | 256-bit data key | Per organization, above | 12 bytes, `crypto/rand` | Plaintext key cached in Redis for 15 minutes | `internal/app/cipher/encrypt.go`, `decrypt.go`, `cache.go` | +| Mailbox SMTP and IMAP credentials, mailbox OAuth tokens, webhook signing secrets | AES-256-GCM, nonce prefixed, hex | 256-bit `CREDENTIALS_ENCRYPTION_KEY` | Operator-supplied, 64 hex characters, validated at boot | 12 bytes, `crypto/rand` | Environment variable; writes fail closed without it | `internal/pkg/encrypt/encrypter.go`, `internal/repository/pg_email.go`, `pg_webhook.go` | +| TOTP secrets | AES-256-GCM | 256-bit, SHA-256 of `TWOFA_SECRET` | Operator-supplied, falls back to `AUTH_SECRET` | 12 bytes, `crypto/rand` | Rotating it invalidates enrolled authenticators, which is documented | `internal/app/twofa/seal.go` | +| Workspace export archives | Argon2id then AES-256-GCM | 256-bit derived | Argon2id t=4, m=256 MiB, p=4 from the passphrase | 16-byte salt, 12-byte nonce, `crypto/rand` | The passphrase is never stored; parameters are clamped on import | `internal/app/orgtransfer/seal.go` | + +## Password and code hashing + +| Operation | Algorithm | Parameters | Salt | Evidence | +|---|---|---|---|---| +| Account passwords | Argon2id | m=64 MiB, t=3, p=2, 32-byte output | 16 bytes, `crypto/rand` | `internal/pkg/argon2/config.go`, `hash.go` | +| Emailed login and registration codes | Argon2id | same | same | `internal/app/auth/login.go`, `registration.go` | +| 2FA recovery codes | Argon2id | same | same | `internal/app/twofa/recovery.go` | + +Argon2id is in the approved list in NIST SP 800-63B 5.1.1.2, and these +parameters exceed the OWASP minimum. Verification is constant-time +(`internal/pkg/argon2/verify.go`). + +## Token hashing + +These are high-entropy random values, so an unsalted SHA-256 is the correct +construction: there is nothing to brute-force and the lookup has to be by exact +value. + +| Token | Bits of entropy | Stored as | Evidence | +|---|---|---|---| +| API key | 256 | SHA-256 hex | `internal/app/apikey/service.go` | +| OAuth authorization code, access token, refresh token | 256 each | SHA-256 | `internal/app/oauth/service.go` | +| CLI device code | 256 | SHA-256 | `internal/app/cliauth/service.go` | +| Fleet join token | 256 | SHA-256, constant-time compare | `internal/app/fleetnode/service.go` | +| First-run setup token | 256 | SHA-256 | `internal/app/bootstrap/bootstrap.go` | + +## Message authentication + +| Operation | Algorithm | Key | Comparison | Evidence | +|---|---|---|---|---| +| Outbound webhook signature | HMAC-SHA256 over `.` | 256-bit per endpoint, encrypted at rest | Receiver's | `internal/app/webhook/service.go` | +| Unsubscribe link token | HMAC-SHA256, 128-bit truncated tag | Derived from `AUTH_SECRET` with a purpose string | `hmac.Equal` | `internal/app/unsublink/signer.go` | +| Forms render token | HMAC-SHA256 | SHA-256 of the internal token plus a purpose string | `hmac.Equal` | `internal/formserver/token.go` | +| Inbound GitHub release webhook | HMAC-SHA256 | Operator secret | `hmac.Equal` | `internal/app/releases/service.go` | +| Stripe webhook | Stripe's signature scheme | Stripe secret | Library | `internal/app/stripe/service.go` | + +Every key here is domain-separated: a key derived for one purpose cannot verify +another purpose's tag. + +## Digital signatures + +| Operation | Algorithm | Key | Validation | Evidence | +|---|---|---|---|---| +| Session, refresh, websocket, challenge and reset tokens | HS256 | `AUTH_SECRET`, at least 32 bytes, enforced at boot | Algorithm pinned to HS256, expiry required, purpose claim required | `internal/app/token/gen.go`, `internal/config/config_auth.go` | +| Same tokens, verified by the realtime service | HS256 | The same value as `JWT_SECRET`, same floor | `verify_strict` with an exact algorithm list, purpose required | `realtime/lib/realtime/auth.ex` | +| Google and Apple ID tokens | RS256 | Provider JWKS | Algorithm pinned, issuer and audience checked, expiry required | `internal/pkg/idtoken/idtoken.go` | +| Cloud Tasks caller | RS256 | Google JWKS | Algorithm, issuer, subject and audience checked | `internal/api/middleware/oidc.go` | +| APNs authentication | ES256 (P-256) | Apple `.p8` | Apple's | `internal/infrastructure/apns/client.go` | + +## Randomness + +Every secret, nonce, salt and token comes from `crypto/rand`: +`internal/pkg/crypt/gen.go` is the shared source. The six-digit verification +code uses `rand.Int` with a bound rather than a modulo, so it is unbiased. + +`math/rand` is used only for scheduling jitter, warmup behaviour sampling and +spintax selection, none of which is a security decision. + +## Transport + +| Connection | Minimum version | Verification | +|---|---|---| +| Inbound HTTPS | 1.2, edge-terminated | Let's Encrypt or platform certificate | +| Outbound SMTP | 1.2 explicit | Full verification; cleartext only to a loopback peer on a self-host, checked on the socket | +| Outbound IMAP | 1.2 (Go default) | Full verification, same loopback exception | +| Outbound HTTP | 1.2 (Go default) | Full verification, through the SSRF-guarded client | +| Postgres | Operator-set `sslmode` | `verify-full` with the RDS bundle in the production template | +| Redis, NATS, Kafka | TLS schemes supported and used across untrusted networks | System roots | + +## Algorithms deliberately absent + +No MD5, DES, 3DES, RC4, or any CBC mode. SHA-1 appears only inside RFC 6238 +TOTP, where the specification requires it and where it is used as an HMAC key +derivation rather than for collision resistance. + +## Key management summary + +| Key | Where it lives | Rotation | +|---|---|---| +| AWS KMS CMK | KMS, never leaves it | AWS-managed annual rotation; old ciphertexts continue to decrypt | +| `KMS_LOCAL_MASTER_KEY` | Environment or file, memory only | Manual; requires re-wrapping every organization key | +| Organization data key | Wrapped in Postgres, plaintext cached in Redis for 15 minutes | Per organization, on creation | +| `CREDENTIALS_ENCRYPTION_KEY` | Environment | Manual; requires re-sealing stored credentials | +| `AUTH_SECRET` | Environment | Manual; rotating it invalidates every session, which is the intended effect | +| `TWOFA_SECRET` | Environment | Manual; rotating it invalidates enrolled authenticators, documented | +| Webhook signing secret | Encrypted in Postgres | Customer-initiated, per endpoint | +| API key | Hashed in Postgres | Customer-initiated: create new, revoke old | + +Rotating the two instance-wide keys currently requires a re-encryption pass that +is not yet automated. Recorded here as a known gap rather than claimed as done. diff --git a/compliance/casa/evidence.md b/compliance/casa/evidence.md new file mode 100644 index 000000000..20fdb7524 --- /dev/null +++ b/compliance/casa/evidence.md @@ -0,0 +1,917 @@ +# CASA evidence + +**Specification:** App Defense Alliance CASA v2.1.1 (2026-06-03) +**Assurance level:** AL1 +**Application:** Warmbly +**Google OAuth client:** `warmbly-mailboxes` (project 1010273043313) +**Repository state:** branch `chore/casa-al1-security-assessment`, base commit `b31c5d52` +**Prepared:** 2026-09-19 + +Scope is defined in `scope.md`. Cryptographic detail for 4.1.3 is in +`crypto-inventory.md`. OAuth detail for 3.2.1 and 3.2.2 is in `oauth.md`. + +This document states the controls as they stand. The change log for the +assessment, which necessarily describes what each control replaced, is held +outside this repository and supplied to the lab directly: Warmbly is +self-hostable, so a public account of what a given control fixed is a map of +every instance that has not updated yet. + +Every file reference below is `path:line` at the commit above. + +--- + +## 1 Authentication + +### 1.1.1 Authentication is resistant to brute force attacks + +**Status: meets the requirement.** CASA asks for at least one of five controls. +Warmbly implements four of them. + +**External authentication services.** Google Sign-In, Apple Sign-In and, for +self-hosted instances, a generic enterprise OIDC provider. Each is listed in +`oauth.md`. A deployment may also use none of them, so the controls below stand +on their own. + +**Control 2.1, rate limiting under 100 failed attempts per account per hour.** +Failed passwords are counted per account, in Redis, keyed on a hash of the +address: + +- `internal/app/auth/config.go` — `LoginFailureLimit = 10`, `LoginFailureTTL = 1 hour` +- `internal/app/auth/cache.go` — `getLoginFailureKey`, `loginFailureExceeded`, `recordLoginFailure`, `clearLoginFailures` +- `internal/app/auth/login.go:36` — the budget is checked before the hash comparison, so a caller past the limit cannot even measure Argon2's timing +- `internal/app/auth/login.go:43` — a wrong password is charged; `:47` clears the count on success + +Ten per hour is well inside the hundred CASA allows. The counter is keyed on the +address rather than the resolved user id, so a guesser learns nothing from the +difference between an account that exists and one that does not. + +Per-source limiting sits alongside it: `internal/api/middleware/ratelimit_ip.go` +bounds every unauthenticated `/auth` request to 60 per 15 minutes per IP +(`AUTH_IP_RATE_LIMIT`), and the remaining public routes to 600 per 15 minutes +(`PUBLIC_IP_RATE_LIMIT`). + +**Control 2.2, CAPTCHA.** Cloudflare Turnstile on login, registration, password +reset request and password reset confirm: + +- `internal/pkg/captcha/turnstile.go` — verifier, including remote-IP check, optional hostname pin and a five-minute challenge-freshness window +- `internal/app/auth/login.go:26`, `internal/app/auth/registration.go:31`, `internal/app/auth/reset_password.go:20` and `:138` — enforcement + +Enabled by setting `TURNSTILE_SECRET`. The hosted deployment sets it. A +self-hosted instance may not, which is why control 2.1 above is unconditional. + +**Control 2.4, minimum length with breached-password prohibition.** Both halves, +server-side: + +- `internal/pkg/crypt/validation.go` — `CheckPassword`: 8 to 128 characters, then a denylist lookup +- `internal/pkg/crypt/passwords/breached.txt` — the UK NCSC list of the 100,000 most commonly breached passwords, reduced to the 46,528 entries long enough to pass the length rule. Sourced from the Have I Been Pwned corpus +- `internal/pkg/crypt/validation.go` — `IsBreachedPassword` lowercases the candidate, so recasing a known password does not get past it +- `internal/pkg/crypt/validation_test.go` — regression tests, including that the list is actually loaded + +Applied at every entry point: `internal/app/auth/registration.go`, +`internal/app/auth/reset_password.go` (both reset and change), +`internal/app/bootstrap/bootstrap.go`, `cmd/warmblyctl/password.go`. + +This follows NIST SP 800-63B 5.1.1.2, which asks for a breach check and +explicitly discourages composition rules. + +**Control 2.5, additional check from an unfamiliar device or location.** + +- `internal/app/auth/login.go:120-149` — `loginCodeRequired`; under `AUTH_LOGIN_CODE=new_device` an emailed code is demanded for a user-agent not seen before +- `internal/app/authrisk/authrisk.go:33-70` — impossible-travel check; two sign-ins that could not be the same person travelling (faster than 1000 km/h) force the code even from a known device +- `internal/app/auth/cache.go` — known-device memory, 90 days + +**Control 2.3, MFA enforced by default,** is the one Warmbly does not claim for +all users. TOTP and passkeys are available to everyone and are enforced for +administrative accounts (see 3.3.1). + +**Artifacts:** `artifacts/screenshots/` (rate limit refusal, CAPTCHA challenge, +breached-password refusal, emailed-code challenge from a new device). + +### 1.1.2 System-generated initial passwords or activation codes + +**Status: meets the requirement.** + +Warmbly generates no initial passwords. An account gets a password one of three +ways: the person chooses it at registration, the operator supplies one when +creating the first owner, or the person sets one through a reset. None of them +is a system-generated password that could become a long-term one. + +Codes and one-time tokens: + +| Verifier | Generation | Length / entropy | Expiry | Single use | +|---|---|---|---|---| +| Registration code | `internal/pkg/crypt/gen.go` `VerificationCode`, `crypto/rand.Int` | 6 digits, ~19.9 bits | 10 min | 3 attempts, session deleted | +| Login code | same | 6 digits | 10 min | 3 attempts | +| First-run setup token | `internal/app/bootstrap/bootstrap.go:170` | 32 bytes, 256 bits | 24 h | `GETDEL`, and refused once any account exists | +| Team invitation | `internal/app/organization/service.go:1201` | 32 bytes, 256 bits | 7 days default | Deleted on acceptance | +| Password reset | `internal/app/auth/reset_password.go:83` | JWT plus a 128-bit nonce | 1 h | Nonce deleted before use | + +Codes are stored Argon2id-hashed, never in the clear. The 24-hour setup token is +inside the 48-hour maximum; the 7-day invitation is a capability to join a +workspace, not an account credential, and is the value CASA allows for a +link-style verifier. + +### 1.1.3 Passwords stored in a form resistant to offline attacks + +**Status: meets the requirement.** + +Argon2id, which is in the NIST SP 800-63B 5.1.1.2 approved list: + +- `internal/pkg/argon2/config.go` — memory 64 MiB, iterations 3, parallelism 2, 16-byte salt, 32-byte output +- `internal/pkg/argon2/hash.go` — `argon2.IDKey`, PHC-encoded, salt from `crypto/rand` +- `internal/pkg/argon2/verify.go:30` — `subtle.ConstantTimeCompare` + +The parameters exceed the OWASP minimum of 19 MiB / t=2 / p=1. Comparison +happens at `internal/repository/pg_auth.go:67` and +`internal/app/auth/reset_password.go:203`. + +Argon2id also protects the emailed login and registration codes and the 2FA +recovery codes. Full inventory in `crypto-inventory.md`. + +### 1.2.1 Default credentials on publicly exposed interfaces + +**Status: meets the requirement.** + +No account exists on a fresh instance. The first one is created either from an +operator-supplied password or by claiming a one-time setup link printed at boot, +and the claim is refused once any account exists +(`internal/app/bootstrap/bootstrap.go:270-294`). + +Fixture accounts with published passwords exist for local development only +(`cmd/seed`, `internal/seed`). Three things keep them out of a deployment: + +- the compose seed service is behind a profile and is never published (`docker-compose.yml`) +- the installer has no seed step +- `cmd/seed/main.go` refuses to run when `APP_ENV` is set to anything other than a development value, which closes the case where the binary inside the release image is pointed at a production database + +`internal/app/instancecheck/checks_security.go` reports a published default +secret still in use as an instance finding, continuously rather than once at +boot. + +### 1.3.1 Out of band verifier expires in a reasonable timeframe + +**Status: meets the requirement.** Password reset expires in 1 hour, inside the +7 days CASA allows. MFA-related verifiers expire in 10 minutes (emailed code) and +5 minutes (2FA pending challenge), inside the 30 minutes allowed. See the table +under 1.1.2. + +### 1.3.2 Out of band verifier used only once + +**Status: meets the requirement.** + +- Emailed login and registration codes: the session is deleted on success (`internal/app/auth/login.go:186`) +- Password reset: the nonce is deleted before the password is written (`internal/app/auth/cache.go`) +- 2FA pending challenge: deleted before the session is minted (`internal/app/twofa/login.go:74-77`) +- Recovery codes: consumed by compare-and-swap on `used_at` (`internal/repository/pg_totp.go`) +- TOTP: the accepted time step is retired, so the same six digits cannot be presented twice inside their validity window (`internal/app/twofa/totp.go` `ValidateCodeStep`, `internal/repository/pg_totp.go` `ConsumeTOTPStep`, migration `000183`). The update is compare-and-swap, so two requests racing with one code cannot both win +- Setup token and SSO state: `GETDEL` +- Mailbox OAuth state: `GETDEL` (`internal/app/email/cache.go`) + +### 1.3.3 Out of band verifier is securely random + +**Status: meets the requirement.** Every verifier comes from `crypto/rand`: +`internal/pkg/crypt/gen.go` (`Nonce`, `VerificationCode` via `rand.Int`, so no +modulo bias), `internal/app/bootstrap/bootstrap.go`, +`internal/app/organization/service.go`, `internal/app/oauth/service.go`. No use +of `math/rand` for any secret; its only uses are scheduling jitter and warmup +behaviour sampling. + +### 1.3.4 Out of band verifier resists brute force + +**Status: meets the requirement.** The six-digit codes carry ~19.9 bits, above +the 20-bit guidance for a six-digit number, and being under 64 bits they are +rate limited as CASA requires: + +- 3 attempts per login or registration session (`internal/app/auth/config.go` `AuthAttempts`) +- 5 sends per address per 30 minutes (`AuthEmailLimit`, `AuthEmailTTL`) +- 2 password-reset requests per address per 4 hours (`PasswordResetLimit`) +- 5 attempts per 2FA challenge, plus 20 verifications per IP per 15 minutes (`internal/app/twofa/service.go`) +- 60 requests per IP per 15 minutes across the whole `/auth` group + +Every link-style token is 128 bits or more and needs no rate limit by the same +rule. + +--- + +## 2 Session Management + +### 2.1.1 No passwords or session tokens in URL parameters + +**Status: meets the requirement.** Evidence: Burp scan (see `README.md`), plus: + +Credentials are read from the `Authorization` header only: +`internal/api/middleware/auth.go:21-28`, `internal/api/middleware/apikey.go:70-88`. +A grep for query-parameter credential reads across `internal/` and `cmd/` finds +none. Passwords travel in JSON bodies on POST; there is no GET login form. + +Tokens that do appear in a URL are single-purpose, single-use and short-lived, +never session tokens: the password-reset link (1 h), the invitation link, the +first-run setup link (24 h), the SSO handoff code (60 s), OAuth callback codes, +and the WebSocket ticket (10 min, minted per connect by `POST /v1/getaway`). + +The WebSocket takes its credential as a query parameter because that is what the +Phoenix transport supports. That credential is now a purpose-scoped ticket and +nothing else: see 2.3.4. + +### 2.2.1 Logout invalidates stateful session tokens + +**Status: meets the requirement.** + +Sessions are stateful. The access and refresh tokens are JWTs, but each carries a +nonce that must match the `sessions` row, so both are revocable: + +- `internal/app/token/verify.go:41-68` — rejects a revoked session and a stale nonce +- `internal/app/token/logout.go` — `RevokeSession` stamps `revoked_at` and deletes the Redis cache entry, so revocation is immediate rather than waiting out the cache TTL +- `internal/app/token/logout.go` — `RevokeAllSession` for "sign out everywhere" +- `internal/repository/pg_token.go` — refresh rotates both nonces by compare-and-swap, so a replayed refresh token fails +- `internal/api/handler/session.go` — self-service session list and revocation + +A ban now revokes live sessions too, through the token service so the cache is +cleared as well (`internal/app/admin/service.go`, `cmd/backend/main.go`). + +### 2.2.2 Password change terminates other sessions + +**Status: meets the requirement.** + +- `internal/app/auth/reset_password.go:203-237` — changing a password requires the current one and then revokes every other session +- `internal/app/auth/reset_password.go:178-186` — a forgotten-password reset revokes all sessions +- `internal/repository/pg_token.go` — `RevokeOtherSessions` has no provider filter, so federated and passkey sessions are covered + +### 2.2.3 Non-revocable stateless tokens expire within 24 hours + +**Status: meets the requirement.** Every stateless token Warmbly mints is either +inside 24 hours or bound to a revocable server-side record: + +| Token | TTL | Revocable | +|---|---|---| +| Access JWT | 12 h | Yes, session nonce | +| Refresh JWT | 180 d | Yes, session nonce, rotated on every use | +| Login-code challenge | 10 min | Yes, Redis nonce | +| Password reset | 1 h | Yes, Redis nonce | +| 2FA pending | 5 min | Yes, Redis record | +| WebSocket ticket | 10 min | n/a, inside 24 h | +| OAuth access token | 1 h | Yes, hashed row | +| OAuth refresh token | 90 d | Yes, hashed row, rotated | + +Constants: `internal/app/token/config.go`, `internal/app/auth/config.go`, +`internal/app/socket/config.go`, `internal/models/oauth_app.go`. + +### 2.3.1 and 2.3.2 Cookie Secure and HttpOnly attributes + +**Status: not applicable, and confirmed by construction.** Warmbly sets no +cookies anywhere. A grep for `SetCookie`, `http.Cookie` and `Set-Cookie` across +`internal/` and `cmd/` returns nothing; no frontend uses `credentials: include`. +Authentication is a bearer token in the `Authorization` header on every surface: +dashboard, admin panel, iOS app and API. + +Because the token is in `localStorage` rather than a cookie, the relevant client +risk is XSS rather than CSRF. The compensating controls are the content security +policy and framing headers added for 5.1.7, React's default escaping, the +parser-based sanitizer on all rendered HTML, the 12-hour access token, and +immediate server-side revocation. + +Evidence: Burp scan should report no cookie findings, because there are no +cookies. + +### 2.3.3 Session tokens rather than static API secrets + +**Status: meets the requirement.** + +A session is minted only after authentication, through one path for every +provider (`internal/app/auth/login.go` `finishLoginAsWith`). The session id is a +fresh UUID and both nonces are 128 bits from `crypto/rand` +(`internal/app/token/gen.go`). + +API keys exist as a deliberate developer feature, not as the primary +authentication: 256-bit random, SHA-256 at rest, per-key permission bitmask, IP +allowlist, optional expiry, per-key rate limit, mailbox allowlist, revocation +with reason (`internal/app/apikey/service.go`, +`internal/api/middleware/apikey.go`). Third-party applications are steered to +OAuth 2.1 with one-hour access tokens instead. + +Sensitive routes refuse API keys entirely and require a session +(`internal/api/routes.go`, the `jwtOnly` group), including creating an API key. + +### 2.3.4 Stateless tokens signed, protected against substitution + +**Status: meets the requirement.** + +- `internal/app/token/gen.go` — HS256, and the verifier pins exactly that algorithm with `jwt.WithValidMethods([]string{"HS256"})` and `jwt.WithExpirationRequired()`. `alg=none` is refused +- `internal/config/config_auth.go` — `AUTH_SECRET` must be at least 32 bytes, enforced at boot. `realtime/config/runtime.exs` applies the same floor to the same value +- `realtime/lib/realtime/auth.ex` — `JOSE.JWT.verify_strict(..., ["HS256"], ...)` +- `internal/pkg/idtoken/idtoken.go` — third-party ID tokens are RS256-pinned with JWKS, issuer and audience checks +- `internal/api/middleware/oidc.go` — the Cloud Tasks caller check pins RS256 and now also the audience + +**Token substitution between flows.** One signing key issues the access, +refresh, websocket, login-challenge, 2FA-pending and password-reset tokens. +Every token now carries a `purpose` claim and every verifier requires the one it +expects: + +- `internal/app/token/config.go` — the `Purpose*` constants +- `internal/app/token/gen.go` — `GenerateTokenFor` +- `internal/app/token/verify.go` — `VerifyTokenFor` +- `realtime/lib/realtime/auth.ex` — the socket accepts `purpose: "ws"` and nothing else +- `internal/app/token/purpose_test.go` — a token minted for any one purpose is refused for every other + +### 2.4.1 Sensitive account modifications require re-authentication + +**Status: meets the requirement.** + +Two-stage sign-in exists and the intermediate token is not a session: the +challenge token issued after a password has no `sessions` row, so it is refused +by `ValidateAccessToken` (`internal/app/token/verify.go:51-66`) and can only be +spent at `LoginConfirm`. The same holds for the 2FA pending token. + +Already re-verified before the change: + +| Action | What it asks for | Evidence | +|---|---|---| +| Change password | Current password | `internal/app/auth/reset_password.go:203` | +| Disable 2FA | Current TOTP or recovery code | `internal/app/twofa/service.go:74` | + +Now gated by a fresh confirmation (`RequireFreshAuth`, five-minute window): + +| Action | Route | +|---|---| +| Create an API key | `POST /api-keys` | +| Add a passkey | `POST /auth/passkey/register/begin`, `/finish` | +| Remove a passkey | `DELETE /auth/passkey/credentials/:id` | +| Transfer a workspace | `POST /organizations/transfer-ownership` | +| Schedule workspace deletion | `POST /organizations/current/danger-zone/delete` | +| Schedule account deletion | `POST /me/danger-zone/delete` | + +- `internal/api/middleware/fresh_auth.go` — the gate. It applies to session callers. An API key and an OAuth token have no session and no second factor to present; each was itself minted from a confirmed session, its use is audited, and the route's permission gate governs it, so they pass through. The threat this addresses is a browser token lifted from an unattended machine, and refusing automation would exceed what the control asks for +- `internal/api/handler/reauth.go` — `POST /v1/auth/reauth`, accepting a password or a current TOTP or recovery code +- `internal/app/token/reauth.go` — `ReauthWindow`, the stamp, and the cache bust +- `internal/app/auth/cache.go` — a per-account budget on confirmations, because this endpoint checks a password and would otherwise be a second, unthrottled place to guess one +- migration `000184` — `sessions.reauth_at` +- `web/src/components/app/modals/ReauthModal.tsx` and `web/src/lib/api/client/Request.ts` — the client prompts and retries automatically + +Workspace and account deletion additionally require typing the exact name, and +are delayed and cancellable (`internal/api/handler/danger_zone.go`). + +An account created through Google, Apple or enterprise SSO may hold neither a +password nor an enrolled authenticator. There is nothing for it to confirm with, +and accepting the live session instead would turn a stolen token into a +permanent API key, so the endpoint refuses with `reauth_no_factor` and names the +remedy: enrol two-factor authentication, which is not itself gated. This is a +deliberate choice of friction over a silent hole, and it leaves such accounts +with a recovery factor they did not have before. + +--- + +## 3 Access Control + +### 3.1.1, 3.1.2, 3.1.3 Least privilege on a trusted service layer + +**Status: meets the requirement.** One written description covers all three, as +CASA allows. + +**Where access control is decided.** Entirely server-side, in middleware ahead of +every handler (`internal/api/routes.go`, `internal/api/middleware/`). The +frontend hides what a role cannot use, but hiding is not the control: every +route re-derives the caller's identity, workspace and permissions from the +database on each request. + +**Identity.** `AuthMiddleware` (`auth.go`) validates the bearer token against the +`sessions` row. `CombinedAuthMiddleware` (`apikey.go`) additionally accepts an +API key or an OAuth access token, each resolved to its organization and +permission mask. + +**Workspace context.** Taken from the session's `current_organization_id`, the +API key's organization, or the OAuth grant. It is never taken from a request +body. Where a route carries an organization id in its path, membership is +verified before the handler runs (`internal/api/middleware/organization.go` +`RequireMembership`, and `requireMember` in +`internal/app/organization/service.go` for the routes whose path parameter the +middleware does not match). + +**Roles and permissions.** A uint16 bitmask per member +(`internal/models/organization_permission.go`), with seeded Admin, Manager and +Viewer roles plus custom roles. The owner is a flag on the organization, not a +role, and always holds every permission. + +**No self-elevation.** `UpdateMemberRole` +(`internal/app/organization/service.go`) refuses to re-role yourself, refuses to +touch the owner, and requires the actor to already hold every permission being +granted. Ownership transfer now additionally requires the actor to be the owner. +On the platform-admin side, `GrantAdminPermissions` +(`internal/app/admin/service.go`) refuses to grant a bit the granter does not +hold, and `RevokeAdminPermissions` refuses to remove the last super admin. + +**Fail closed.** Every middleware aborts on error rather than continuing: a +database or cache failure produces 401, 403 or 500 and the handler never runs. +The membership helper is the explicit form of this, because +`GetMembership` answers `(nil, nil)` for a non-member and a caller that only +tests the error would let everyone through. + +**Least privilege in the architecture, not just the API.** A worker holds no +database credential and no cloud credential: it reaches relational data through +the internal API and gets key and blob operations brokered +(`internal/api/handler/internal_dek.go`, `internal_blobs.go`), with the blob +presigner restricted to three key prefixes. + +### 3.1.4 Insecure Direct Object Reference + +**Status: meets the requirement.** + +**The pattern.** Every repository method that reads or writes a tenant-owned row +takes the organization id as a parameter and filters on it in SQL. The +identifier from the request is never the only predicate. For example +`internal/repository/pg_contact.go` — `WHERE id = $1 AND organization_id = $2` +on get, update and delete; bulk operations use `id = ANY($1) AND organization_id = $2`. + +**APIs that accept a caller-supplied identifier.** Path parameters on every +resource (campaigns, contacts, mailboxes, sequences, automations, templates, API +keys, webhooks, members, threads, forms, CRM records), plus body identifiers on +create and update. The full route list is +`docs/content/docs/api/endpoints.mdx`. + +**How they are protected.** + +1. Path identifiers are scoped in the query, as above. +2. Body identifiers that reference another row are verified to belong to the + caller's workspace before being stored. `internal/repository/pg_crm.go` + `verifyRefs` does this for every reference a deal, task or note can carry. +3. Read-side joins carry the tenant predicate too, so a row that somehow holds a + foreign reference still discloses nothing (`pg_crm.go`, the `SearchDeals` + joins). +4. A foreign identifier answers 404, never 403, so a prober cannot tell an id + that exists elsewhere from one that does not exist. +5. Public object references are unguessable capabilities rather than sequential + ids: form public ids are 105 bits, unsubscribe tokens are HMAC-signed or + 128-bit random, tracked links and tracking tickets are UUIDv4. + +A review of every handler and repository method against this pattern was +carried out for this assessment, and the findings were remediated. The change +log is supplied to the lab separately, for the reason given at the top of this +document. + +### 3.1.5 Anti-CSRF + +**Status: meets the requirement.** Evidence: Burp scan. + +Warmbly sets no cookies and uses no ambient browser credential, so a +cross-site request carries no authority: the bearer token has to be attached by +JavaScript that the attacker's origin cannot run. That is the primary control +and it is structural. + +Supporting controls: + +- CORS is an explicit origin allowlist with credentials, or wildcard without credentials, never both (`internal/api/routes.go`, `internal/api/cors.go`) +- `X-Frame-Options: DENY` and `frame-ancestors 'none'` on the API, and on the dashboard and admin panel (`internal/api/middleware/security_headers.go`, `web/nginx-security-headers.conf`, `web/public/_headers`) +- unauthenticated state-changing endpoints carry anti-automation: Turnstile on registration, login and password reset; honeypot, timing trap and per-IP budget on public form submission + +### 3.1.6 Directory browsing disabled + +**Status: meets the requirement.** Evidence: Burp scan. + +No component serves a directory index. The forms service uses gin's `Static`, +which wraps the filesystem so `Readdir` returns nothing +(`internal/formserver/server.go`). The nginx images set no `autoindex`, so the +default off applies (`web/nginx.conf`, `admin/nginx.conf`, +`deploy/nginx/warmbly.conf`). The Rust and Elixir services register fixed routes +and mount no static tree. The backend's `/public` route serves a single object +per request, restricted to four key prefixes, and now refuses a key naming a +directory (`internal/infrastructure/storage/filesystem.go`). + +### 3.2.1 and 3.2.2 OAuth + +**Status: meets the requirement.** Full detail in `oauth.md`, including the +exact Google scopes. + +Summary: every integration uses the authorization code flow. The implicit and +resource-owner-password grants are not implemented anywhere, as a client or as a +server. PKCE is used on every flow that supports it, including the Gmail and +Microsoft mailbox flows. `redirect_uri` is a fixed server-side value derived +from configuration, never taken from the request. `state` is 128 to 256 bits +from `crypto/rand`, stored server-side, bound to the user who started the flow, +and consumed atomically with `GETDEL`. + +### 3.3.1 Administrative interfaces use multi-factor authentication + +**Status: meets the requirement.** + +The admin panel is the only application-exposed administrative interface. It is +limited to application-layer functions and exposes no cloud infrastructure: +there is no install, restart, shell, logs or reboot action anywhere in it. + +MFA is enforced, not merely available: + +- `internal/api/middleware/admin.go` — `AdminMiddleware` refuses any session that did not present a second factor, with code `admin_mfa_required` +- migration `000182` — `sessions.mfa_verified` +- `internal/app/token/gen.go` — `GenerateMFASession`, the only way the flag is set +- `internal/app/twofa/login.go` and `internal/app/passkey/login.go` — the only two callers: a TOTP or recovery code, or a passkey +- `admin/src/components/layout/RequireAdmin.tsx` — explains the refusal and points at where to enrol + +The check is on the session rather than on enrolment, so an admin who turns 2FA +on does not silently keep a single-factor session. Existing sessions default to +not verified, which is the safe direction. It is not configurable. + +A passkey counts as multi-factor: the credential never leaves the device and the +platform unlocks it with a biometric or PIN. + +`warmblyctl` is the operator's other surface. It talks to the database directly, +serves no HTTP, and is not internet-exposed; access to it is access to the +database. + +--- + +## 4 Communications + +### 4.1.1 TLS enforced, 1.2 or above, strong ciphers + +**Status: meets the requirement.** Evidence: Qualys SSL Labs report per hostname +in `artifacts/`. + +TLS is terminated at the edge on every deployment shape: Railway and Cloudflare +for the hosted service, bundled Caddy 2 with automatic HTTPS for the +one-command self-host, nginx with Let's Encrypt for bare metal. All three +default to TLS 1.2 and 1.3 with modern cipher suites. + +HSTS is now emitted by every layer: `internal/api/middleware/security_headers.go` +(on a request the edge reports as HTTPS), the rendered Caddyfile in +`site/public/install.sh`, `deploy/nginx/warmbly.conf`, +`web/nginx-security-headers.conf`, and the Cloudflare Pages `_headers` files. + +Outbound TLS is enforced rather than assumed. Connections to a customer's +mailbox provider require TLS or STARTTLS +(`internal/client/smtpimap/smtp/client.go`, `internal/client/smtpimap/imap/client.go`, +both with `MinVersion: tls.VersionTLS12`); cleartext is possible only to a +loopback peer on a self-hosted instance, checked twice, once on the hostname and +once on the actual socket (`internal/client/netbind/netbind.go`). Outbound +webhooks require HTTPS and a public address unless the operator explicitly opts +out (`internal/app/webhook/service.go`). + +### 4.1.2 Trusted TLS certificates + +**Status: meets the requirement.** Evidence: the same Qualys reports. + +Certificates are issued by Let's Encrypt or the platform edge. No self-signed +certificate is trusted anywhere in the default configuration. +`InsecureSkipVerify` appears only behind an operator-set development flag +(`MAIL_TLS_INSECURE`, `internal/client/netbind/netbind.go`) and in the local +sandbox package, and the installer pins it to false. + +### 4.1.3 No weak cryptography + +**Status: meets the requirement.** Full inventory in `crypto-inventory.md`, +covering every encryption, hashing and MAC operation with algorithm, key size, +key and IV generation, and key management. + +Summary: AES-256-GCM for everything encrypted at rest, with 12-byte nonces from +`crypto/rand`; Argon2id for passwords and codes; SHA-256 for token lookup; +HMAC-SHA256 for webhook and link signatures; HS256 with a key of at least 32 +bytes for sessions; RS256 with JWKS for third-party ID tokens; ES256 for APNs. + +No MD5, DES, RC4 or CBC anywhere. SHA-1 appears only inside RFC 6238 TOTP, where +the specification requires it. + +### 4.1.4 Cryptographic modules fail securely + +**Status: meets the requirement.** + +Every symmetric operation is AES-GCM. There is no CBC and no padded mode +anywhere, so a padding oracle has nothing to attack: an authentication failure +is indistinguishable from any other decryption failure. + +Failures are opaque to the caller. `internal/app/cipher/decrypt.go` returns a +generic error; callers report it to the error tracker and answer with a generic +message. The data-key broker returns one fixed sentence regardless of cause +(`internal/api/handler/internal_dek.go`), deliberately, so a prober cannot tell +"not one of our keys" from "malformed". As of this assessment, every +internal-class error answers with one fixed sentence and logs the detail against +the request id (`internal/errx/errx.go` `clientMessage`). + +Comparisons on attacker-supplied secrets are constant-time throughout: +`subtle.ConstantTimeCompare` for internal tokens, join tokens and Argon2 output; +`hmac.Equal` for every HMAC. + +--- + +## 5 Data Validation and Sanitization + +Test cases 5.1.1 through 5.1.10 are validated by the authenticated Burp scan. +The written controls below describe what the scan is expected to confirm. + +### 5.1.1 HTTP parameter pollution + +Query parameters are parsed first-value-wins by gin, matching Go's `net/url` and +the proxies in front of it, so there is no front-end/back-end disagreement to +exploit. Only one route reads a multi-value parameter and it allowlists each +element (`internal/api/handler/advisor.go`). No authentication material is read +from the query string. + +### 5.1.2 URL redirects and forwards + +Redirects are allowlisted or server-derived in every case: + +- OAuth callbacks return to a fixed URL built from configuration +- the login `next` parameter must be a same-origin relative path (`web/src/app/auth/login/page.tsx`) +- OAuth client `redirect_uri` is matched by exact string against the registered list, with dangerous schemes rejected at registration (`internal/app/oauth/flow.go`, `internal/app/oauth/dcr.go`) +- Stripe checkout and portal return URLs are now pinned to this instance's dashboard origin rather than taken from the request (`internal/api/handler/billing_return_url.go`) +- the pool-link return URL is pinned to the registered instance's own host + +The click-tracking redirect is an intentional redirector: the destination is read +from a database row minted when the email was sent, never from the request, and +the scheme is validated to http or https at mint time on the decoded href +(`internal/tasks/links.go`). The URL carries a ticket id and no destination, so +there is no open-redirect parameter to manipulate. + +### 5.1.3 and 5.1.4 Dynamic code execution and template injection + +No scripting engine is embedded: no `eval`, no `new Function`, no JavaScript VM, +no Lua, no Starlark. The frontend contains no `eval` or `new Function`. + +The expression and merge-field engines use Go `text/template` over a data object +that is a `map[string]string` of contact fields, with a 20-function allowlist of +pure string and arithmetic helpers (`internal/pkg/tmplfuncs/tmplfuncs.go`). No +struct pointer, service handle or `io` value is ever placed in the data, so +there is nothing to pivot to. Spintax is a bounded regex expander with a +20-iteration cap (`internal/tasks/spintax.go`). + +All transactional email templates use `html/template`, which escapes +contextually. + +### 5.1.5 Server-Side Request Forgery + +Every outbound request whose URL a user can influence goes through +`internal/pkg/safehttp`. The guard runs at the dialer, not on the hostname +string, which is what defeats DNS rebinding: + +- resolution happens inside the dialer, and the validated address is the one dialled +- a mixed result set fails closed: one private answer blocks the request +- blocked ranges include loopback, RFC1918, IPv6 unique-local, link-local including 169.254.169.254, CGNAT, multicast, IPv4-mapped IPv6 and the reserved ranges +- a pre-resolution hostname denylist covers `localhost` and the cloud metadata names, closing split-horizon DNS +- ports are restricted to 443 and 8443 +- redirects are re-validated per hop, capped at five; the webhook worker refuses redirects entirely + +Covered surfaces: customer webhooks, webhook verification, user-entered MCP +server URLs, integration actions, AI page fetching, operator notification +channels, and OAuth app webhook URLs. As of this assessment the email +verification MX probe also refuses a non-public address +(`internal/pkg/emailverify/emailverify.go`). + +User-entered IMAP and SMTP hosts are an arbitrary connection by product +necessity. The compensating control is socket-level: after connecting, the peer +address is checked, so a rebinding answer does not help +(`internal/client/netbind/netbind.go`). + +### 5.1.6 XPath and XML injection + +Not applicable, and confirmed structurally: no Go file imports `encoding/xml`. +There is no XPath library, no SAML, and no feed parsing. XXE is impossible. + +XLSX import is the only XML-derived input. It is handled by `excelize`, which +processes OOXML internally without DTD support, and is now bounded against +decompression bombs (512 MiB total, 64 MiB per part) with streaming row reads +and a recover around the parser (`internal/app/contact/import.go`). + +### 5.1.7 Cross-site scripting + +React escapes by default and there are exactly two +`dangerouslySetInnerHTML` uses in the dashboard, both rendering a compile-time +SVG path map. + +Inbound email HTML is the largest untrusted surface. It is sanitized with +`bluemonday` on an allowlist policy that drops `script`, `style`, `iframe`, +`object`, `embed` and `applet` with their content, permits only http, https, +mailto and tel URL schemes, and permits data URIs only for raster images, so +neither `data:text/html` nor SVG survives (`internal/pkg/mailhtml/mailhtml.go`). +It is then rendered in an iframe without `allow-scripts` +(`web/src/components/app/unibox/EmailBody.tsx`). + +The mailbox signature editor now sanitizes with DOMPurify on assignment rather +than inspecting with a regex (`web/src/components/app/EmailEditor.tsx`). + +Security headers are set on every surface: +`internal/api/middleware/security_headers.go` for the API, +`web/nginx-security-headers.conf` and `web/public/_headers` for the dashboard, +the equivalents for the admin panel and marketing site, and per-form +`frame-ancestors` for the forms service. + +The forms default is deliberately unchanged. A form with no configured embed +allowlist may be framed anywhere, which is the documented contract and what +every embed installed without configuring the list depends on; narrowing it +would have taken those forms off their owners' websites with no error anywhere. +What changed is that the permissive case now states `frame-ancestors *` +explicitly instead of sending no header, so the policy is legible to a scanner +and to a reader rather than being an absence. Restricting framing is offered as +a per-form setting, and the documentation now recommends using it. + +### 5.1.8 Database injection + +The repository layer uses pgx with `$n` placeholders throughout, and +`internal/repository/query_prepare_live_test.go` prepares every query in the +package against a live server. + +Where SQL is built dynamically, identifiers come from static allowlists, never +from the request. The segment filter engine, which compiles customer-authored +JSON into SQL, resolves every field through a static catalog and four literal +column maps, matches operators against constants with a `FALSE` default, binds +every value, binds JSONB keys rather than interpolating them, and escapes LIKE +metacharacters (`internal/repository/pg_segment_sql.go`). All eleven dynamic +`ORDER BY` builders allowlist the column. + +Sort keys that reach an `ORDER BY` are bound as parameters rather than +interpolated, and validated at write time against the same rule every other +custom-field key answers to. + +Org export and import triple-guard their identifiers: table names come from a +compiled registry, column names are filtered against the destination's live +catalog, and every identifier passes `pgx.Identifier.Sanitize`. + +### 5.1.9 OS command injection + +No production HTTP service invokes a subprocess. `cmd/backend`, `cmd/worker`, +`cmd/consumer`, `internal/api`, `internal/app` and `internal/formserver` do not +import `os/exec`. The Rust and Elixir services invoke nothing. + +The only request-reachable path is the operator update action, which is behind +the admin bit and MFA, validates the tag against a strict character allowlist +before use, and never invokes a shell (`internal/updater/image.go`). + +### 5.1.10 Local and remote file inclusion + +No `http.ServeFile`, `c.File` or raw `http.Dir` in any HTTP surface. Blob keys +are cleaned and `..` is rejected as a literal path component before +normalization (`internal/infrastructure/storage/filesystem.go`); the public +object route and the node presigner both reject `..` before testing the prefix, +which is the ordering that makes the check correct +(`internal/api/handler/public_object.go`, `internal_blobs.go`). + +### 5.2.1 Untrusted file uploads + +**Status: meets the requirement.** + +| Upload | Limit | Type validation | Stored as | +|---|---|---|---| +| Campaign attachment | 15 MiB | Extension denylist, sniffed type | `attachments//-`, presigned download only | +| Email image | 5 MiB | Magic-byte allowlist, real image decode, dimension cap | `email-images//.` | +| Avatar | 2 MiB | Magic-byte allowlist, real decode, dimension cap | `avatars//--.` | +| Form asset | 1 to 4 MiB | Magic-byte allowlist, real decode | `form-assets//--.` | +| Contact import | 50 MiB | Extension, then bounded parse | Parsed in memory, never stored | +| Workspace archive | 8 GiB | Zip structure and manifest | Parsed, then discarded | + +The controls that matter for execution: + +- every image path forces the extension from a server-side allowlist, so the stored key cannot end in `.svg` or `.html` +- `/public` derives Content-Type from the key's extension, serves only that image allowlist inline, hands anything else over as `application/octet-stream` with `Content-Disposition: attachment`, and sets `X-Content-Type-Options: nosniff` plus a sandboxing content security policy (`internal/api/handler/public_object.go`) +- attachments are never served from a Warmbly origin; they are fetched by a 15-minute presigned URL +- the workspace-import path validates every object key against the shapes this product mints, forces the image extension under public prefixes, and rewrites the workspace segment of a public key to the importing workspace rather than taking it from the archive, so an archive cannot address another workspace's prefix (`internal/app/orgtransfer/blobkey.go`) + +There is no antivirus scanning. Campaign attachments are relayed to external +recipients as the customer supplied them, which is the same posture as any mail +client; recipient-side scanning is the control. This is stated rather than +claimed otherwise. + +--- + +## 6 Configuration + +### 6.1.1 No components with known exploitable vulnerabilities + +**Status: meets the requirement.** Evidence: `artifacts/` scan output. + +Scanners run in CI (`.github/workflows/security.yml`): `govulncheck` for Go +including the standard library, Trivy for the filesystem, `pnpm audit --prod` +per frontend tree, and `cargo audit` for the Rust service. + +At the commit above: + +| Tree | Result | +|---|---| +| Go | No advisory at CVSS 7.0 or above with a fix available. Four remain with no upstream fix; each is justified below | +| web, admin, site, forms | No high or critical advisory in production dependencies | +| docs | No high or critical advisory in production dependencies | +| tracking (Rust) | Clean | +| realtime (Elixir) | Two cowlib advisories, both below CVSS 7.0 | + +**Justified, no upstream fix available.** CASA permits this where the library +has a regular patch process: + +| Advisory | Component | Why it does not apply | +|---|---|---| +| GO-2026-6452 | `xuri/excelize` | A panic on a crafted shared-string index. Reachable only through contact import, which requires authentication and the `manage_contacts` permission. The parser now runs under a recover and answers 400, and decompression is bounded, so the worst case is a rejected upload | +| GO-2026-5046, 5047, 5048 | `hamba/avro` | Decoder advisories. The decoder is compiled only into the `-kafka` image variant, behind a build tag, and decodes messages from Warmbly's own internal bus, never attacker input. The default images contain no Avro decoder at all | + +Both projects patch regularly; these will be picked up when they do. + +### 6.2.1 Debug modes disabled in production + +**Status: meets the requirement.** Evidence: Burp scan, plus: + +- gin runs in release mode in every shipped configuration (`docker-compose.yml`, `deploy/config/env.example`, `site/public/install.sh`), set explicitly by every service rather than inherited +- no Go file imports `net/http/pprof`; there is no `/debug` route +- panics are reported to the error tracker with their stack and answered with a bare 500 carrying no body (`internal/api/middleware/reporting.go`) +- a 500 response now carries one fixed sentence; the detail is logged against the request id (`internal/errx/errx.go`) +- the Phoenix production config does not print connection details on a failure (`realtime/config/runtime.exs`) +- source maps are generated only when they are being uploaded to the error tracker, and deleted after upload (`web/vite.config.ts`, `web/package.json`) +- health endpoints return a status literal and nothing else + +### 6.3.1 The Origin header is not used for access control + +**Status: meets the requirement.** Evidence: Burp scan. + +Nothing authenticates or authorizes on `Origin`, `Referer` or `Host`. A grep for +those headers finds only CORS configuration and the per-form embed policy. + +CORS never reflects an arbitrary origin with credentials: the wildcard branch +sets `AllowCredentials: false` explicitly, and the allowlist branch enumerates +origins from configuration (`internal/api/routes.go`). Private-network origin +reflection exists only outside release mode, for local development. + +The per-form `frame-ancestors` allowlist is a browser containment directive in a +response header, not a server-side grant derived from a request header. It +grants nobody anything, and the form is equally reachable by direct navigation. + +### 6.4.1 Subdomain takeover + +**Status: meets the requirement.** Evidence: DNS export in `artifacts/`, to be +attached at submission. + +The hostname inventory is in `scope.md`. Every record points at infrastructure +Warmbly controls or at a platform Warmbly holds the account for. + +Customer-owned custom domains are the interesting case: a customer points a +CNAME at Warmbly for tracking or forms. A certificate is issued for such a name +only after the instance has verified it, checked on every request by +`GET /tls/authorize` (`internal/api/handler/tls_authorize.go`), which requires a +verified row, fails closed on a database error, and does not cache the failure. +Background sweeps re-verify and clear a record that stops resolving. + +### 6.5.1 No credentials or payment details in logs + +**Status: meets the requirement.** Evidence: `artifacts/log-sample-login.txt`. + +- the request logger records method, path, status, latency and client IP, and not the query string, which on some routes carries a single-use token placed there by a provider or a mail client (`internal/api/middleware/request_log.go`; the forms service uses the same logger) +- no password, token or secret is logged in any auth code path +- API keys are stored and looked up as SHA-256; the usage log records the key id, never the key +- Warmbly never receives payment details: Stripe Checkout and the billing portal are hosted by Stripe, and no card field exists in this repository +- Sentry's `SendDefaultPII` is off in all three initializations, so request headers, cookies and bodies are not attached +- session replay masks password inputs and every one-time code entry field; console capture is off, and no token is written to the console + +A login request produces one line of the shape recorded in +`artifacts/log-sample-login.txt`. + +### 6.6.1 Browser storage cleared at logout + +**Status: meets the requirement.** + +The dashboard and admin panel store the token pair, a persisted workspace +selection and UI preferences, and reply drafts. There is no IndexedDB, no +service worker, and no persisted query cache. + +One teardown is used by logout and by every path that discovers the session is +gone, so being signed out clears the same things as signing out +(`web/src/lib/session.ts` `clearClientSession`, called from +`web/src/lib/api/hooks/auth/useLogout.ts` and `web/src/hooks/UserProvider.tsx`). +It clears the tokens, the reply drafts, the SSO binding, the persisted store and +the query cache. + +Reply drafts hold the body, subject and recipients of an unsent email, so they +are cleared alongside the tokens (`web/src/lib/auth.ts`, the prefix sweep in +`clearTokens`). + +### 6.7.1 Server-side secrets stored securely + +**Status: meets the requirement.** + +**How secrets reach the application.** Environment variables, from the platform's +secret store on the hosted deployment and from a `.env` file on a self-host. The +installer creates that file with `umask 077` before writing to it, so it is 0600 +from the moment it exists and never briefly world-readable +(`site/public/install.sh`). AWS Secrets Manager and SSM Parameter Store are +supported as alternative sources (`internal/config`). + +**Refusal of published defaults.** The backend will not start when one of the +five published development secrets is still in use +(`cmd/backend/boot.go`), and `AUTH_SECRET` must be at least 32 bytes. + +**Customer secrets at rest.** + +| Secret | Protection | +|---|---| +| Mailbox SMTP and IMAP credentials | AES-256-GCM under the instance credential key | +| Mailbox OAuth tokens | AES-256-GCM under the instance credential key | +| Integration and MCP tokens | AES-256-GCM under the per-organization data key | +| API keys | SHA-256, irreversible, shown once | +| Webhook signing secrets | AES-256-GCM under the instance credential key. A workspace archive carries the secret only when exported with credentials, and the export and import guide says to rotate after a move | +| TOTP secrets | AES-256-GCM under a dedicated key | + +**Access control.** Workers hold no cloud credential: key decryption and blob +signing are brokered by the control plane, on a separate token from the one the +internet-facing services carry, and the presigner is restricted to three key +prefixes (`internal/api/handler/internal_dek.go`, `internal_blobs.go`, +`internal/api/middleware/internal_auth.go`). The admin panel cannot reveal a +secret: the configuration view redacts by name marker and returns a four-character +fingerprint instead of a value (`internal/app/instanceconfig/redact.go`). + +**Monitoring.** Every mutation that touches a secret is written to the audit log +with actor, action and target. As of this assessment the two endpoints that hand +out key material also log every access and every refusal, which is the clearest +probe signal the instance produces (`internal/api/handler/broker_access_log.go`). + +**No secrets in the repository.** A scan for AWS keys, Stripe live keys, private +key blocks and platform tokens across the tree and its history returns nothing. +The only committed `.env` files are examples with placeholders. diff --git a/compliance/casa/oauth.md b/compliance/casa/oauth.md new file mode 100644 index 000000000..7bc421b15 --- /dev/null +++ b/compliance/casa/oauth.md @@ -0,0 +1,134 @@ +# OAuth integrations + +For CASA test cases 3.2.1 (no deprecated flows) and 3.2.2 (`redirect_uri` and +`state` validation). + +## Summary + +Every integration uses the **authorization code flow**. The **implicit grant** +and the **resource owner password credentials grant** are not implemented +anywhere in this codebase, as a client or as a server. Warmbly's own +authorization server rejects any `grant_type` other than `authorization_code` +and `refresh_token`. + +## Warmbly as a client + +### The client under assessment: Gmail mailbox access + +This is the `warmbly-mailboxes` client. + +| Property | Value | +|---|---| +| Flow | Authorization code with PKCE (S256) | +| Authorization endpoint | `https://accounts.google.com/o/oauth2/auth` | +| `redirect_uri` | Fixed server-side: the API's public base plus `/addresses/google/callback`. Never read from the request | +| `state` | 128-bit from `crypto/rand`, stored in Redis with a 10-minute TTL, consumed with `GETDEL`, and bound to the user who started the flow | +| PKCE verifier | Generated at start, stored in the server-side state, never sent to the browser | +| Extra parameters | `access_type=offline`, `prompt=consent` | +| Token storage | AES-256-GCM under the instance credential key | +| Revocation | On mailbox deletion, the refresh token is posted to Google's revoke endpoint | + +**Scopes requested, and nothing else:** + +| Scope | Why | +|---|---| +| `https://www.googleapis.com/auth/gmail.modify` | Send campaign and warmup mail, read replies, move messages between folders | +| `https://www.googleapis.com/auth/gmail.settings.basic` | Read the send-as addresses Google has verified, and the signature already configured | + +Google's Gmail scopes nest, and `gmail.modify` already confers `gmail.readonly`, +`gmail.send`, `gmail.compose` and `gmail.metadata`, so naming those as well would +widen the consent screen and the declared restricted-scope set without granting +anything additional. Mailboxes connected under a broader consent continue to +work: the nesting is resolved in both directions by `scopeSatisfiedBy` +(`internal/app/email/onboarding.go`). + +`https://mail.google.com/` is **not** requested. It appears only in the +satisfaction table, as a scope that would confer the ones above if a user had +granted it previously. + +**Partial consent is refused.** A consent screen lets a person untick individual +permissions and still returns a token. `checkGrantedScopes` +(`internal/app/email/onboarding.go`) compares what was granted against what was +asked and refuses the connection, naming the missing permission, rather than +storing a mailbox that looks connected and fails days later. + +Evidence: `internal/config/inbox.go`, `internal/app/email/onboarding.go`, +`internal/app/email/oauth_params.go`, `internal/app/email/cache.go`. + +### Microsoft Graph mailbox access + +| Property | Value | +|---|---| +| Flow | Authorization code with PKCE (S256) | +| `redirect_uri` | Fixed server-side: API base plus `/addresses/outlook/callback` | +| `state` | As above: 128-bit, Redis, `GETDEL`, user-bound | +| Scopes | `Mail.Send`, `Mail.ReadWrite`, `User.Read`, `offline_access` | +| Extra parameters | `prompt=select_account`. Deliberately not `prompt=consent`, which causes Entra ID to re-run consent eligibility and refuse non-admin users | + +### Google Sign-In (authenticating a person into Warmbly) + +| Property | Value | +|---|---| +| Flow | Authorization code with PKCE (S256) and a nonce | +| `redirect_uri` | Fixed server-side, must be absolute, validated at boot | +| `state` | 256-bit from `crypto/rand`, Redis, 10-minute TTL, `GETDEL`, provider-bound | +| ID token | Verified against Google's JWKS: RS256 pinned, issuer allowlist, audience equal to the client id, expiry required, nonce compared | +| Tokens stored | None. Warmbly reads the identity and discards the tokens | + +After the callback, a single-use 60-second handoff code is exchanged over POST +with a binding secret the browser held throughout, which defends against login +CSRF (RFC 9700 4.7.1). + +Evidence: `internal/app/socialauth/socialauth.go`, `internal/app/auth/sso.go`, +`internal/pkg/idtoken/idtoken.go`. + +### Apple Sign-In + +Authorization code with `response_mode=form_post`, state and nonce. Apple does +not support PKCE on the web, so the nonce inside the ID token plus a single-use +state are the binding. The ID token is verified against Apple's JWKS with the +issuer and audience pinned. `redirect_uri` is fixed server-side and required to +be HTTPS at boot. + +### Enterprise OIDC (self-hosted) + +Discovery at boot with the issuer pinned to the configured value, RS256 +required, authorization code with PKCE and a nonce, and the same Redis state +machinery. Optional domain allowlist. + +Evidence: `internal/app/oidcauth/oidcauth.go`. + +### Third-party integrations + +HubSpot, Slack, Google Sheets, Pipedrive and Salesforce, each authorization code +with a fixed server-side redirect URI and a 192-bit state stored in Postgres, +consumed atomically by a conditional update, and bound to the user who started +it. Google Sheets and Salesforce use PKCE. Tokens are encrypted under the +per-organization data key. + +Evidence: `internal/app/integration/oauth.go`, `service.go`. + +**Callback origin.** The bouncer pages that hand an authorization code back to +the dashboard address `postMessage` to this instance's dashboard origin, and +deliver nothing rather than falling back to a wildcard when that origin is +unconfigured (`internal/api/handler/integration.go`, +`internal/api/handler/email_oauth_callback.go`). + +## Warmbly as an authorization server + +Warmbly implements OAuth 2.1 for third-party apps and MCP clients. + +| Property | Value | +|---|---| +| Grants | `authorization_code` and `refresh_token` only. Anything else returns `unsupported_grant_type` | +| PKCE | S256 only; `plain` is rejected. Mandatory for public clients, checked at authorize and again at token exchange | +| `redirect_uri` | Exact string match against the registered list, with no prefix matching. Re-checked at token exchange against the value the code was issued for | +| Registration | HTTPS, loopback HTTP, or a private-use scheme. `javascript:`, `data:`, `vbscript:`, `file:`, `blob:` and `about:` are rejected; opaque URIs are rejected; 12 maximum, 2048 characters each | +| Authorization code | 256-bit, stored SHA-256, 10-minute TTL, consumed by conditional update, bound to the client | +| Access token | 1 hour, hashed at rest | +| Refresh token | 90 days, hashed at rest, rotated on every use | +| Revocation | RFC 7009, and never confirms whether a token existed | +| Dynamic registration | RFC 7591, open but rate limited per IP, and a self-registered client can never request `SEND_CAMPAIGNS` or `API_KEYS` | + +Evidence: `internal/app/oauth/flow.go`, `service.go`, `dcr.go`, +`internal/api/handler/oauth.go`. diff --git a/compliance/casa/scope.md b/compliance/casa/scope.md new file mode 100644 index 000000000..f45ed77b9 --- /dev/null +++ b/compliance/casa/scope.md @@ -0,0 +1,95 @@ +# Assessment scope + +## The application + +Warmbly is an email warmup and cold outreach platform. A customer connects their +own mailboxes, and Warmbly sends, syncs and tracks mail through them. The Google +OAuth client under assessment, `warmbly-mailboxes`, is what connects a Gmail or +Google Workspace mailbox. + +## First-party components in scope + +Everything below is one system behind one authentication and authorization +model, so all of it is in scope. + +| Component | Path | Role | +|---|---|---| +| Backend API | `cmd/backend`, `internal/api`, `internal/app` | The control plane. Authentication, authorization, every customer-facing endpoint | +| Consumer | `cmd/consumer` | Processes bus events and updates platform state | +| Worker | `cmd/worker` | Sends and syncs mail. Holds no database credential and no cloud credential | +| Forms service | `cmd/forms`, `internal/formserver`, `forms/` | Public lead-capture form pages on their own origin | +| Tracking service | `tracking/` (Rust) | Open and click tracking, unsubscribe forwarding | +| Realtime service | `realtime/` (Elixir) | WebSocket fan-out to signed-in dashboards | +| Dashboard | `web/` | The customer-facing single-page app | +| Admin panel | `admin/` | The operator surface. Platform-admin bit plus MFA on every route | +| Marketing site | `site/` | Static. Also serves `install.sh` and `cli.sh` | + +## Hostnames + +The Qualys SSL Labs scans and the DNS review for test cases 4.1.1, 4.1.2 and +6.4.1 cover: + +| Hostname | Serves | +|---|---| +| `warmbly.com` | Marketing site, `install.sh`, `cli.sh` | +| `app.warmbly.com` | Dashboard | +| `api.warmbly.com` | Backend API, `/public` objects, OAuth callbacks | +| `admin.warmbly.com` | Admin panel | +| `docs.warmbly.com` | Documentation | +| `forms.warmbly.com` | Public form pages | +| The tracking host | Open and click tracking | +| The realtime host | WebSocket gateway | + +Customer-owned custom tracking and forms domains point at Warmbly by CNAME. +Certificates for those are issued on demand only after the instance has verified +the name, gated by `GET /tls/authorize` +(`internal/api/handler/tls_authorize.go`). + +## Third-party services in scope + +CASA puts a third-party API in scope when it performs authentication, or reads +or mutates user data. These qualify, and are covered under sections 1, 2 and 3 +only: + +| Service | What it does | Flow | +|---|---|---| +| Google Sign-In | Authenticates a person into Warmbly | Authorization code with PKCE and nonce | +| Apple Sign-In | Authenticates a person into Warmbly | Authorization code with state and nonce | +| Google (Gmail API) | Reads and sends a customer's mail | Authorization code with PKCE. The client under assessment | +| Microsoft Graph | Reads and sends a customer's mail | Authorization code with PKCE | +| Enterprise OIDC | Authenticates a person into a self-hosted instance | Discovery, authorization code with PKCE and nonce | + +Warmbly is also an OAuth 2.1 authorization server for third-party apps and MCP +clients (`internal/app/oauth`). That is first-party code and is assessed as part +of the backend. + +## Out of scope + +- **Stripe.** Billing only. Warmbly never sees a card number: Checkout and the + billing portal are hosted by Stripe, and no PAN, CVV or expiry field exists + anywhere in this repository. +- **PostHog and Sentry.** Product analytics and error reporting. Neither + authenticates anyone nor holds customer mail. +- **AWS KMS, S3, SES; Cloudflare; Railway.** Infrastructure the application runs + on. In scope for how Warmbly configures and uses them, which sections 4 and 6 + cover, not as separately assessed products. +- **Recipients' mail servers.** Warmbly authenticates to a customer's own + mailbox provider; it never connects to a recipient's MX. + +## What the Burp scan has to reach + +The DAST test cases require an authenticated scan. A scan that only sees the +signed-out surface proves nothing about them. The scan should be run against a +staging instance with a seeded workspace, authenticated as a workspace owner, +and should reach at least: + +- the full dashboard under `/app`, including campaigns, contacts, the unified + inbox, forms, automations and settings +- the REST API under `/v1` with a bearer token, including the list and detail + endpoints for every resource in `docs/content/docs/api/endpoints.mdx` +- the public form pages on the forms origin +- the unsubscribe and tracking endpoints on the tracking origin + +Authentication for the scan: sign in with a password, complete the emailed code, +and attach the resulting bearer token to scan requests. The token lives 12 hours, +which is long enough for a full crawl and audit. diff --git a/deploy/config/env.example b/deploy/config/env.example index dc5ffa2da..f43a21f92 100644 --- a/deploy/config/env.example +++ b/deploy/config/env.example @@ -311,6 +311,10 @@ REDIS_URL=redis://localhost:6379 # Realtime transport. false (default): Redis bridge, no cloud. Read identically by # backend, consumer, and realtime — never set true on one side only. PUBSUB_ENABLED=false +# Origins a browser connects FROM, comma separated. Not the websocket host: +# the Origin on an upgrade is the dashboard's. Empty leaves the check off. +CHECK_ORIGIN_HOSTS= +# Legacy host-based form, consulted only when CHECK_ORIGIN_HOSTS is empty. CHECK_ORIGIN=false # When PUBSUB_ENABLED=true (Google Pub/Sub): also set GCP_PROJECT_ID + # GOOGLE_APPLICATION_CREDENTIALS_JSON on every service. diff --git a/deploy/docker/backend.Dockerfile b/deploy/docker/backend.Dockerfile index 1534a48c8..45b8ae4b0 100644 --- a/deploy/docker/backend.Dockerfile +++ b/deploy/docker/backend.Dockerfile @@ -11,7 +11,7 @@ # (adds librdkafka + CGO; slower, and CGO cannot cross-compile — build each arch # on a native runner). Runtime selection is still by env # (EVENTBUS_PROVIDER / CODEC_PROVIDER). -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG GO_TAGS="" ARG TARGETOS TARGETARCH diff --git a/deploy/docker/cli.Dockerfile b/deploy/docker/cli.Dockerfile index 53193f3a5..19a826502 100644 --- a/deploy/docker/cli.Dockerfile +++ b/deploy/docker/cli.Dockerfile @@ -5,7 +5,7 @@ # # Distroless-style: the CLI is a static binary that talks to one HTTPS API, so # the runtime needs certificates, timezone data and nothing else. -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG TARGETOS ARG TARGETARCH diff --git a/deploy/docker/consumer.Dockerfile b/deploy/docker/consumer.Dockerfile index c45994f87..e01e4c40c 100644 --- a/deploy/docker/consumer.Dockerfile +++ b/deploy/docker/consumer.Dockerfile @@ -3,7 +3,7 @@ # CGO-free by default (NATS + JSON). Build with --build-arg GO_TAGS=kafka to # include the Kafka backend (adds librdkafka + CGO). See backend.Dockerfile. # Builder runs on $BUILDPLATFORM and cross-compiles to $TARGETARCH (no QEMU). -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG GO_TAGS="" ARG TARGETOS TARGETARCH diff --git a/deploy/docker/forms.Dockerfile b/deploy/docker/forms.Dockerfile index 7fb5b7b2d..bd41cbcf9 100644 --- a/deploy/docker/forms.Dockerfile +++ b/deploy/docker/forms.Dockerfile @@ -30,7 +30,7 @@ RUN --mount=type=secret,id=posthog_cli_api_key,required=false \ pnpm sourcemaps:posthog; \ fi -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG TARGETOS TARGETARCH # Build identity shown in the admin panel; see internal/version. diff --git a/deploy/docker/go-dev.Dockerfile b/deploy/docker/go-dev.Dockerfile index 1161118f8..ef6a9b3a6 100644 --- a/deploy/docker/go-dev.Dockerfile +++ b/deploy/docker/go-dev.Dockerfile @@ -14,7 +14,7 @@ # /tmp/main in place, then restarts it. No docker layer pipeline, no # image rebuild — just `go build` against a warm cache. -FROM golang:1.25-alpine +FROM golang:1.26-alpine RUN apk add --no-cache git ca-certificates gcc musl-dev librdkafka-dev curl diff --git a/deploy/docker/updater.Dockerfile b/deploy/docker/updater.Dockerfile index 66278d978..4557ba8e0 100644 --- a/deploy/docker/updater.Dockerfile +++ b/deploy/docker/updater.Dockerfile @@ -5,7 +5,7 @@ # containers. It needs git and the docker CLI with the compose plugin, and the # docker socket mounted at runtime (see the updater service in # docker-compose.yml). Builder runs on $BUILDPLATFORM and cross-compiles. -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG TARGETOS TARGETARCH ARG VERSION="" COMMIT="" BUILT_AT="" diff --git a/deploy/docker/worker.Dockerfile b/deploy/docker/worker.Dockerfile index bf969c7e8..3a7bcb26e 100644 --- a/deploy/docker/worker.Dockerfile +++ b/deploy/docker/worker.Dockerfile @@ -3,7 +3,7 @@ # CGO-free by default (NATS + JSON). Build with --build-arg GO_TAGS=kafka to # include the Kafka backend (adds librdkafka + CGO). See backend.Dockerfile. # Builder runs on $BUILDPLATFORM and cross-compiles to $TARGETARCH (no QEMU). -FROM --platform=$BUILDPLATFORM golang:1.25-alpine AS builder +FROM --platform=$BUILDPLATFORM golang:1.26-alpine AS builder ARG GO_TAGS="" ARG TARGETOS TARGETARCH diff --git a/deploy/nginx/warmbly.conf b/deploy/nginx/warmbly.conf index f3ec3ec4b..ab5d4e5f5 100644 --- a/deploy/nginx/warmbly.conf +++ b/deploy/nginx/warmbly.conf @@ -21,11 +21,47 @@ server { root /opt/warmbly/web; index index.html; - location / { try_files $uri $uri/ /index.html; } + location / { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + try_files $uri $uri/ /index.html; + } # Never cache the shell or the runtime config; hashed assets are immutable. - location = /index.html { add_header Cache-Control "no-store"; } - location = /config.js { add_header Cache-Control "no-store"; } - location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; } + location = /index.html { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "no-store" always; + } + location = /config.js { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "no-store" always; + } + location /assets/ { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "public, max-age=31536000, immutable" always; + } } # Admin panel (admin/dist) @@ -37,10 +73,47 @@ server { root /opt/warmbly/admin; index index.html; - location / { try_files $uri $uri/ /index.html; } - location = /index.html { add_header Cache-Control "no-store"; } - location = /config.js { add_header Cache-Control "no-store"; } - location /assets/ { add_header Cache-Control "public, max-age=31536000, immutable"; } + location / { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + try_files $uri $uri/ /index.html; + } + # Never cache the shell or the runtime config; hashed assets are immutable. + location = /index.html { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "no-store" always; + } + location = /config.js { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "no-store" always; + } + location /assets/ { + # Security response headers. Repeated per location because nginx drops + # inherited add_header directives in any block that declares its own. + add_header X-Content-Type-Options "nosniff" always; + add_header X-Frame-Options "DENY" always; + add_header Referrer-Policy "strict-origin-when-cross-origin" always; + add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header Cache-Control "public, max-age=31536000, immutable" always; + } } # Backend API (:8080). Set TRUSTED_PROXIES=127.0.0.1/32 in warmbly.env so the diff --git a/docker-compose.yml b/docker-compose.yml index c5ecb5af9..f8550c236 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -590,8 +590,14 @@ services: JWT_SECRET: ${AUTH_SECRET:-local-dev-auth-secret-minimum-32-characters-long} SECRET_KEY_BASE: ${SECRET_KEY_BASE:-local-development-secret-key-base-minimum-64-characters-for-phoenix} PUBSUB_ENABLED: ${PUBSUB_ENABLED:-false} - # Behind a reverse proxy set CHECK_ORIGIN=true once PHX_HOST matches the - # public websocket hostname. + # The origins a browser connects FROM, comma separated, e.g. + # "https://app.example.com,https://admin.example.com". Not this service's + # own host: the browser's Origin on a websocket upgrade is the dashboard's. + # Empty leaves the check off, which is right for a LAN install where the + # origin is whatever host was typed; the socket still requires a + # short-lived ticket either way. + CHECK_ORIGIN_HOSTS: ${CHECK_ORIGIN_HOSTS:-} + # Legacy host-based form, consulted only when CHECK_ORIGIN_HOSTS is empty. CHECK_ORIGIN: ${CHECK_ORIGIN:-false} # The environment label events are tagged with, matching every other # service in this file. diff --git a/docs/content/docs/api/endpoints.mdx b/docs/content/docs/api/endpoints.mdx index 2a2ed29c5..faa541b00 100644 --- a/docs/content/docs/api/endpoints.mdx +++ b/docs/content/docs/api/endpoints.mdx @@ -290,7 +290,7 @@ Changing Advisor settings (`PATCH /advisor/settings`) is JWT only, alongside the | Method | Path | API Permission | |--------|------|----------------| | GET | `/api-keys` | `API_KEYS` | -| POST | `/api-keys` | `API_KEYS` | +| POST | `/api-keys` | `API_KEYS`, JWT only | | GET | `/api-keys/permissions` | `API_KEYS` | | GET | `/api-keys/:id` | `API_KEYS` | | PATCH | `/api-keys/:id` | `API_KEYS` | @@ -300,6 +300,8 @@ Changing Advisor settings (`PATCH /advisor/settings`) is JWT only, alongside the `DELETE /api-keys/:id/permanent` deletes a key that has already been revoked or has expired, taking its usage logs with it. A key that could still authenticate gets a `409`, because revoking is what records that a credential was ended and why. See [Ending a key](/api/authentication/). +`POST /api-keys` requires a recent confirmation (`POST /auth/reauth`) when called from a signed-in session, because a key outlives the session that made it and a stolen browser token should not be able to leave one behind. An API key or OAuth token calling it is unaffected: it has no session and no second factor to present, it was itself minted from a confirmed session, and the `API_KEYS` scope is the explicit grant that governs it. Automation and the CLI keep working. + `DELETE /api-keys/self` revokes the key the request was made with, and is the one route here that needs no scope. A credential must always be able to end itself: requiring `API_KEYS` to sign out would leave a read-only key on a laptop someone is handing back live, which is what [`warmbly auth logout`](/api/cli/) promises to prevent. A JWT caller gets a `400`: there is no key in that request to end, only a session, which `POST /auth/logout` ends. ### OAuth apps @@ -388,11 +390,28 @@ Folders (on campaigns), tags (on mailboxes) and categories (on contacts and inbo These never accept an API key. They depend on a human-bound session: billing flows, governance, OAuth onboarding, websocket bootstrap, and operational destruction. - `POST /auth/login`, `/auth/login/confirm`, `/auth/register`, `/auth/register/confirm`, `/auth/refresh`, `/auth/reset-password`, `/auth/reset-password/confirm` +- `POST /auth/reauth` (re-prove the account holder behind a live session, for the changes that require a recent confirmation) - `GET /auth/config` (public deployment capabilities: which sign-in methods this backend has enabled, whether a login code step follows, whether signups are open, whether the instance still needs claiming) - `GET /auth/instance` (JWT only: the running Warmbly version of a self-hosted instance and whether a newer release exists, for the dashboard's version pill; a hosted deployment answers `self_hosted: false` and nothing else) `POST /auth/register` accepts an optional `invite` field carrying an invitation token. On a deployment running `DISABLE_REGISTRATION=invite_only` it is what permits the signup, and the account is created inside the inviting organization rather than in a new one. The token must resolve to a live invitation whose email equals the submitted address, otherwise the request is refused with `invitation_invalid`. Omitting it on a closed deployment returns `registration_invite_only` or `registration_closed`. See [error codes](/api/error-codes/#registration-and-invitation-refusals). +### Actions that need a recent confirmation + +Four changes require the session to have confirmed the account holder within the last five minutes, over and above the permission they already need: + +| Action | Route | +|--------|-------| +| Create an API key | `POST /api-keys` | +| Add a passkey | `POST /auth/passkey/register/begin`, `/finish` | +| Remove a passkey | `DELETE /auth/passkey/credentials/:id` | +| Transfer a workspace | `POST /organizations/transfer-ownership` | +| Schedule a workspace or account for deletion | `POST /organizations/current/danger-zone/delete`, `POST /me/danger-zone/delete` | + +Each either hands out a credential that outlives the session that created it, or cannot be reversed by the person it was done to. Without a confirmation they answer `403` with code `reauth_required`; confirm with `POST /auth/reauth` (password or a current two-factor code) and retry. See [error codes](/api/error-codes/#confirmation-required). + +This applies to session callers. An API key or OAuth token has no session to confirm and is not the threat here, so it passes straight through to the route's permission gate. + `GET /auth/config` gained two fields: `invites_required` (boolean, true when an invitation token is needed to create an account) and `docs_url` (string, the deployment's link to the accounts and access documentation, for a client to surface next to a refusal). `GET /auth/config` also carries `websocket_url` and `app_url` (both strings, each omitted when the instance has none). They are the realtime gateway a developer client connects to and the dashboard origin a client sends someone to. Both are served here because on a self-hosted instance the host layout is whatever the operator chose, and there is no other way to discover it: the [CLI](/api/cli/) reads them for `warmbly events tail` and `warmbly browse`. diff --git a/docs/content/docs/api/error-codes.mdx b/docs/content/docs/api/error-codes.mdx index 7f23c5b31..54cc390b6 100644 --- a/docs/content/docs/api/error-codes.mdx +++ b/docs/content/docs/api/error-codes.mdx @@ -20,8 +20,6 @@ All errors follow this structure: `error` and `message` are for people. Client logic should use `code`, HTTP status, and endpoint-specific fields such as `retry_after`. Include `request_id` when contacting support. -A `4xx` message names the specific thing to fix, so it is worth showing to whoever made the request. A `5xx` message is deliberately generic: a server-side fault has no fix the caller can apply, and the detail behind it stays in the server's own log, where it is recorded against the same `request_id` this response carries. Quote that id and an operator can read the exact failure. The exceptions are the coded conditions listed below (`mailbox_provider_not_configured` and friends), which are `5xx` responses a reader genuinely can act on and which say so in full. - ## HTTP status codes ### Client errors (4xx) @@ -95,6 +93,23 @@ Returned when the request cannot be processed due to invalid syntax. | `invalid_setting` | `PATCH /outreach/settings` (or a campaign's advanced settings) carried a value outside the documented vocabulary, for example a `reply_intent.crm_task_intents` entry that is not a reply intent | | `no_organization` | The request needs a workspace and the caller has none selected. Every entitlement, limit and suppression rule is scoped to a workspace, so a write that would run unscoped is refused rather than run without those checks. API keys always carry their workspace; a dashboard session picks one at sign-in, so this normally means the session predates the workspace being chosen. Select a workspace and retry | +#### Password refusals + +| `code` | Status | Meaning | +|--------|--------|---------| +| `password_breached` | 400 | The password appears in a public list of breached passwords and was refused. Choose one that does not | + +A password must be 8 to 128 characters. There is no composition rule, but it is checked against the 100,000 most commonly breached passwords published by the UK National Cyber Security Centre, case-insensitively. + +```json +{ + "error": "Bad Request", + "message": "This password appears in a public list of breached passwords. Choose one that does not.", + "code": "password_breached", + "request_id": "4bbbd1b2-8f86-47dd-8a7f-9476501ad20e" +} +``` + ### 401 Unauthorized Returned when authentication fails. @@ -208,6 +223,38 @@ Signup and invitation refusals carry their own `code`, so a client can branch on **How to fix:** on a self-hosted deployment these are configuration, not faults. See [accounts and access](/development/accounts-and-access/#registration-modes). +#### Confirmation required + +| `code` | Status | Meaning | +|--------|--------|---------| +| `reauth_required` | 403 | The action needs a proof of identity newer than the session. Confirm with `POST /v1/auth/reauth`, then retry | +| `reauth_no_factor` | 400 | The account has neither a password nor two-factor authentication, so there is nothing to confirm with. Enrol one first | +| `admin_mfa_required` | 403 | An admin route was reached by a session that did not present a second factor. Turn on 2FA or add a passkey, then sign in again | + +`reauth_required` guards the changes that hand out a durable credential or cannot be undone: creating an API key, adding or removing a passkey, transferring a workspace, and scheduling a workspace or account for deletion. Confirm with a password or a current two-factor code: + +```bash +curl -X POST "https://api.warmbly.com/v1/auth/reauth" \ + -H "Authorization: Bearer $ACCESS_TOKEN" \ + -H "Content-Type: application/json" \ + -d '{"password": "..."}' +``` + +```json +{ "valid_for_seconds": 300 } +``` + +The confirmation is recorded on the session and lasts for the window returned, so a run of related changes only asks once. API keys and OAuth tokens have no session to confirm, so these routes are reachable only with a signed-in session; that is deliberate for key creation, which otherwise lets one leaked key mint more. + +```json +{ + "error": "Forbidden", + "message": "Confirm it is you before making this change.", + "code": "reauth_required", + "request_id": "4bbbd1b2-8f86-47dd-8a7f-9476501ad20e" +} +``` + ### 404 Not Found Returned when the requested resource doesn't exist. @@ -293,7 +340,7 @@ Returned when an unexpected error occurs on the server. ```json { "error": "Internal Server Error", - "message": "Something went wrong on our end. Try again in a moment. If it keeps happening, contact support with the request id.", + "message": "Something went wrong.", "code": "internal_error", "request_id": "4bbbd1b2-8f86-47dd-8a7f-9476501ad20e" } @@ -301,9 +348,11 @@ Returned when an unexpected error occurs on the server. **How to fix:** - Retry the request after a short delay -- If persistent, contact support and quote `request_id`. It is the only thing that identifies this exact failure in the server's logs, where the underlying cause is recorded +- If persistent, contact support with request details -One `internal_error` variant is worth distinguishing. When an authentication endpoint cannot send its email, the message names that specifically rather than reporting a generic fault: +A 500 always carries this same message. The underlying detail is not returned, because it is usually database or provider output naming tables, columns and hosts, none of which helps a caller. It is logged against the `request_id` in the response, so quoting that id in a support request is what connects the two. + +One `internal_error` variant is worth distinguishing. When an authentication endpoint cannot send its email, the message names that specifically rather than reporting a generic fault, because on a self-hosted instance the person reading it is often the one who can fix it: ```json { @@ -325,7 +374,7 @@ Returned when the service is temporarily unavailable. ```json { "error": "Service Unavailable", - "message": "This part of Warmbly is temporarily unavailable. Nothing was changed. Try again in a moment.", + "message": "service unavailable", "code": "service_unavailable", "request_id": "4bbbd1b2-8f86-47dd-8a7f-9476501ad20e" } @@ -489,56 +538,6 @@ A `503` whose `code` is `mailbox_identity_unavailable` comes from `POST /emails/ - Retry. Placement happens within moments, so a second attempt usually succeeds - `GET /emails/{id}` reports the mailbox's `status`; an `inactive` mailbox is not placed on a worker at all and will keep refusing until it is reactivated -#### `mailbox_validation_timeout` - -A `400` whose `code` is `mailbox_validation_timeout` comes from the SMTP and IMAP connect and credential-update paths. The credentials were sent to a worker and tried against the servers named, and no answer came back inside the check's deadline. It is not a refused password: the usual causes are a wrong host or port, a firewall between the worker and the server, or a mail server that is simply slow. - -```json -{ - "error": "Bad Request", - "message": "The mail server didn't answer in time, so the credentials could not be checked. Confirm the host, port and security settings, then try again.", - "code": "mailbox_validation_timeout", - "request_id": "0b7c6a5e-2f83-4e1a-9de4-1c72b8f9a340" -} -``` - -**How to fix:** -- Confirm the SMTP and IMAP host, port and security setting against the provider's own documentation -- Retry. A slow server often answers on the second attempt - -#### `mailbox_validation_unavailable` - -A `503` whose `code` is `mailbox_validation_unavailable` means the check itself could not be run: the machine that tries credentials could not be reached, or the channel its answer comes back on was unavailable. Nothing is known about the credentials either way, and nothing was saved. - -```json -{ - "error": "Service Unavailable", - "message": "Warmbly couldn't check these credentials right now, so nothing was saved. Try again in a moment.", - "code": "mailbox_validation_unavailable", - "request_id": "9a1d3f27-64bb-4c0e-8a61-2f5b7c0e9d14" -} -``` - -**How to fix:** -- Retry. Nothing about the mailbox was changed, so the request is safe to repeat - -#### `passkey_unavailable` - -A `503` whose `code` is `passkey_unavailable` comes from the passkey registration and sign-in endpoints. A ceremony holds its challenge outside the browser for the few minutes between starting and finishing, and that store could not be written or read. The passkey and the account are both fine. - -```json -{ - "error": "Service Unavailable", - "message": "Passkey sign-in isn't available right now. Try again in a moment, or sign in with your password.", - "code": "passkey_unavailable", - "request_id": "3c8e0b14-7a52-4d9f-b0c3-6e1d29fa7b58" -} -``` - -**How to fix:** -- Retry the ceremony from the start -- Sign in with a password meanwhile. Do not register a replacement passkey; the existing one is not the problem - ## Error handling best practices ### Implement retry logic diff --git a/docs/content/docs/api/reference/mailboxes.mdx b/docs/content/docs/api/reference/mailboxes.mdx index ccce97c42..d1c4bbb3c 100644 --- a/docs/content/docs/api/reference/mailboxes.mdx +++ b/docs/content/docs/api/reference/mailboxes.mdx @@ -642,7 +642,7 @@ Auth: **Scope** `WRITE_EMAILS` · **Org permission** `manage_emails` `DELETE /emails/:id` -Disconnects and deletes a mailbox. It is removed from all warmup pools and an account-disconnected event fans out. The mailbox is looked up in the caller's workspace, so any member with `manage_emails` (or a key with `WRITE_EMAILS`) can delete any mailbox the workspace holds, not only the member who connected it; a mailbox in another workspace answers `404`. +Disconnects and deletes a mailbox. It is removed from all warmup pools and an account-disconnected event fans out. Nothing is removed unless the two steps that cannot be repaired afterwards succeed first: the machine syncing the mailbox is told to drop it, and the mailbox's [Warmbly Cloud](/guides/warmbly-cloud/) link is released, which takes an enrolled mailbox's stored credentials out of the pool and returns a cloud-managed mirror to the cloud workspace. A failure at either point puts the mailbox back as it was and is safe to retry. If the record itself then fails to delete, the mailbox remains but its link is already released, so its warmup moves back to this instance until the delete is retried. diff --git a/docs/content/docs/development/admin-panel.mdx b/docs/content/docs/development/admin-panel.mdx index dc794303b..df409e18e 100644 --- a/docs/content/docs/development/admin-panel.mdx +++ b/docs/content/docs/development/admin-panel.mdx @@ -9,6 +9,14 @@ The admin panel is the operator's view of an instance: every worker, user, organ The panel runs on `:5174` in the default stack (`http://localhost:5174` on a stock install, or the host you proxied to it). Sign in with the same account as the dashboard. The first owner holds every admin bit from the moment they claim the instance, and `warmblyctl user create --admin` creates a further account that already holds them. A page the account has no bit for says which bit it needs instead of rendering. + +Every admin route refuses a session that did not present a second factor. Turn on 2FA or add a passkey under **Settings > Security** in the dashboard, then sign in again; the panel says so rather than failing silently. + +The check is on the session, not on enrolment, so switching 2FA on does not upgrade the session you are already holding. Sign out and back in. + +This is deliberate and not configurable. An administrative interface reachable from the internet is the one account where a stolen password should not be enough, and it is what the App Defense Alliance CASA assessment requires of any such interface. + + The old paths still redirect, so a bookmark or a link in an older version of these docs lands on the right tab. ## Command palette diff --git a/docs/content/docs/development/configuration.mdx b/docs/content/docs/development/configuration.mdx index 8bb574a6c..2c3f43cbf 100644 --- a/docs/content/docs/development/configuration.mdx +++ b/docs/content/docs/development/configuration.mdx @@ -55,7 +55,7 @@ Five values protect the whole instance. Compose ships a working default for each | Variable | Format | What it protects | Restart needed | |---|---|---|---| -| `AUTH_SECRET` | 32 characters or more | JWT and session signing. The realtime service reads the same value as `JWT_SECRET` | yes | +| `AUTH_SECRET` | 32 characters or more, enforced at boot | JWT and session signing. The realtime service reads the same value as `JWT_SECRET` and applies the same floor. Both refuse to start below it: a shorter HS256 key can be recovered offline from any token the service has issued | yes | | `INTERNAL_API_TOKEN` | any random string | The backend's `/api/v1/internal/` routes, which workers and the tracking service authenticate against | yes | | `NODE_BROKER_TOKEN` | any random string | The routes that perform a privileged operation for the caller: opening a sealed data key, signing a blob operation, and minting a provider access token for a mailbox Warmbly Cloud manages. Optional, and falls back to `INTERNAL_API_TOKEN`. The same value has to be set on the control plane and on every node that calls those routes, or they answer 401. Worth setting in a split deployment, where the tracking and forms services are internet-facing and hold the shared token | yes | | `SECRET_KEY_BASE` | 64 characters or more | Phoenix session signing in the realtime service | yes | @@ -143,6 +143,7 @@ TRUSTED_PROXIES=10.0.0.0/8,172.16.0.0/12 | `SSO_AUTO_PROVISION` | `true` lets a verified identity provider assertion create an account regardless of `DISABLE_REGISTRATION` | `false` | yes | | `AUTH_IP_RATE_LIMIT` | Unauthenticated auth requests allowed per source IP per 15 minutes | `60` | yes | | `CLI_AUTH_IP_RATE_LIMIT` | CLI sign-in handshake requests allowed per source IP per 15 minutes. Its own budget, because one `warmbly auth login` polls around 200 times and must not exhaust the allowance above | `500` | yes | +| `PUBLIC_IP_RATE_LIMIT` | Requests allowed per source IP per 15 minutes on the remaining public routes: unsubscribe, invitation preview, fleet enrolment and the analytics proxy. Each carries its authorization in a high-entropy token, so this bounds unmetered writes and relayed bandwidth rather than guessing. Counts reads as well as writes, unlike the auth limiter | `600` | yes | | `WARMBLY_BOOTSTRAP_EMAIL` | First owner's address, read only while the users table is empty | unset | yes | | `WARMBLY_BOOTSTRAP_PASSWORD_HASH` | Argon2 PHC string for that owner. Preferred over the plaintext form | unset | yes | | `WARMBLY_BOOTSTRAP_PASSWORD` | Plaintext convenience form. Warns at boot, and leaves a password in your process environment | unset | yes | @@ -681,7 +682,8 @@ The Elixir websocket service. Its runtime configuration is read only when the re | `REDIS_URL` | The Redis bridge the backend publishes events onto | `redis://localhost:6379/0` | | `PHX_HOST` | The service's own hostname | `localhost` | | `PORT` | Listen port | `4000` | -| `CHECK_ORIGIN` | `true` accepts a websocket upgrade only from `PHX_HOST` | `false` | +| `CHECK_ORIGIN_HOSTS` | Origins a browser may open a socket from, comma separated, e.g. `https://app.example.com,https://admin.example.com`. Not this service's own host | unset | +| `CHECK_ORIGIN` | Legacy host-based form, consulted only when `CHECK_ORIGIN_HOSTS` is empty. `true` accepts an upgrade only from `PHX_HOST` | `false` | | `PUBSUB_ENABLED` | `true` swaps the Redis bridge for Google Pub/Sub | `false` | | `GCP_PROJECT_ID` | Required when `PUBSUB_ENABLED=true`; the service refuses to boot without it | unset | | `MAX_CONNECTIONS_PER_USER` | Concurrent sockets one account may hold. The caller's plan limit applies too, whichever is lower | `10` | @@ -695,8 +697,10 @@ The Elixir websocket service. Its runtime configuration is read only when the re | `SENTRY_DSN` | The same through Sentry. An empty string is treated as unset on purpose, because the library rejects `""` hard enough to take the node down | unset | | `WARMBLY_RELEASE` | The build reported errors are tagged with | `dev` | - -The shipped default accepts a websocket upgrade from **any** origin. A token is still required to join a channel, so an attacker needs a valid JWT either way, but on a deployment reachable from the internet set `PHX_HOST` to the public websocket hostname and `CHECK_ORIGIN=true` so only your own dashboard can open a socket. + +With neither variable set, a websocket upgrade is accepted from any origin. A short-lived ticket is still required to open the socket, and channel membership is checked on every join, so an attacker needs a real credential either way. On a deployment reachable from the internet, set `CHECK_ORIGIN_HOSTS` to your dashboard and admin origins. + +List the origins the **browser connects from**, not the websocket host. The `Origin` header on an upgrade names the page that opened the socket, which is the dashboard. Setting `CHECK_ORIGIN=true` and pointing `PHX_HOST` at the websocket hostname refuses every real connection, which is the trap this variable replaces. The installer sets `CHECK_ORIGIN_HOSTS` correctly for you. ## Settings stored in the database diff --git a/docs/content/docs/development/updates.mdx b/docs/content/docs/development/updates.mdx index 2e4519e1e..65076cef5 100644 --- a/docs/content/docs/development/updates.mdx +++ b/docs/content/docs/development/updates.mdx @@ -51,6 +51,31 @@ A build that carries no version (an image built without the build arguments, rep The version comes from the binary itself: the Dockerfiles and `make up` stamp the tag, commit and build time in (`internal/version`), CI does the same for published images, and `warmblyctl status` prints it as the first line. +## Before updating past this release + +Two boot-time requirements were added, and an instance that does not meet them +will restart-loop after the pull rather than starting with a warning. Both are +worth checking before you press the button. + +- **`AUTH_SECRET` must be at least 32 characters.** It signs every session + token, and a shorter key can be recovered offline from any token the instance + has issued. The realtime service applies the same floor to the same value + (`JWT_SECRET`). Generate one with `make gen-key`, or any 32-plus-character + random string, and set it in the install's `.env`. **Changing it signs + everybody out**, which is the intended effect and is a good moment to do it. +- **Administrators need two-factor authentication.** Every admin route now + refuses a session that did not present a second factor. Enrol at least one + administrator under **Settings > Security** in the dashboard *before* + updating, or the admin panel is unreachable until someone does. The dashboard + itself is unaffected, so enrolling afterwards still works; it is just a worse + moment to discover it. + +Check the first one with: + +```bash +awk -F= '/^AUTH_SECRET=/{print length($2)" characters"}' /opt/warmbly/.env +``` + ## Update and restart The button appears when the updater is reachable and something newer exists. It needs the `manage_settings` admin permission, and every press is an audit row (`upgrade` on `instance`). diff --git a/docs/content/docs/guides/forms.mdx b/docs/content/docs/guides/forms.mdx index b8fcc4a0b..e8069d5af 100644 --- a/docs/content/docs/guides/forms.mdx +++ b/docs/content/docs/guides/forms.mdx @@ -144,6 +144,8 @@ Two more controls are yours: - **Captcha challenge** adds a Cloudflare Turnstile check to the form. The toggle appears once the operator has configured Turnstile for the instance. - **Allowed embed domains** limits which sites may embed the form. With domains listed, browsers refuse to frame the page anywhere else (a domain covers its subdomains); empty allows any site. The hosted link keeps working either way. + Worth listing your domains even if you only embed on one site. A form left open to any origin can be framed invisibly under someone else's page and used to collect leads that look like yours, and the browser is the only thing that can prevent it. + ## Data and portability Forms, their design, their logo and cover images, their submissions, personalized link tickets and funnel events all belong to the **Contacts** data group of a [workspace archive](/guides/workspace-export-import/). The public form id travels with them, so embed codes installed on your website keep working after a move to another instance (point your embeds at the new host), and link tickets travel verbatim, so personalized links already sitting in sent emails keep identifying their contacts. A form's campaign link is dropped on import when campaigns stay behind. diff --git a/docs/content/docs/guides/mailboxes.mdx b/docs/content/docs/guides/mailboxes.mdx index 2cbe69e01..be2f0f0e0 100644 --- a/docs/content/docs/guides/mailboxes.mdx +++ b/docs/content/docs/guides/mailboxes.mdx @@ -21,6 +21,23 @@ Open **Accounts** and choose **Add account**. **OAuth** sends you to your provider's consent screen and returns a token instead of a password. Both OAuth providers use the provider's native API, never IMAP or SMTP, so consent asks to send mail and to read and organize your mailbox. Google additionally asks to read your mail settings, which is what lets Warmbly offer the addresses Google has verified you to send as and import the signature you already wrote there. It needs no app passwords or server settings. Note that Google revokes Gmail tokens when the account's password changes, so a password change there means [re-authorizing the mailbox](#reconnecting-an-account) once. +#### What each provider is asked for + +Exactly these, and nothing beyond them: + +| Provider | Scope | What it is for | +|----------|-------|----------------| +| Google | `https://www.googleapis.com/auth/gmail.modify` | Send campaign and warmup mail, read replies, and move messages between folders | +| Google | `https://www.googleapis.com/auth/gmail.settings.basic` | Read the send-as addresses Google has verified for the account, and the signature already set there | +| Microsoft | `https://graph.microsoft.com/Mail.Send` | Send mail | +| Microsoft | `https://graph.microsoft.com/Mail.ReadWrite` | Read replies and move messages | +| Microsoft | `https://graph.microsoft.com/User.Read` | Read the signed-in address, so the mailbox is filed under the right one | +| Microsoft | `offline_access` | Keep the connection alive without asking again | + +Google's scopes nest, so `gmail.modify` already covers reading, sending, composing and metadata. Warmbly used to ask for those four by name as well, which widened the consent screen without granting anything extra; it no longer does. A mailbox connected under the older, broader consent keeps working and does not need reconnecting. + +A consent screen lets you untick individual permissions. Warmbly checks what was actually granted and refuses a half-granted mailbox at connect time, naming the missing permission, rather than storing one that looks connected and fails on its first send days later. + **IMAP / SMTP** needs host, port, username, and password for each direction: ```text @@ -289,7 +306,7 @@ Leads mid-sequence on that mailbox move to another one in their campaign as they It keeps its worker assignment while off, so switching it back on puts it back on the same machine, sending from the same IP, and it resumes syncing from where it stopped instead of re-importing. -**Disconnecting** removes the mailbox for good. It is on the mailbox's own **More** menu in the list, as **Disconnect mailbox**, and at the bottom of its **Settings** tab under Danger zone. To remove several at once, tick their rows and use the selection bar. Any member with the manage mailboxes permission can disconnect any mailbox in the workspace, not only the member who connected it. The machine syncing it is told to drop it before the record is removed, because afterwards there is nothing left to tell. If that instruction cannot be delivered, the disconnect fails with a `503` and nothing is removed, so retry it in a moment rather than assuming it worked. When a disconnect is refused, the notice in the dashboard carries the reason the API gave, so a mailbox that could not be released from Warmbly Cloud or a machine that could not be reached reads as that rather than as a generic failure. +**Disconnecting** removes the mailbox for good. It is on the mailbox's own **More** menu in the list, as **Disconnect mailbox**, and at the bottom of its **Settings** tab under Danger zone. To remove several at once, tick their rows and use the selection bar. The machine syncing it is told to drop it before the record is removed, because afterwards there is nothing left to tell. If that instruction cannot be delivered, the disconnect fails with a `503` and nothing is removed, so retry it in a moment rather than assuming it worked. Everything belonging to that mailbox goes with it: its imported mail in the unibox, its warmup history and pool membership, its credentials, its sender links, and any send still scheduled for it. A campaign that was using it keeps running on its remaining senders, and the leads it had been writing to move onto them at their next step. Export the workspace first if you want a copy. Disable the mailbox instead when you only want it to stop. diff --git a/docs/content/docs/guides/security.mdx b/docs/content/docs/guides/security.mdx index 384ef2577..a9642151a 100644 --- a/docs/content/docs/guides/security.mdx +++ b/docs/content/docs/guides/security.mdx @@ -33,6 +33,8 @@ They are displayed a single time during setup, each works once, and they are you At sign-in, the code submits automatically once six digits are in. Without your authenticator, choose **Use a recovery code**. +Each code works once. An authenticator code stays valid for about a minute so a slow connection still works, but once it has signed you in, that same code is spent and cannot be used again. + Disabling asks for a current code or a recovery code first. With 2FA off you are protected only by your password plus the emailed code, and setting it up again issues a fresh secret and new recovery codes, invalidating the old ones. ## Passkeys @@ -47,6 +49,21 @@ Each entry shows when it was added and last used, and can be renamed or removed. Unsynced passkeys live only on the device that created them. On a device without one, Warmbly says none was found and you sign in with your password, then add a passkey there. +## Confirming sensitive changes + +Some changes ask you to confirm it is you even though you are already signed in: + +- creating an API key +- adding or removing a passkey +- transferring a workspace to someone else +- scheduling a workspace or account for deletion + +Enter your password or a code from your authenticator, whichever your account has. The confirmation lasts five minutes, so a run of related changes only asks once. + +If you signed up with Google, Apple or your company's single sign-on, your account may have neither a password nor 2FA yet. There is nothing to confirm with in that case, so turn on 2FA first; the prompt says so rather than refusing a password you never set. + +This exists because the things on that list either hand out a credential that outlives the session that made it, or cannot be undone from your side. Someone who got hold of a signed-in browser should not be able to do any of them without knowing something you know. + ## Sessions Every signed-in device appears under **Sessions** with its device (`Chrome on macOS`), location where known, sign-in method (Email, Google, Apple, or Passkey), and last activity. Your current device is tagged **This device**. @@ -57,9 +74,17 @@ Every signed-in device appears under **Sessions** with its device (`Chrome on ma Sign out the session, change your password, and make sure 2FA is on. Signing out other sessions is the fastest way to cut off access. +## Choosing a password + +A password has to be between 8 and 128 characters, and it is checked against a list of the 100,000 most commonly breached passwords published by the UK National Cyber Security Centre. If yours appears there, it is refused and you are told why. The check is case-insensitive, so capitalising the first letter of a known password does not get past it. + +There is no rule about mixing upper case, digits and symbols. A long passphrase you can remember beats a short one with a symbol bolted on, which is what current guidance from NIST and the NCSC both say. The dashboard shows a strength meter as you type. + +Repeated wrong passwords are counted per account, not just per device, so guessing one account from many addresses does not buy an attacker more attempts. After ten failures the account stops accepting password attempts for an hour. Signing in correctly clears the count. + ## Password and alerts -Change your password under **Password**: current password, then a new one of at least 12 characters with upper and lower case and a number. **Changing it signs out every other device automatically**, while the device you change it on stays in. Accounts that only use Google, Apple, or a passkey have no password to change. +Change your password under **Password**: current password, then a new one. **Changing it signs out every other device automatically**, while the device you change it on stays in. Accounts that only use Google, Apple, or a passkey have no password to change. **Sign-in alerts** notify you when your account is accessed from a new browser and OS combination, naming the device and location with a reminder to act if it was not you. They appear in your in-app feed by default; enable email under **Settings > Notifications**, Security section, Email channel. Your first sign-in is never alerted, as there is nothing to compare against. diff --git a/docs/content/docs/guides/warmup.mdx b/docs/content/docs/guides/warmup.mdx index 44e2ca422..5f0b9be41 100644 --- a/docs/content/docs/guides/warmup.mdx +++ b/docs/content/docs/guides/warmup.mdx @@ -80,8 +80,6 @@ At defaults a mailbox sends 10 on day one, 11 the next, and levels off at 40 aft Four things shape the real daily number: sends are spread across your warmup hours with jitter, the target is capped by how many eligible partners exist, a mailbox whose health drops gets reduced volume and wider spacing until it recovers, and a recent spam placement holds the ramp where it is. -The target is checked twice: when the next send is placed, and again as it goes out. A signal that lowers the day's number while a send is already waiting (a spam placement, a health band, partners leaving the pool) holds that send rather than letting it go out over the new number, and the mailbox picks up again at its next opening. A cut can still land below what the mailbox has already sent that day, and the drawer shows that honestly; what it cannot do is add to the excess. - ### Holding the ramp on an early signal If any warmup email lands in a recipient's spam folder, that mailbox stops climbing immediately: @@ -106,7 +104,7 @@ Real inboxes reply, so a configurable share of the time a mailbox answers an exi Replies thread properly with a real `Re:` subject and `In-Reply-To` header, and candidates must be between 45 minutes and seven days old, so nothing is answered instantly or revived indefinitely. -Receiving warmup mail can also prompt an answer directly. When a verified warmup email arrives, the recipient sometimes points its next scheduled send back at whoever wrote, 25 minutes to 5 hours later and inside its own warmup hours. That is a re-pointing, not extra work: each mailbox has one warmup send queued at a time, so a reply-back moves that send earlier and aims it, and can never push a send the mailbox had already planned sooner. If the send it moved was parked for tomorrow because today's target is spent, the day's cap still holds: the answer waits for the next opening and keeps its aim. The chance is the recipient's own reply rate, drawn once when the reply is scheduled rather than again when it sends, and it stops before a thread reaches its message cap so replies cannot answer replies indefinitely. +Receiving warmup mail can also prompt an answer directly. When a verified warmup email arrives, the recipient sometimes points its next scheduled send back at whoever wrote, 25 minutes to 5 hours later and inside its own warmup hours. That is a re-pointing, not extra work: each mailbox has one warmup send queued at a time, so a reply-back moves that send earlier and aims it, and can never push a send the mailbox had already planned sooner. The chance is the recipient's own reply rate, drawn once when the reply is scheduled rather than again when it sends, and it stops before a thread reaches its message cap so replies cannot answer replies indefinitely. Timing imitates people throughout: sends come in bursts and lulls rather than a fixed rhythm, never land on round clock marks, and opens happen on a natural delay during the recipient's waking hours. No mailbox in the pool reads mail at 3am or reacts within seconds. diff --git a/docs/content/docs/guides/webhooks.mdx b/docs/content/docs/guides/webhooks.mdx index befd96555..72ae85990 100644 --- a/docs/content/docs/guides/webhooks.mdx +++ b/docs/content/docs/guides/webhooks.mdx @@ -16,6 +16,8 @@ Open **Settings -> Webhooks** in the dashboard and click **Add endpoint**. 3. Choose which events to subscribe to. Leave the list empty to receive all standard events (high-volume firehose events are opt-in separately, see below). 4. Click **Create**. The signing secret is shown exactly once. Copy it now and store it somewhere safe (a secrets manager or environment variable). It is never shown again. Use **Rotate secret** if you need a new one later. +The secret is encrypted at rest with the instance's credential key, the same one that protects mailbox passwords, and is decrypted only when a delivery is signed. It is never returned by the API after creation, and never shown in the admin panel. + After creation the endpoint is **unverified** and will receive only a challenge request, not real events. ## Verifying your endpoint diff --git a/docs/content/docs/guides/workspace-export-import.mdx b/docs/content/docs/guides/workspace-export-import.mdx index 96376b17f..e24d42d74 100644 --- a/docs/content/docs/guides/workspace-export-import.mdx +++ b/docs/content/docs/guides/workspace-export-import.mdx @@ -111,6 +111,7 @@ An import runs as one transaction. If anything fails, nothing lands and the work - **Check campaign schedules.** Per-contact progress travels, so a running campaign resumes at the step it reached rather than restarting. - **Expect the daily send counters to be honoured.** Today's counts come across, so a mailbox cannot double its volume by being migrated mid-day. - **Re-authorize integrations** if you exported without credentials. +- **Rotate each webhook's signing secret.** The secret is encrypted at rest with the source instance's key, so it travels only in an export that carries credentials. Exported without them, the endpoint arrives with no secret and its deliveries will not verify at your receiver. Open each endpoint and use **Rotate secret**, then put the new value in your receiver. If you have shell access to the source, `warmblyctl org export` writes the same archive straight to a file without going through a browser, which is the easier route for a large workspace. See the [warmblyctl reference](/development/warmblyctl/). diff --git a/docs/pnpm-lock.yaml b/docs/pnpm-lock.yaml index 6b6ff191b..2a326373c 100644 --- a/docs/pnpm-lock.yaml +++ b/docs/pnpm-lock.yaml @@ -11,6 +11,7 @@ overrides: sharp: ^0.35.0 postcss: ^8.5.23 nanoid: ^3.3.17 + image-size: ^2.0.3 importers: @@ -2463,9 +2464,9 @@ packages: resolution: {integrity: sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==} engines: {node: '>= 4'} - image-size@2.0.2: - resolution: {integrity: sha512-IRqXKlaXwgSMAMtpNzZa1ZAe8m+Sa1770Dhk8VkSsP9LS+iHD62Zd8FQKs8fbPiagBE7BzoFX23cxFnwshpV6w==} - engines: {node: '>=16.x'} + image-size@2.0.4: + resolution: {integrity: sha512-QRUkFFsRV/6fuESxb9Vkq+a0LkSrgKXuc2NEqfikiXxxN/G3tjWt5EVUlMaImRBZRZK/jRBEbYvpPYZL8t08Zw==} + engines: {node: '>=18'} hasBin: true import-fresh@3.3.1: @@ -5982,7 +5983,7 @@ snapshots: github-slugger: 2.0.0 hast-util-to-estree: 3.1.3 hast-util-to-jsx-runtime: 2.3.6 - image-size: 2.0.2 + image-size: 2.0.4 negotiator: 1.0.0 npm-to-yarn: 3.0.1 path-to-regexp: 8.4.2 @@ -6234,7 +6235,7 @@ snapshots: ignore@7.0.9: {} - image-size@2.0.2: {} + image-size@2.0.4: {} import-fresh@3.3.1: dependencies: diff --git a/docs/pnpm-workspace.yaml b/docs/pnpm-workspace.yaml index dbfb24b01..67f89534f 100644 --- a/docs/pnpm-workspace.yaml +++ b/docs/pnpm-workspace.yaml @@ -19,3 +19,8 @@ overrides: postcss: ^8.5.23 # Clear CVE-2026-67213 (DoS via infinite loop) in the transitive nanoid. nanoid: ^3.3.17 + # Clear GHSA-w3rx-r6r6-pgpr and GHSA-5p2g-fcmc-qvqq in the image-size that + # fumadocs-core pulls in. Build-time only on repo-authored MDX, but the docs + # site is in scope for the dependency scan and an unjustified high finding is + # the same amount of work to explain as to fix. + image-size: ^2.0.3 diff --git a/go.mod b/go.mod index 33fa604fc..93901ea5c 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,23 @@ module github.com/warmbly/warmbly -go 1.25.0 +go 1.26.0 + +// Pinned so every build, local and CI, uses a toolchain carrying the +// standard-library security fixes. The net/http, crypto/tls, net/url, +// encoding/xml, encoding/asn1 and net advisories govulncheck reports against +// earlier toolchains are fixed in go1.26.6; the Docker builder images track the +// matching 1.26 line. Raise both together. +toolchain go1.26.8 require ( cloud.google.com/go/cloudtasks v1.13.7 cloud.google.com/go/pubsub v1.50.1 github.com/MicahParks/keyfunc/v3 v3.7.0 github.com/andybalholm/cascadia v1.3.5 - github.com/aws/aws-sdk-go-v2 v1.41.0 + github.com/aws/aws-sdk-go-v2 v1.47.0 github.com/aws/aws-sdk-go-v2/config v1.30.2 github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 - github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 + github.com/aws/aws-sdk-go-v2/service/s3 v1.113.1 github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0 github.com/aws/aws-sdk-go-v2/service/sesv2 v1.49.0 github.com/aws/aws-sdk-go-v2/service/ssm v1.67.7 @@ -26,10 +33,10 @@ require ( github.com/golang-migrate/migrate/v4 v4.19.1 github.com/golangci/golangci-lint v1.64.8 github.com/google/uuid v1.6.0 - github.com/gorilla/websocket v1.5.0 - github.com/hamba/avro/v2 v2.24.0 + github.com/gorilla/websocket v1.5.3 + github.com/hamba/avro/v2 v2.31.0 github.com/invopop/jsonschema v0.13.0 - github.com/jackc/pgx/v5 v5.9.0 + github.com/jackc/pgx/v5 v5.11.0 github.com/meszmate/apple-go v0.0.0-20250828163208-7fea48c91b32 github.com/microcosm-cc/bluemonday v1.0.27 github.com/mileusna/useragent v1.3.5 @@ -46,10 +53,10 @@ require ( github.com/stripe/stripe-go/v86 v86.4.2 github.com/xuri/excelize/v2 v2.11.0 go.uber.org/zap v1.27.0 - golang.org/x/crypto v0.55.0 - golang.org/x/net v0.58.0 + golang.org/x/crypto v0.57.0 + golang.org/x/net v0.59.0 golang.org/x/oauth2 v0.36.0 - golang.org/x/term v0.45.0 + golang.org/x/term v0.46.0 google.golang.org/api v0.264.0 google.golang.org/grpc v1.83.2 google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.6.1 @@ -87,21 +94,21 @@ require ( github.com/antithesishq/antithesis-sdk-go v0.7.0-default-no-op // indirect github.com/ashanbrown/forbidigo v1.6.0 // indirect github.com/ashanbrown/makezero v1.2.0 // indirect - github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 // indirect + github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 // indirect github.com/aws/aws-sdk-go-v2/credentials v1.18.2 // indirect github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.3 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.3 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect - github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 // indirect + github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.3 // indirect github.com/aws/aws-sdk-go-v2/service/sso v1.26.1 // indirect github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1 // indirect github.com/aws/aws-sdk-go-v2/service/sts v1.35.1 // indirect - github.com/aws/smithy-go v1.24.0 // indirect + github.com/aws/smithy-go v1.28.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/beorn7/perks v1.0.1 // indirect @@ -319,10 +326,10 @@ require ( go.yaml.in/yaml/v2 v2.4.2 // indirect golang.org/x/arch v0.19.0 // indirect golang.org/x/exp/typeparams v0.0.0-20250210185358-939b2ce775ac // indirect - golang.org/x/mod v0.40.0 // indirect - golang.org/x/sync v0.22.0 // indirect - golang.org/x/sys v0.47.0 // indirect - golang.org/x/text v0.41.0 // indirect + golang.org/x/mod v0.41.0 // indirect + golang.org/x/sync v0.23.0 // indirect + golang.org/x/sys v0.48.0 // indirect + golang.org/x/text v0.42.0 // indirect golang.org/x/time v0.15.0 // indirect golang.org/x/tools v0.49.0 // indirect golang.org/x/tools/go/expect v0.1.1-deprecated // indirect diff --git a/go.sum b/go.sum index 4837449c1..61d5019dd 100644 --- a/go.sum +++ b/go.sum @@ -102,36 +102,36 @@ github.com/ashanbrown/forbidigo v1.6.0 h1:D3aewfM37Yb3pxHujIPSpTf6oQk9sc9WZi8ger github.com/ashanbrown/forbidigo v1.6.0/go.mod h1:Y8j9jy9ZYAEHXdu723cUlraTqbzjKF1MUyfOKL+AjcU= github.com/ashanbrown/makezero v1.2.0 h1:/2Lp1bypdmK9wDIq7uWBlDF1iMUpIIS4A+pF6C9IEUU= github.com/ashanbrown/makezero v1.2.0/go.mod h1:dxlPhHbDMC6N6xICzFBSK+4njQDdK8euNO0qjQMtGY4= -github.com/aws/aws-sdk-go-v2 v1.41.0 h1:tNvqh1s+v0vFYdA1xq0aOJH+Y5cRyZ5upu6roPgPKd4= -github.com/aws/aws-sdk-go-v2 v1.41.0/go.mod h1:MayyLB8y+buD9hZqkCW3kX1AKq07Y5pXxtgB+rRFhz0= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4 h1:489krEF9xIGkOaaX3CE/Be2uWjiXrkCH6gUX+bZA/BU= -github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.4/go.mod h1:IOAPF6oT9KCsceNTvvYMNHy0+kMF8akOjeDvPENWxp4= +github.com/aws/aws-sdk-go-v2 v1.47.0 h1:0jsHallhJCeaU0Ko48c/3FK1ctOQ7NpzggxriJOQ8MQ= +github.com/aws/aws-sdk-go-v2 v1.47.0/go.mod h1:bttEH6JqnUL8LepvDVfdrds/fZ5bCIxzpe3abyUrhDU= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20 h1:GPRlPwz40I2B2VrBEASOA3Bi77NyeqejNLkifosX0rs= +github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.7.20/go.mod h1:g7PNzKcsOKWb4fkSRBA7BZVAS6Y8IcxzN+nRohhQ1Q8= github.com/aws/aws-sdk-go-v2/config v1.30.2 h1:YE1BmSc4fFYqFgN1mN8uzrtc7R9x+7oSWeX8ckoltAw= github.com/aws/aws-sdk-go-v2/config v1.30.2/go.mod h1:UNrLGZ6jfAVjgVJpkIxjLufRJqTXCVYOpkeVf83kwBo= github.com/aws/aws-sdk-go-v2/credentials v1.18.2 h1:mfm0GKY/PHLhs7KO0sUaOtFnIQ15Qqxt+wXbO/5fIfs= github.com/aws/aws-sdk-go-v2/credentials v1.18.2/go.mod h1:v0SdJX6ayPeZFQxgXUKw5RhLpAoZUuynxWDfh8+Eknc= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1 h1:owmNBboeA0kHKDcdF8KiSXmrIuXZustfMGGytv6OMkM= github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.18.1/go.mod h1:Bg1miN59SGxrZqlP8vJZSmXW+1N8Y1MjQDq1OfuNod8= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16 h1:rgGwPzb82iBYSvHMHXc8h9mRoOUBZIGFgKb9qniaZZc= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.4.16/go.mod h1:L/UxsGeKpGoIj6DxfhOWHWQ/kGKcd4I1VncE4++IyKA= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16 h1:1jtGzuV7c82xnqOVfx2F0xmJcOw5374L7N6juGW6x6U= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.7.16/go.mod h1:M2E5OQf+XLe+SZGmmpaI2yy+J326aFf6/+54PoxSANc= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.3 h1:Hp/VgjP0BysR3OgLlR057Vz2LcbbVnoWeJ+3qWiS/fY= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.5.3/go.mod h1:nwGV5qw7F1IZPgxCvA/ph8N2TAuz+BkRG/bXn808qMA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.3 h1:MUaM4f+kj1ZIBPZfUS8cxP1GKXXZtHJjAthy93AN7SM= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.8.3/go.mod h1:6YmVmEVRI5ZZzRjCSsb9SryKH0hAlMRdgA7kG9aDvBU= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16 h1:CjMzUs78RDDv4ROu3JnJn/Ig1r6ZD7/T2DXLLRpejic= -github.com/aws/aws-sdk-go-v2/internal/v4a v1.4.16/go.mod h1:uVW4OLBqbJXSHJYA9svT9BluSvvwbzLQ2Crf6UPzR3c= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4 h1:0ryTNEdJbzUCEWkVXEXoqlXV72J5keC1GvILMOuD00E= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.4/go.mod h1:HQ4qwNZh32C3CBeO6iJLQlgtMzqeG17ziAA/3KDJFow= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7 h1:DIBqIrJ7hv+e4CmIk2z3pyKT+3B6qVMgRsawHiR3qso= -github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.9.7/go.mod h1:vLm00xmBke75UmpNvOcZQ/Q30ZFjbczeLFqGx5urmGo= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16 h1:oHjJHeUy0ImIV0bsrX0X91GkV5nJAyv1l1CC9lnO0TI= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.13.16/go.mod h1:iRSNGgOYmiYwSCXxXaKb9HfOEj40+oTKn8pTxMlYkRM= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16 h1:NSbvS17MlI2lurYgXnCOLvCFX38sBW4eiVER7+kkgsU= -github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.19.16/go.mod h1:SwT8Tmqd4sA6G1qaGdzWCJN99bUmPGHfRwwq3G5Qb+A= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.3 h1:fuSCw4Z2qfRCztMPO3GXJNSiEp6Wee+WOLwrHHUMy9c= +github.com/aws/aws-sdk-go-v2/internal/v4a v1.5.3/go.mod h1:6SxcHheD1pPR5+kWm1wGvjlL/YqUsh267sAfEmN4K7A= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19 h1:bAdDl/HkGCcGPoe25ToSHEw23VIxt6CT5fLcg111BKg= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.13.19/go.mod h1:KaUzbLxv4CeSxh6ZCl9B4m7CuFenS8kUEaDs+f/DQr4= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.3 h1:BHKCSX4QXERe8So8rbWqaM7owqOmDJxATXgJwGng22A= +github.com/aws/aws-sdk-go-v2/service/internal/checksum v1.11.3/go.mod h1:GqWeeKfYfezihA2KfFL9l7ohEdZWe1tuFWh3GfyNSnE= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.3 h1:bON1rJf67TSTDCKg816AAIE4xSTtoo9tl0XRkO72R+I= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.14.3/go.mod h1:c5BBpjJcQXpfeq9iASyVKA3T6vX6B6LEXY4mL/gklDY= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.3 h1:L8vIOxylma91TcR96NFTEC07G3JDwSl+CvK2b+IODms= +github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.20.3/go.mod h1:fmPIZQzTExYuBNWFyi1P7IoDjvskgphXqK1yObMzusM= github.com/aws/aws-sdk-go-v2/service/kms v1.49.4 h1:2gom8MohxN0SnhHZBYAC4S8jHG+ENEnXjyJ5xKe3vLc= github.com/aws/aws-sdk-go-v2/service/kms v1.49.4/go.mod h1:HO31s0qt0lso/ADvZQyzKs8js/ku0fMHsfyXW8OPVYc= -github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0 h1:MIWra+MSq53CFaXXAywB2qg9YvVZifkk6vEGl/1Qor0= -github.com/aws/aws-sdk-go-v2/service/s3 v1.95.0/go.mod h1:79S2BdqCJpScXZA2y+cpZuocWsjGjJINyXnOsf5DTz8= +github.com/aws/aws-sdk-go-v2/service/s3 v1.113.1 h1:cFHmwLxZPvtoAlo79MboURL2+7b0TMHycnrcf5VZNXk= +github.com/aws/aws-sdk-go-v2/service/s3 v1.113.1/go.mod h1:/uA+2Qj4jd5qBWagVC1AyzzDFXVK997E7U04w7Kw0wI= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0 h1:vL6rQXcGtFv9q/9eRPdI+lL+dvTm7xKGZYSHEvmrpDk= github.com/aws/aws-sdk-go-v2/service/secretsmanager v1.41.0/go.mod h1:QwEDLD+7EukuEUnbWtiNE8LhgvvmhjZoi4XAppYPtyc= github.com/aws/aws-sdk-go-v2/service/sesv2 v1.49.0 h1:XzMkmb8eU1B3WTgfKdLnhJCcWTLZPCoP54ZSsDzPKLY= @@ -144,8 +144,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1 h1:XdG6/o1/ZDmn3wJU5SRAejHa github.com/aws/aws-sdk-go-v2/service/ssooidc v1.31.1/go.mod h1:oiotGTKadCOCl3vg/tYh4k45JlDF81Ka8rdumNhEnIQ= github.com/aws/aws-sdk-go-v2/service/sts v1.35.1 h1:iF4Xxkc0H9c/K2dS0zZw3SCkj0Z7n6AMnUiiyoJND+I= github.com/aws/aws-sdk-go-v2/service/sts v1.35.1/go.mod h1:0bxIatfN0aLq4mjoLDeBpOjOke68OsFlXPDFJ7V0MYw= -github.com/aws/smithy-go v1.24.0 h1:LpilSUItNPFr1eY85RYgTIg5eIEPtvFbskaFcmmIUnk= -github.com/aws/smithy-go v1.24.0/go.mod h1:LEj2LM3rBRQJxPZTB4KuzZkaZYnZPnvgIhb4pu07mx0= +github.com/aws/smithy-go v1.28.1 h1:R/nXH00c8qcfCzQVELtRw+eLQWtzv+VAIEFJ1/xxXlQ= +github.com/aws/smithy-go v1.28.1/go.mod h1:YE2RhdIuDbA5E5bTdciG9KrW3+TiEONeUWCqxX9i1Fc= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -468,8 +468,8 @@ github.com/gorilla/css v1.0.1 h1:ntNaBIghp6JmvWnxbZKANoLyuXTPZ4cAMlo6RyhlbO8= github.com/gorilla/css v1.0.1/go.mod h1:BvnYkspnSzMmwRK+b8/xgNPLiIuNZr6vbZBTPQ2A3b0= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= -github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= -github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/gorilla/websocket v1.5.3 h1:saDtZ6Pbx/0u+bgYQ3q96pZgCzfhKXGPqt7kZ72aNNg= +github.com/gorilla/websocket v1.5.3/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gostaticanalysis/analysisutil v0.7.1 h1:ZMCjoue3DtDWQ5WyU16YbjbQEQ3VuzwxALrpYd+HeKk= github.com/gostaticanalysis/analysisutil v0.7.1/go.mod h1:v21E3hY37WKMGSnbsw2S/ojApNWb6C1//mXO48CXbVc= github.com/gostaticanalysis/comment v1.4.1/go.mod h1:ih6ZxzTHLdadaiSnF5WY3dxUoXfXAlTaRzuaNDlSado= @@ -485,8 +485,8 @@ github.com/gostaticanalysis/testutil v0.5.0 h1:Dq4wT1DdTwTGCQQv3rl3IvD5Ld0E6HiY+ github.com/gostaticanalysis/testutil v0.5.0/go.mod h1:OLQSbuM6zw2EvCcXTz1lVq5unyoNft372msDY0nY5Hs= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rHAxPBD8KFhJpmcqms= github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= -github.com/hamba/avro/v2 v2.24.0 h1:axTlaYDkcSY0dVekRSy8cdrsj5MG86WqosUQacKCids= -github.com/hamba/avro/v2 v2.24.0/go.mod h1:7vDfy/2+kYCE8WUHoj2et59GTv0ap7ptktMXu0QHePI= +github.com/hamba/avro/v2 v2.31.0 h1:wv3nmua7lCEIwWsb6vqsTS3pXktTxcKg5eoyNu0VhrU= +github.com/hamba/avro/v2 v2.31.0/go.mod h1:t6lJYAGE5Mswfn17zjtyQsssRQgnqO6TXLBCHHWRqrw= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= @@ -532,8 +532,8 @@ github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsI github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.9.0 h1:T/dI+2TvmI2H8s/KH1/lXIbz1CUFk3gn5oTjr0/mBsE= -github.com/jackc/pgx/v5 v5.9.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= +github.com/jackc/pgx/v5 v5.11.0 h1:IzBBtyK9AHqf98cctWFifYSci2hgQR/cd56wB4p+ogg= +github.com/jackc/pgx/v5 v5.11.0/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4= github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jgautheron/goconst v1.7.1 h1:VpdAG7Ca7yvvJk5n8dMwQhfEZJh95kl/Hl9S1OI5Jkk= @@ -1035,8 +1035,8 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= -golang.org/x/crypto v0.55.0 h1:+KWHjbgOaAQ66dh/YlkZKHlz9ZUlq61AFirAR9ntP8M= -golang.org/x/crypto v0.55.0/go.mod h1:uq0V9dE/fzQuJtbnL+2EhWOE63vo164FY8xqEnV9xis= +golang.org/x/crypto v0.57.0 h1:3ZVCjf8Ggz7zneR/EHRVx68Ctf+2pmIMP2UFhh9cC6M= +golang.org/x/crypto v0.57.0/go.mod h1:Fdz0i5U6CoizGwLda9DttjSk6qlZo25zYNtR+ycvuZA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0 h1:e66Fs6Z+fZTbFBAxKfP3PALWBtpfqks2bwGcexMxgtk= golang.org/x/exp v0.0.0-20240909161429-701f63a606c0/go.mod h1:2TbTHSBQa924w8M6Xs1QcRcFwyucIwBGpK1p2f1YFFY= @@ -1060,8 +1060,8 @@ golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.13.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= -golang.org/x/mod v0.40.0 h1:hUv+3cXcdRHz08UmSiOob7sadHig73uo5bkXxQ/tvUs= -golang.org/x/mod v0.40.0/go.mod h1:0/weTWkPWGBikyTWAX3dkjVztMmBA5hM0DH6BElSupE= +golang.org/x/mod v0.41.0 h1:qJmnOUb4YB+FsEuM3HcWucdZASCPGhsX6uljO6pog0c= +golang.org/x/mod v0.41.0/go.mod h1:Ek9pY8RKWXwsWvd3rQiHYtMqkjSUV+s1Rj7j4H5Ur6o= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1082,8 +1082,8 @@ golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= golang.org/x/net v0.16.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= -golang.org/x/net v0.58.0 h1:ynWG7rqYi4ccpTEuPZ2QGWHktVEM9DMCj9yzDE0Q7To= -golang.org/x/net v0.58.0/go.mod h1:YwCddHnFlT7eLQqVprV19OnhLGtc5xOKgE0RyqgfWAU= +golang.org/x/net v0.59.0 h1:5zfYln+w5XCxwrnMMJPufRgNoXEaGxl0wo5GqPXyues= +golang.org/x/net v0.59.0/go.mod h1:2DA/G1UfVbCpQPeWTmMPGY7Cs2PkBkwu743bVX5PIVg= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.36.0 h1:peZ/1z27fi9hUOFCAZaHyrpWG5lwe0RJEEEeH0ThlIs= golang.org/x/oauth2 v0.36.0/go.mod h1:YDBUJMTkDnJS+A4BP4eZBjCqtokkg1hODuPjwiGPO7Q= @@ -1098,8 +1098,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.22.0 h1:SZjpbeLmrCk4xhRSZFNZW5gFUeCeFgjekvI/+gfScek= -golang.org/x/sync v0.22.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= +golang.org/x/sync v0.23.0 h1:KameEIfc1IkluZyXWLn39Wd4tURc6GbCiISGiZm2bQk= +golang.org/x/sync v0.23.0/go.mod h1:sUUOizhqBxiL6pEWpqNLUiaJn1ShEbZ6BBqskPbjZm0= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1124,8 +1124,8 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.47.0 h1:o7XGOvZQCADBQQ4Y7VNq2dRWQR7JmOUW8Kxx4ZsNgWs= -golang.org/x/sys v0.47.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= +golang.org/x/sys v0.48.0 h1:bbX/i/6MgT9BVLM9RT1thmxL04yeTAhbEz4SyadbXoo= +golang.org/x/sys v0.48.0/go.mod h1:hNLxWAXmnKAxqDtdwIYC4bM9oQPEecfsnNMuSxOs3og= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= @@ -1134,8 +1134,8 @@ golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU= golang.org/x/term v0.13.0/go.mod h1:LTmsnFJwVN6bCy1rVCoS+qHT1HhALEFxKncY3WNNh4U= -golang.org/x/term v0.45.0 h1:NwWyBmoJCbfTHpxrWoZ9C6/VxOf7ic219I8xZZFdrf0= -golang.org/x/term v0.45.0/go.mod h1:9aqxs0blBcrm/n0L9QW0aRVD+ktan8ssZromtqJC43w= +golang.org/x/term v0.46.0 h1:3+OXuTbaKDgwk8jTi3aSLHRlmWqHEUDUtxnbFigO4YE= +golang.org/x/term v0.46.0/go.mod h1:+K02xbkittuwc0Am4abfA3Fc+XRGXkvBXNO88NCXPoc= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -1147,8 +1147,8 @@ golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.41.0 h1:vz/seA0lnX87Othu2f/0L24RcgrXD9/YFTSuGjj3rH8= -golang.org/x/text v0.41.0/go.mod h1:jvf1O8ajNzZqhSrQBPbutR/EB83Cc0CFrezNQIwbb5M= +golang.org/x/text v0.42.0 h1:JbOZXgfeCPU9gacVtYliJqOhD+zhrEqK4LfdpmlUZqI= +golang.org/x/text v0.42.0/go.mod h1:ojzP1Z+2QtioaF8DTtO8K5q7JWVVYwZKenzujK0Zd0E= golang.org/x/time v0.15.0 h1:bbrp8t3bGUeFOx08pvsMYRTCVSMk89u4tKbNOZbp88U= golang.org/x/time v0.15.0/go.mod h1:Y4YMaQmXwGQZoFaVFk4YpCt4FLQMYKZe9oeV/f4MSno= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/api/handler/admin.go b/internal/api/handler/admin.go index d2fbae3ab..8c84f4918 100644 --- a/internal/api/handler/admin.go +++ b/internal/api/handler/admin.go @@ -377,7 +377,7 @@ func (h *Handler) AdminListWarmupPools(c *gin.Context) { // AdminGetWarmupHealthSummary returns an aggregate health overview of all warmup pools func (h *Handler) AdminGetWarmupHealthSummary(c *gin.Context) { if h.WarmupService == nil { - errx.JSON(c, errx.NewPublic(errx.Internal, "Warmup service not available.")) + errx.JSON(c, errx.New(errx.Internal, "warmup service not available")) return } summary, xerr := h.WarmupService.GetPoolHealthSummary(c.Request.Context()) diff --git a/internal/api/handler/admin_fleet.go b/internal/api/handler/admin_fleet.go index c1524893f..3168528ab 100644 --- a/internal/api/handler/admin_fleet.go +++ b/internal/api/handler/admin_fleet.go @@ -19,12 +19,12 @@ import ( // GET /admin/fleet/capacity func (h *Handler) AdminFleetCapacity(c *gin.Context) { if h.AdminFleetRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet view is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet view is not available on this instance")) return } rows, err := h.AdminFleetRepo.Capacity(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": rows}) @@ -35,7 +35,7 @@ func (h *Handler) AdminFleetCapacity(c *gin.Context) { // GET /admin/fleet/decisions?kind=&worker_id=&limit= func (h *Handler) AdminFleetDecisions(c *gin.Context) { if h.AdminFleetRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet view is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet view is not available on this instance")) return } var workerID *uuid.UUID @@ -58,7 +58,7 @@ func (h *Handler) AdminFleetDecisions(c *gin.Context) { } rows, err := h.AdminFleetRepo.Decisions(c.Request.Context(), c.Query("kind"), workerID, limit) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": rows}) @@ -69,12 +69,12 @@ func (h *Handler) AdminFleetDecisions(c *gin.Context) { // GET /admin/fleet/dedicated func (h *Handler) AdminFleetDedicated(c *gin.Context) { if h.AdminFleetRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet view is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet view is not available on this instance")) return } rows, err := h.AdminFleetRepo.DedicatedAssignments(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": rows}) @@ -96,14 +96,14 @@ func (h *Handler) AdminFleetReleaseIsolatedEgress(c *gin.Context) { return } if h.WorkerRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Worker placement is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "worker placement is not available on this instance")) return } ctx := c.Request.Context() assignment, err := h.WorkerRepo.GetActiveDedicatedAssignment(ctx, orgID) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if assignment == nil { diff --git a/internal/api/handler/admin_insight.go b/internal/api/handler/admin_insight.go index c566f77fd..a210c0a78 100644 --- a/internal/api/handler/admin_insight.go +++ b/internal/api/handler/admin_insight.go @@ -81,7 +81,7 @@ func (h *Handler) AdminListOrgAPIKeys(c *gin.Context) { // AdminRevokeOrgAPIKey is DELETE /admin/organizations/:id/api-keys/:keyId. func (h *Handler) AdminRevokeOrgAPIKey(c *gin.Context) { if h.APIKeyService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "API keys are not available on this instance")) + errx.JSON(c, errx.New(errx.NotImplemented, "API keys are not available on this instance")) return } orgID, err := uuid.Parse(c.Param("id")) diff --git a/internal/api/handler/admin_jobs.go b/internal/api/handler/admin_jobs.go index 7f2d781ef..fe1a13909 100644 --- a/internal/api/handler/admin_jobs.go +++ b/internal/api/handler/admin_jobs.go @@ -18,12 +18,12 @@ const scheduledJobEntity models.AuditEntityType = "scheduled_job" // AdminListJobs lists every registered background loop. func (h *Handler) AdminListJobs(c *gin.Context) { if h.JobRuns == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Job registry is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "job registry is not available on this instance")) return } jobs, err := h.JobRuns.List(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if jobs == nil { @@ -35,7 +35,7 @@ func (h *Handler) AdminListJobs(c *gin.Context) { // AdminRunJob asks the loop that owns the job to run at its next poll. func (h *Handler) AdminRunJob(c *gin.Context) { if h.JobRuns == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Job registry is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "job registry is not available on this instance")) return } name := c.Param("name") @@ -45,7 +45,7 @@ func (h *Handler) AdminRunJob(c *gin.Context) { } found, err := h.JobRuns.RequestRun(c.Request.Context(), name) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if !found { diff --git a/internal/api/handler/admin_org_plan.go b/internal/api/handler/admin_org_plan.go index 1055c4822..8082d0171 100644 --- a/internal/api/handler/admin_org_plan.go +++ b/internal/api/handler/admin_org_plan.go @@ -25,7 +25,7 @@ type adminManagedPlanRequest struct { // one (an internal or partner plan), so the picker needs the full list. func (h *Handler) AdminListPlans(c *gin.Context) { if h.SubscriptionService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Plans are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "plans are not available on this instance")) return } plans, xerr := h.SubscriptionService.ListPlans(c.Request.Context(), false) @@ -44,7 +44,7 @@ func (h *Handler) AdminGetOrgManagedPlan(c *gin.Context) { return } if h.OrganizationService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Organizations are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "organizations are not available on this instance")) return } managed, xerr := h.OrganizationService.GetManagedPlan(c.Request.Context(), orgID) @@ -67,7 +67,7 @@ func (h *Handler) AdminGrantOrgManagedPlan(c *gin.Context) { return } if h.OrganizationService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Organizations are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "organizations are not available on this instance")) return } @@ -113,7 +113,7 @@ func (h *Handler) AdminRevokeOrgManagedPlan(c *gin.Context) { return } if h.OrganizationService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Organizations are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "organizations are not available on this instance")) return } diff --git a/internal/api/handler/admin_org_risk.go b/internal/api/handler/admin_org_risk.go index 818d02de6..343a4e86f 100644 --- a/internal/api/handler/admin_org_risk.go +++ b/internal/api/handler/admin_org_risk.go @@ -29,7 +29,7 @@ func (h *Handler) AdminGetOrgRisk(c *gin.Context) { return } if h.OrgRiskService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Risk posture is not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "risk posture is not available on this instance")) return } risk, xerr := h.OrgRiskService.Get(c.Request.Context(), orgID) @@ -54,7 +54,7 @@ func (h *Handler) AdminSetOrgRiskOverride(c *gin.Context) { return } if h.OrgRiskService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Risk posture is not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "risk posture is not available on this instance")) return } @@ -98,7 +98,7 @@ func (h *Handler) AdminClearOrgRiskOverride(c *gin.Context) { return } if h.OrgRiskService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Risk posture is not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "risk posture is not available on this instance")) return } @@ -125,7 +125,7 @@ func (h *Handler) AdminClearOrgRiskSignal(c *gin.Context) { return } if h.OrgRiskService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Risk posture is not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "risk posture is not available on this instance")) return } key := strings.TrimSpace(c.Param("key")) diff --git a/internal/api/handler/admin_outreach.go b/internal/api/handler/admin_outreach.go index 0027f4f33..2a89132b2 100644 --- a/internal/api/handler/admin_outreach.go +++ b/internal/api/handler/admin_outreach.go @@ -12,7 +12,7 @@ import ( // AdminSendOutreach is POST /admin/outreach. func (h *Handler) AdminSendOutreach(c *gin.Context) { if h.AdminOutreachService == nil { - errx.JSON(c, errx.NewPublic(errx.Internal, "Admin outreach service not available.")) + errx.JSON(c, errx.New(errx.Internal, "admin outreach service not available")) return } adminID := middleware.GetAdminUserID(c) @@ -56,7 +56,7 @@ func (h *Handler) AdminSendOutreach(c *gin.Context) { // params; returns the standard {data, pagination} envelope. func (h *Handler) AdminListOutreach(c *gin.Context) { if h.AdminOutreachService == nil { - errx.JSON(c, errx.NewPublic(errx.Internal, "Admin outreach service not available.")) + errx.JSON(c, errx.New(errx.Internal, "admin outreach service not available")) return } var search models.AdminOutreachSearch diff --git a/internal/api/handler/admin_sends.go b/internal/api/handler/admin_sends.go index 8a588ee8f..3ee75425d 100644 --- a/internal/api/handler/admin_sends.go +++ b/internal/api/handler/admin_sends.go @@ -40,7 +40,7 @@ func parseBoundedLimit(s string, def, max int) int { func (h *Handler) adminSendsReady(c *gin.Context) bool { if h.AdminSendsRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Send operations are not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "send operations are not available on this instance")) return false } return true @@ -55,7 +55,7 @@ func (h *Handler) AdminInFlightSends(c *gin.Context) { reclaimAfter := time.Duration(config.CampaignSendReclaimAfterMinutes) * time.Minute result, err := h.AdminSendsRepo.InFlight(c.Request.Context(), reclaimAfter, limit) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, result) @@ -77,7 +77,7 @@ func (h *Handler) AdminListDeadLetters(c *gin.Context) { } result, err := h.AdminSendsRepo.ListDeadLetters(c.Request.Context(), status, cursor, limit) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, result) @@ -89,7 +89,7 @@ func (h *Handler) AdminReplayDeadLetter(c *gin.Context) { return } if h.AdvancedService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Dead letter replay is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "dead letter replay is not available on this instance")) return } id, err := uuid.Parse(c.Param("id")) @@ -99,7 +99,7 @@ func (h *Handler) AdminReplayDeadLetter(c *gin.Context) { } row, err := h.AdminSendsRepo.GetDeadLetter(c.Request.Context(), id) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if row == nil { @@ -130,7 +130,7 @@ func (h *Handler) AdminRecentTaskFailures(c *gin.Context) { limit := parseBoundedLimit(c.Query("limit"), 100, 500) rows, err := h.AdminSendsRepo.RecentTaskFailures(c.Request.Context(), limit) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": rows}) @@ -143,7 +143,7 @@ func (h *Handler) AdminWebhookHealth(c *gin.Context) { } health, err := h.AdminSendsRepo.WebhookHealth(c.Request.Context(), webhookDeliveryLease) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, health) @@ -152,12 +152,12 @@ func (h *Handler) AdminWebhookHealth(c *gin.Context) { // AdminWebhookReclaim re-queues deliveries stranded in_flight past the lease. func (h *Handler) AdminWebhookReclaim(c *gin.Context) { if h.WebhookRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Webhook delivery is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "webhook delivery is not available on this instance")) return } n, err := h.WebhookRepo.ReclaimStuckDeliveries(c.Request.Context(), webhookDeliveryLease) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } h.audit(c, models.AuditActionUpdate, models.AuditEntityWebhook, nil, map[string]string{ @@ -179,7 +179,7 @@ func (h *Handler) AdminListOrgWebhooks(c *gin.Context) { } rows, err := h.AdminSendsRepo.OrgWebhooks(c.Request.Context(), orgID) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": rows}) diff --git a/internal/api/handler/admin_sync.go b/internal/api/handler/admin_sync.go index 3b806dd10..4ec08e90b 100644 --- a/internal/api/handler/admin_sync.go +++ b/internal/api/handler/admin_sync.go @@ -19,7 +19,7 @@ const ( // AdminSearchSync is GET /admin/sync: every mailbox's sync governor state. func (h *Handler) AdminSearchSync(c *gin.Context) { if h.AdminSyncRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Sync operations are not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "sync operations are not available on this instance")) return } var search models.AdminSyncSearch @@ -45,7 +45,7 @@ func (h *Handler) AdminSearchSync(c *gin.Context) { // AdminSyncClearThrottle is POST /admin/sync/:id/clear-throttle. func (h *Handler) AdminSyncClearThrottle(c *gin.Context) { if h.AdminSyncRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Sync operations are not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "sync operations are not available on this instance")) return } id, err := uuid.Parse(c.Param("id")) @@ -73,7 +73,7 @@ func (h *Handler) AdminSyncClearThrottle(c *gin.Context) { // AdminSyncRestartBackfill is POST /admin/sync/:id/restart-backfill. func (h *Handler) AdminSyncRestartBackfill(c *gin.Context) { if h.AdminSyncRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Sync operations are not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "sync operations are not available on this instance")) return } id, err := uuid.Parse(c.Param("id")) diff --git a/internal/api/handler/admin_tester.go b/internal/api/handler/admin_tester.go index 99bd8d33a..4f9218b3c 100644 --- a/internal/api/handler/admin_tester.go +++ b/internal/api/handler/admin_tester.go @@ -92,7 +92,7 @@ func (h *Handler) AdminCreateTester(c *gin.Context) { return } if h.UserRepo == nil || h.OrganizationService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Account creation is not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "account creation is not available on this instance")) return } @@ -202,7 +202,7 @@ func (h *Handler) undoHalfMadeTester(c *gin.Context, userID uuid.UUID, cause *er // is the set an operator needs to review and prune. func (h *Handler) AdminListTesters(c *gin.Context) { if h.UserRepo == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Accounts are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "accounts are not available on this instance")) return } list, err := h.UserRepo.ListLoginCodeExempt(c.Request.Context()) @@ -227,7 +227,7 @@ func (h *Handler) AdminRevokeTester(c *gin.Context) { return } if h.UserRepo == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Accounts are not available on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "accounts are not available on this instance")) return } if err := h.UserRepo.SetLoginCodeExempt(c.Request.Context(), userID, false, "", nil); err != nil { diff --git a/internal/api/handler/admin_transfer.go b/internal/api/handler/admin_transfer.go index 724c198bb..1b2aa40cb 100644 --- a/internal/api/handler/admin_transfer.go +++ b/internal/api/handler/admin_transfer.go @@ -27,7 +27,7 @@ func (h *Handler) adminTransferOrg(c *gin.Context) (uuid.UUID, bool) { } org, err := h.OrgRepo.GetByID(c.Request.Context(), orgID) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return uuid.Nil, false } if org == nil { @@ -35,7 +35,7 @@ func (h *Handler) adminTransferOrg(c *gin.Context) (uuid.UUID, bool) { return uuid.Nil, false } if h.OrgTransferService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Workspace transfer is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "Workspace transfer is not available on this instance.")) return uuid.Nil, false } return orgID, true diff --git a/internal/api/handler/advanced_outreach.go b/internal/api/handler/advanced_outreach.go index a57674f9d..847b22849 100644 --- a/internal/api/handler/advanced_outreach.go +++ b/internal/api/handler/advanced_outreach.go @@ -55,10 +55,29 @@ func (h *Handler) UpdateOutreachSettings(c *gin.Context) { c.Status(http.StatusNoContent) } -func (h *Handler) GetCampaignAdvancedSettings(c *gin.Context) { +// ownedCampaign resolves the :id campaign for the advanced-outreach routes and +// proves it belongs to the caller's organization. The route carries only a +// campaign id, so this is the only thing that ties the request to a tenant: +// every handler here must go through it rather than parsing the param itself. +func (h *Handler) ownedCampaign(c *gin.Context) (uuid.UUID, *errx.Error) { campaignID, err := uuid.Parse(c.Param("id")) if err != nil { - errx.JSON(c, errx.ErrUuid) + return uuid.Nil, errx.ErrUuid + } + orgID := middleware.GetOrganizationID(c) + if orgID == nil { + return uuid.Nil, errx.New(errx.BadRequest, "no organization selected") + } + if _, xerr := h.CampaignService.Get(c.Request.Context(), orgID.String(), campaignID.String()); xerr != nil { + return uuid.Nil, xerr + } + return campaignID, nil +} + +func (h *Handler) GetCampaignAdvancedSettings(c *gin.Context) { + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } settings, xerr := h.AdvancedService.GetCampaignSettings(c.Request.Context(), campaignID) @@ -70,9 +89,9 @@ func (h *Handler) GetCampaignAdvancedSettings(c *gin.Context) { } func (h *Handler) UpdateCampaignAdvancedSettings(c *gin.Context) { - campaignID, err := uuid.Parse(c.Param("id")) - if err != nil { - errx.JSON(c, errx.ErrUuid) + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } var req models.UpsertOutreachSettingsRequest @@ -94,9 +113,9 @@ func (h *Handler) UpdateCampaignAdvancedSettings(c *gin.Context) { } func (h *Handler) ListCampaignABVariants(c *gin.Context) { - campaignID, err := uuid.Parse(c.Param("id")) - if err != nil { - errx.JSON(c, errx.ErrUuid) + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } variants, xerr := h.AdvancedService.ListABVariants(c.Request.Context(), campaignID) @@ -108,9 +127,9 @@ func (h *Handler) ListCampaignABVariants(c *gin.Context) { } func (h *Handler) CreateCampaignABVariant(c *gin.Context) { - campaignID, err := uuid.Parse(c.Param("id")) - if err != nil { - errx.JSON(c, errx.ErrUuid) + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } var req models.CreateCampaignABVariantRequest @@ -135,9 +154,9 @@ func (h *Handler) CreateCampaignABVariant(c *gin.Context) { } func (h *Handler) UpdateCampaignABVariant(c *gin.Context) { - campaignID, err := uuid.Parse(c.Param("id")) - if err != nil { - errx.JSON(c, errx.ErrUuid) + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } variantID, err := uuid.Parse(c.Param("variantId")) @@ -165,9 +184,9 @@ func (h *Handler) UpdateCampaignABVariant(c *gin.Context) { } func (h *Handler) DeleteCampaignABVariant(c *gin.Context) { - campaignID, err := uuid.Parse(c.Param("id")) - if err != nil { - errx.JSON(c, errx.ErrUuid) + campaignID, cerr := h.ownedCampaign(c) + if cerr != nil { + errx.JSON(c, cerr) return } variantID, err := uuid.Parse(c.Param("variantId")) diff --git a/internal/api/handler/advisor.go b/internal/api/handler/advisor.go index 5dc5142fa..caaf551c9 100644 --- a/internal/api/handler/advisor.go +++ b/internal/api/handler/advisor.go @@ -33,7 +33,7 @@ const advisorReadMaxAge = 30 * time.Minute // advisorOrg resolves the caller's org, or writes the error. func (h *Handler) advisorOrg(c *gin.Context) (uuid.UUID, bool) { if h.AdvisorService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The Advisor is not configured on this server.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the Advisor is not configured on this server")) return uuid.Nil, false } orgID := middleware.GetOrganizationID(c) @@ -140,7 +140,7 @@ func (h *Handler) RefreshAdvisor(c *gin.Context) { // request is safe without an idempotency key. func (h *Handler) ApplyAdvisorFinding(c *gin.Context) { if h.AdvisorService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The Advisor is not configured on this server.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the Advisor is not configured on this server")) return } inv, xerr := h.jwtInvocation(c) @@ -169,7 +169,7 @@ func (h *Handler) ApplyAdvisorFinding(c *gin.Context) { // and reports what it actually called rather than only what it says it did. func (h *Handler) AgentFixAdvisorFinding(c *gin.Context) { if h.AdvisorService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The Advisor is not configured on this server.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the Advisor is not configured on this server")) return } inv, xerr := h.jwtInvocation(c) @@ -194,7 +194,7 @@ func (h *Handler) AgentFixAdvisorFinding(c *gin.Context) { // UndoAdvisorFinding — POST /advisor/recommendations/:id/undo func (h *Handler) UndoAdvisorFinding(c *gin.Context) { if h.AdvisorService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The Advisor is not configured on this server.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the Advisor is not configured on this server")) return } inv, xerr := h.jwtInvocation(c) diff --git a/internal/api/handler/agent_tools.go b/internal/api/handler/agent_tools.go index 6a18e62c5..a9e4f7a14 100644 --- a/internal/api/handler/agent_tools.go +++ b/internal/api/handler/agent_tools.go @@ -50,7 +50,7 @@ func (h *Handler) agentToolInvocation(c *gin.Context) (aitools.Invocation, *errx // array or inside a Hermes block. func (h *Handler) ListAgentTools(c *gin.Context) { if h.AITools == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI tools are not available")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI tools are not available")) return } inv, xerr := h.agentToolInvocation(c) @@ -102,7 +102,7 @@ func (h *Handler) ListAgentTools(c *gin.Context) { // tool returned JSON (they all do today) and as a string otherwise. func (h *Handler) CallAgentTool(c *gin.Context) { if h.AITools == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI tools are not available")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI tools are not available")) return } inv, xerr := h.agentToolInvocation(c) diff --git a/internal/api/handler/ai_agent.go b/internal/api/handler/ai_agent.go index 42414ac7f..4bc49b7d4 100644 --- a/internal/api/handler/ai_agent.go +++ b/internal/api/handler/ai_agent.go @@ -49,7 +49,7 @@ func (h *Handler) jwtInvocation(c *gin.Context) (aitools.Invocation, *errx.Error // CreateAgentSession — POST /ai/sessions func (h *Handler) CreateAgentSession(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -74,7 +74,7 @@ func (h *Handler) CreateAgentSession(c *gin.Context) { // ListAgentSessions — GET /ai/sessions (cursor paginated, newest first) func (h *Handler) ListAgentSessions(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -113,7 +113,7 @@ func (h *Handler) ListAgentSessions(c *gin.Context) { // hydrated transcript (+ any pending approval) so a reopened tab rehydrates. func (h *Handler) AgentSessionMessages(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -148,7 +148,7 @@ func (h *Handler) AgentSessionMessages(c *gin.Context) { // transcript. Sessions are private to the member, so no extra permission gate. func (h *Handler) DeleteAgentSession(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -172,7 +172,7 @@ func (h *Handler) DeleteAgentSession(c *gin.Context) { // conversation history in this workspace. func (h *Handler) ClearAgentSessions(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -191,7 +191,7 @@ func (h *Handler) ClearAgentSessions(c *gin.Context) { // AgentMessage — POST /ai/sessions/:id/messages (SSE) func (h *Handler) AgentMessage(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -220,14 +220,14 @@ func (h *Handler) AgentMessage(c *gin.Context) { emit := sseEmitter(c) if serr := h.AIAgentService.RunMessage(c.Request.Context(), inv, sessionID, req.MessageID, req.Text, req.Page, req.Resource, emit); serr != nil { - emit(aiagent.StreamEvent{Type: "error", Code: string(codeIdentifier(serr)), Message: serr.UserMessage()}) + emit(aiagent.StreamEvent{Type: "error", Code: string(codeIdentifier(serr)), Message: serr.Message}) } } // AgentApprove — POST /ai/sessions/:id/approve (SSE) resumes a paused run. func (h *Handler) AgentApprove(c *gin.Context) { if h.AIAgentService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } inv, xerr := h.jwtInvocation(c) @@ -256,7 +256,7 @@ func (h *Handler) AgentApprove(c *gin.Context) { emit := sseEmitter(c) if serr := h.AIAgentService.Resume(c.Request.Context(), inv, sessionID, req.Decision, emit); serr != nil { - emit(aiagent.StreamEvent{Type: "error", Code: string(codeIdentifier(serr)), Message: serr.UserMessage()}) + emit(aiagent.StreamEvent{Type: "error", Code: string(codeIdentifier(serr)), Message: serr.Message}) } } diff --git a/internal/api/handler/ai_inbox_agent.go b/internal/api/handler/ai_inbox_agent.go index 8affcf848..1675b42af 100644 --- a/internal/api/handler/ai_inbox_agent.go +++ b/internal/api/handler/ai_inbox_agent.go @@ -66,7 +66,7 @@ func (h *Handler) ApproveAgentDraft(c *gin.Context) { return } if h.AIDraftRepo == nil { - errx.Handle(c, errx.NewPublic(errx.ServiceUnavailable, "The inbox agent is not configured.")) + errx.Handle(c, errx.New(errx.ServiceUnavailable, "the inbox agent is not configured")) return } @@ -156,7 +156,7 @@ func (h *Handler) DiscardAgentDraft(c *gin.Context) { return } if h.AIDraftRepo == nil { - errx.Handle(c, errx.NewPublic(errx.ServiceUnavailable, "The inbox agent is not configured.")) + errx.Handle(c, errx.New(errx.ServiceUnavailable, "the inbox agent is not configured")) return } ok, err := h.AIDraftRepo.SetDraftStatus(c.Request.Context(), *orgID, draftID, models.AIDraftDiscarded) diff --git a/internal/api/handler/ai_reply.go b/internal/api/handler/ai_reply.go index 85c6e1418..01fdff720 100644 --- a/internal/api/handler/ai_reply.go +++ b/internal/api/handler/ai_reply.go @@ -37,7 +37,7 @@ func (h *Handler) DraftReply(c *gin.Context) { return } if h.AIProvider == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } @@ -127,7 +127,7 @@ func (h *Handler) DraftReply(c *gin.Context) { remaining = bal } } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The reply drafter is temporarily unavailable. Your credits were not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "The reply drafter is temporarily unavailable. Your credits were not charged.")) return } diff --git a/internal/api/handler/ai_research.go b/internal/api/handler/ai_research.go index 16e72cd54..548d96117 100644 --- a/internal/api/handler/ai_research.go +++ b/internal/api/handler/ai_research.go @@ -40,7 +40,7 @@ func (h *Handler) aiActorInvocation(c *gin.Context) (aitools.Invocation, *errx.E // ResearchContact — POST /contacts/:id/research (sync) func (h *Handler) ResearchContact(c *gin.Context) { if h.ResearchService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI research is not configured")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI research is not configured")) return } inv, xerr := h.aiActorInvocation(c) @@ -70,7 +70,7 @@ func (h *Handler) ResearchContact(c *gin.Context) { // ListContactResearch — GET /contacts/:id/research func (h *Handler) ListContactResearch(c *gin.Context) { if h.ResearchService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI research is not configured")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI research is not configured")) return } orgID := middleware.GetOrganizationID(c) @@ -99,7 +99,7 @@ func (h *Handler) ListContactResearch(c *gin.Context) { // BatchResearch — POST /contacts/research/batch func (h *Handler) BatchResearch(c *gin.Context) { if h.ResearchService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI research is not configured")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI research is not configured")) return } inv, xerr := h.aiActorInvocation(c) diff --git a/internal/api/handler/attachment.go b/internal/api/handler/attachment.go index 25d47d41a..603619ce8 100644 --- a/internal/api/handler/attachment.go +++ b/internal/api/handler/attachment.go @@ -97,7 +97,7 @@ func (h *Handler) UploadCampaignAttachment(c *gin.Context) { return } if h.Storage == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Object storage not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "object storage not configured")) return } diff --git a/internal/api/handler/auth.go b/internal/api/handler/auth.go index 40dd8b1ab..873e022a9 100644 --- a/internal/api/handler/auth.go +++ b/internal/api/handler/auth.go @@ -162,6 +162,12 @@ func (h *Handler) GetUser(c *gin.Context) { // Scoped to the session's current organization, not the caller: labels // are workspace assets, so a teammate must see what the owner created // (issue #436). A session with no workspace selected gets empty lists. + // Admin routes require a second factor, so the panel has to be able to say + // so before it makes a call that 403s. + if sess := middleware.GetSession(c); sess != nil { + u.SessionMFAVerified = sess.MFAVerified + } + u.Folders, u.Tags, u.Categories = []models.Group{}, []models.Group{}, []models.Group{} if orgID := middleware.GetOrganizationID(c); orgID != nil { if folders, ferr := h.FolderService.List(ctx, *orgID); ferr == nil { diff --git a/internal/api/handler/auth_sso.go b/internal/api/handler/auth_sso.go index cf337489c..efede5d4a 100644 --- a/internal/api/handler/auth_sso.go +++ b/internal/api/handler/auth_sso.go @@ -106,7 +106,7 @@ func (h *Handler) ssoCallback(c *gin.Context, in auth.SSOCallback) { handoff, err := h.AuthService.SSOCallbackComplete(c.Request.Context(), in) if err != nil { - c.Redirect(http.StatusFound, base+"/auth/login?sso_error="+url.QueryEscape(err.UserMessage())) + c.Redirect(http.StatusFound, base+"/auth/login?sso_error="+url.QueryEscape(err.Message)) return } diff --git a/internal/api/handler/avatar.go b/internal/api/handler/avatar.go index 6aefbf3b5..50e59d5ef 100644 --- a/internal/api/handler/avatar.go +++ b/internal/api/handler/avatar.go @@ -348,7 +348,7 @@ func readAvatarUpload(c *gin.Context) ([]byte, string, string, *errx.Error) { func putPublicObject(ctx context.Context, store storage.Store, key string, body []byte, mime string) (string, *errx.Error) { if store == nil { - return "", errx.NewPublic(errx.ServiceUnavailable, "Object storage not configured.") + return "", errx.New(errx.ServiceUnavailable, "object storage not configured") } // Public-read URL with long-lived cache. The backend chooses the right // semantics per store (S3 sets an ACL + s3 URL; filesystem writes and diff --git a/internal/api/handler/billing_return_url.go b/internal/api/handler/billing_return_url.go new file mode 100644 index 000000000..ca9b81044 --- /dev/null +++ b/internal/api/handler/billing_return_url.go @@ -0,0 +1,50 @@ +package handler + +import ( + "strings" + + "github.com/warmbly/warmbly/internal/config" +) + +// billingReturnURL turns a client-supplied Stripe return URL into one that can +// only point back at this instance's dashboard. +// +// Stripe redirects the customer to whatever success_url, cancel_url or +// return_url the session was created with, so accepting the value verbatim +// made every billing endpoint an open redirect laundered through +// checkout.stripe.com, which is about as trustworthy a hop as a phishing link +// can get. Every shipped client already sends a same-origin path, so pinning +// the origin here changes nothing a real client does. +// +// A path is kept, so "which page did you come from" still works. Anything else +// falls back to the dashboard root. +func billingReturnURL(raw, fallbackPath string) string { + base := strings.TrimRight(config.AppBaseURL(), "/") + raw = strings.TrimSpace(raw) + + // A deployment that never configured its own address has no origin to pin + // to, and a relative fallback is not a URL Stripe will accept: returning one + // would take checkout out entirely. Hand back what the caller sent, which is + // the behaviour before this function existed. + if base == "" { + return raw + } + + fallback := base + fallbackPath + if raw == "" { + return fallback + } + // A relative path is the common case and needs no parsing beyond refusing + // the "//evil.example" form, which a browser reads as a protocol-relative + // absolute URL. + if strings.HasPrefix(raw, "/") && !strings.HasPrefix(raw, "//") { + return base + raw + } + if base != "" && strings.HasPrefix(raw, base+"/") { + return raw + } + if raw == base { + return raw + } + return fallback +} diff --git a/internal/api/handler/broker_access_log.go b/internal/api/handler/broker_access_log.go new file mode 100644 index 000000000..b73241c68 --- /dev/null +++ b/internal/api/handler/broker_access_log.go @@ -0,0 +1,36 @@ +package handler + +import ( + "github.com/gin-gonic/gin" + "github.com/rs/zerolog/log" +) + +// Access logging for the two internal endpoints that hand out something worth +// more than a record: the data-key decrypt broker and the blob presigner. +// +// CASA 6.7.1 asks that access to server-side secrets be logged or monitored, +// and these were the two that were silent. They are also the two where a +// refusal is the clearest probe signal the instance produces: a node asks for +// keys it owns and prefixes it uses, so a rejected key or a decrypt that fails +// is either a misconfigured node or somebody holding the internal token and +// looking around. Either way an operator should be able to see it. +// +// Deliberately not logged: the ciphertext, the plaintext key, and the signed +// URL. What is recorded is who asked, for what shape of thing, and whether it +// was allowed, which is what makes a pattern visible without the log itself +// becoming the leak. +func logBrokerAccess(c *gin.Context, operation, subject string, allowed bool, reason string) { + ev := log.Info() + if !allowed { + ev = log.Warn() + } + ev. + Str("event", "broker_access"). + Str("operation", operation). + Str("subject", subject). + Bool("allowed", allowed). + Str("client_ip", c.ClientIP()). + Str("request_id", c.GetHeader("X-Request-Id")). + Str("reason", reason). + Msg("internal broker access") +} diff --git a/internal/api/handler/cli_auth.go b/internal/api/handler/cli_auth.go index c2194ab7f..3cf2c2ae4 100644 --- a/internal/api/handler/cli_auth.go +++ b/internal/api/handler/cli_auth.go @@ -16,7 +16,7 @@ import ( func (h *Handler) cliAuthReady(c *gin.Context) bool { if h.CLIAuthService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "CLI sign-in is not enabled on this instance")) + errx.JSON(c, errx.New(errx.NotImplemented, "CLI sign-in is not enabled on this instance")) return false } return true diff --git a/internal/api/handler/cloudlink.go b/internal/api/handler/cloudlink.go index ee1194912..b7e68fe45 100644 --- a/internal/api/handler/cloudlink.go +++ b/internal/api/handler/cloudlink.go @@ -14,7 +14,7 @@ import ( func (h *Handler) cloudLinkReady(c *gin.Context) bool { if h.CloudLinkService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Cloud link is not enabled on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "cloud link is not enabled on this instance")) return false } return true diff --git a/internal/api/handler/compose_draft.go b/internal/api/handler/compose_draft.go index c149211c5..87fbd0e58 100644 --- a/internal/api/handler/compose_draft.go +++ b/internal/api/handler/compose_draft.go @@ -43,7 +43,7 @@ func (h *Handler) DraftCompose(c *gin.Context) { return } if h.AIProvider == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured")) return } if allowed, xerr := h.FeatureGateService.CanUseUnibox(c.Request.Context(), *orgID); xerr != nil { @@ -126,7 +126,7 @@ func (h *Handler) DraftCompose(c *gin.Context) { remaining = bal } } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The email drafter is temporarily unavailable. Your credits were not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "The email drafter is temporarily unavailable. Your credits were not charged.")) return } diff --git a/internal/api/handler/contact_detail.go b/internal/api/handler/contact_detail.go index 5371602ee..8909a8a31 100644 --- a/internal/api/handler/contact_detail.go +++ b/internal/api/handler/contact_detail.go @@ -75,8 +75,8 @@ func (h *Handler) LookupContactByEmail(c *gin.Context) { // ListContactEmails returns one row per email we sent (or tried to // send) to the contact. Cursor pagination keyed on the task ID. func (h *Handler) ListContactEmails(c *gin.Context) { - userID, err := middleware.GetUserUUID(c) - if err != nil { + orgID := middleware.GetOrganizationID(c) + if orgID == nil { errx.Handle(c, errx.ErrAuth) return } @@ -107,7 +107,7 @@ func (h *Handler) ListContactEmails(c *gin.Context) { } } - res, xerr := h.ContactService.ListSentEmails(c.Request.Context(), userID, contactID, limit, beforeAt, beforeID) + res, xerr := h.ContactService.ListSentEmails(c.Request.Context(), *orgID, contactID, limit, beforeAt, beforeID) if xerr != nil { errx.Handle(c, xerr) return diff --git a/internal/api/handler/credits.go b/internal/api/handler/credits.go index 35e92ae03..5af5dd72f 100644 --- a/internal/api/handler/credits.go +++ b/internal/api/handler/credits.go @@ -28,7 +28,7 @@ func (h *Handler) GetCreditBalance(c *gin.Context) { return } if h.CreditService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Credits are not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "credits are not available")) return } @@ -127,7 +127,9 @@ func (h *Handler) CreateCreditCheckoutSession(c *gin.Context) { } session, xerr := h.StripeService.CreateCreditCheckoutSession( - c.Request.Context(), uid, *orgID, pack.Key, pack.Credits, req.SuccessURL, req.CancelURL, + c.Request.Context(), uid, *orgID, pack.Key, pack.Credits, + billingReturnURL(req.SuccessURL, "/app/settings/billing?credits=done"), + billingReturnURL(req.CancelURL, "/app/settings/billing"), ) if xerr != nil { errx.JSON(c, xerr) @@ -149,7 +151,7 @@ func (h *Handler) ListCreditTransactions(c *gin.Context) { return } if h.CreditService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Credits are not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "credits are not available")) return } @@ -198,7 +200,7 @@ func (h *Handler) GetCreditUsage(c *gin.Context) { return } if h.CreditService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Credits are not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "credits are not available")) return } days := 30 @@ -227,7 +229,7 @@ func (h *Handler) GetCreditSettings(c *gin.Context) { return } if h.CreditService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Credits are not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "credits are not available")) return } cfg, xerr := h.CreditService.GetSpendSettings(c.Request.Context(), *orgID) @@ -247,7 +249,7 @@ func (h *Handler) UpdateCreditSettings(c *gin.Context) { return } if h.CreditService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Credits are not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "credits are not available")) return } var body struct { diff --git a/internal/api/handler/email.go b/internal/api/handler/email.go index 4e01a69b0..7bed73713 100644 --- a/internal/api/handler/email.go +++ b/internal/api/handler/email.go @@ -303,15 +303,11 @@ func (h *Handler) UpdateEmailTrackingDomain(c *gin.Context) { } func (h *Handler) DeleteEmail(c *gin.Context) { - orgID := middleware.GetOrganizationID(c) - if orgID == nil { - errx.Handle(c, errx.New(errx.BadRequest, "no organization selected")) - return - } + userIDStr := middleware.GetUserID(c) emailAccountID := c.Param("id") - if err := h.EmailService.Delete(c.Request.Context(), orgID.String(), emailAccountID); err != nil { + if err := h.EmailService.Delete(c.Request.Context(), userIDStr, emailAccountID); err != nil { errx.Handle(c, err) return } diff --git a/internal/api/handler/email_image.go b/internal/api/handler/email_image.go index 7ecedc028..300997b8d 100644 --- a/internal/api/handler/email_image.go +++ b/internal/api/handler/email_image.go @@ -66,11 +66,11 @@ func (h *Handler) UploadEmailImage(c *gin.Context) { return } if h.Storage == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Object storage not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "object storage not configured")) return } if h.EmailImageRepo == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Image library not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "image library not available")) return } @@ -233,7 +233,7 @@ func (h *Handler) DeleteEmailImage(c *gin.Context) { return } if h.EmailImageRepo == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Image library not available.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "image library not available")) return } id, err := uuid.Parse(c.Param("id")) diff --git a/internal/api/handler/email_oauth_callback.go b/internal/api/handler/email_oauth_callback.go index 1858ab1b7..61d6aea36 100644 --- a/internal/api/handler/email_oauth_callback.go +++ b/internal/api/handler/email_oauth_callback.go @@ -128,6 +128,13 @@ func (h *Handler) renderOAuthCallback(c *gin.Context, provider string) { data.Status = "Connection cancelled." } + // This page is one inline script that hands the code to the opener and + // closes. It loads nothing and submits nothing, so the policy says so; + // 'unsafe-inline' covers the script that is the page itself. + // Cross-Origin-Opener-Policy is relaxed here because talking to the + // opener is the whole job, and the message is addressed to one origin. + c.Header("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'") + c.Header("Cross-Origin-Opener-Policy", "unsafe-none") c.Header("Content-Type", "text/html; charset=utf-8") c.Status(http.StatusOK) _ = callbackPage.Execute(c.Writer, data) diff --git a/internal/api/handler/email_sync.go b/internal/api/handler/email_sync.go index 483aa3ffa..ec1895e77 100644 --- a/internal/api/handler/email_sync.go +++ b/internal/api/handler/email_sync.go @@ -19,12 +19,12 @@ type emailSyncResponse struct { // GetEmailSync reports a mailbox's sync progress and fair-use status. func (h *Handler) GetEmailSync(c *gin.Context) { - userID, err := middleware.GetUserUUID(c) - if err != nil { + orgID := middleware.GetOrganizationID(c) + if orgID == nil { errx.JSON(c, errx.ErrUnauthorized) return } - state, policy, xerr := h.EmailService.GetSyncState(c.Request.Context(), userID.String(), c.Param("id")) + state, policy, xerr := h.EmailService.GetSyncState(c.Request.Context(), orgID.String(), c.Param("id")) if xerr != nil { errx.JSON(c, xerr) return diff --git a/internal/api/handler/fleet_nodes.go b/internal/api/handler/fleet_nodes.go index a90de090f..557f33af7 100644 --- a/internal/api/handler/fleet_nodes.go +++ b/internal/api/handler/fleet_nodes.go @@ -18,6 +18,7 @@ import ( "github.com/warmbly/warmbly/internal/config" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/models" + "github.com/warmbly/warmbly/internal/observability/errs" ) // The fleet is pull-based. A node joins with the instance token, gets the @@ -66,7 +67,7 @@ type fleetJoinResponse struct { // credentials yet — that is the whole point. func (h *Handler) FleetJoin(c *gin.Context) { if h.FleetNodes == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } var req fleetJoinRequest @@ -161,7 +162,12 @@ func (h *Handler) FleetHeartbeat(c *gin.Context) { case errors.Is(err, fleetnode.ErrRoleChanged): c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) default: - c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + // The heartbeat is answered to a machine, not a person, and the + // caller authenticates with a node credential rather than an + // operator session. The detail goes to the log where an operator + // reads it; the node only needs to know to retry. + errs.CaptureException(err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "heartbeat could not be recorded"}) } return } @@ -380,7 +386,7 @@ func renderNodeEnv(nodeID uuid.UUID, role models.NodeRole, region string) string // each is on, what it should be on, and what it is using. func (h *Handler) AdminFleetNodes(c *gin.Context) { if h.FleetNodes == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } role := models.NodeRole(c.Query("role")) @@ -390,7 +396,7 @@ func (h *Handler) AdminFleetNodes(c *gin.Context) { } nodes, err := h.FleetNodes.List(c.Request.Context(), role) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } sort.SliceStable(nodes, func(i, j int) bool { return nodes[i].Role < nodes[j].Role }) @@ -401,12 +407,12 @@ func (h *Handler) AdminFleetNodes(c *gin.Context) { // once. Issuing replaces the previous one, which is also how it is revoked. func (h *Handler) AdminFleetIssueJoinToken(c *gin.Context) { if h.FleetNodes == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } token, err := h.FleetNodes.IssueJoinToken(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } h.audit(c, "fleet_join_token_issued", models.AuditEntityWorker, nil, nil) @@ -426,7 +432,7 @@ type setTagsBody struct { func (h *Handler) AdminListWorkerTags(c *gin.Context) { tags, err := h.WorkerRepo.ListAllWorkerTags(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, gin.H{"data": tags}) @@ -488,7 +494,7 @@ func (h *Handler) AdminFleetReserveWorker(c *gin.Context) { return } if h.WorkerRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Worker placement is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "worker placement is not available on this instance")) return } var body reserveWorkerBody @@ -510,7 +516,7 @@ func (h *Handler) AdminFleetReserveWorker(c *gin.Context) { ctx := c.Request.Context() w, err := h.WorkerRepo.GetWorkerDetail(ctx, id) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if w == nil { @@ -551,11 +557,11 @@ func (h *Handler) AdminFleetDeleteNode(c *gin.Context) { return } if h.FleetNodeRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } if err := h.FleetNodeRepo.Delete(c.Request.Context(), id); err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } h.audit(c, models.AuditActionDelete, models.AuditEntityWorker, &id, nil) @@ -582,7 +588,7 @@ func (h *Handler) AdminFleetPatchNode(c *gin.Context) { return } if h.FleetNodeRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } var body patchNodeBody @@ -595,21 +601,21 @@ func (h *Handler) AdminFleetPatchNode(c *gin.Context) { changed := map[string]string{} if body.Name != nil { if err := h.FleetNodeRepo.SetName(ctx, id, *body.Name); err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } changed["name"] = *body.Name } if body.Notes != nil { if err := h.FleetNodeRepo.SetNotes(ctx, id, *body.Notes); err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } changed["notes"] = *body.Notes } if body.PinnedVersion != nil { if err := h.FleetNodeRepo.SetPinnedVersion(ctx, id, *body.PinnedVersion); err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } changed["pinned_version"] = *body.PinnedVersion @@ -622,7 +628,7 @@ func (h *Handler) AdminFleetPatchNode(c *gin.Context) { h.audit(c, models.AuditActionUpdate, models.AuditEntityWorker, &id, changed) node, err := h.FleetNodes.Get(ctx, id) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } c.JSON(http.StatusOK, node) @@ -632,12 +638,12 @@ func (h *Handler) AdminFleetPatchNode(c *gin.Context) { // converge on. func (h *Handler) AdminFleetRelease(c *gin.Context) { if h.FleetSettingsRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } state, err := h.FleetSettingsRepo.GetRelease(c.Request.Context()) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if state == nil { @@ -656,7 +662,7 @@ type setReleaseBody struct { // rollback. func (h *Handler) AdminFleetSetRelease(c *gin.Context) { if h.FleetSettingsRepo == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Fleet enrolment is not available on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "fleet enrolment is not available on this instance")) return } var body setReleaseBody @@ -668,7 +674,7 @@ func (h *Handler) AdminFleetSetRelease(c *gin.Context) { ctx := c.Request.Context() state, err := h.FleetSettingsRepo.GetRelease(ctx) if err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } if state == nil { @@ -694,7 +700,7 @@ func (h *Handler) AdminFleetSetRelease(c *gin.Context) { } if err := h.FleetSettingsRepo.SetRelease(ctx, state); err != nil { - errx.JSON(c, errx.New(errx.Internal, err.Error())) + errx.JSON(c, errx.NewPublic(errx.Internal, err.Error())) return } h.audit(c, "fleet_release_set", models.AuditEntityWorker, nil, map[string]string{ diff --git a/internal/api/handler/generation.go b/internal/api/handler/generation.go index 4ee609044..3cd66d079 100644 --- a/internal/api/handler/generation.go +++ b/internal/api/handler/generation.go @@ -88,7 +88,7 @@ func (h *Handler) GenerateWriting(c *gin.Context) { // Provider must be configured. if h.WritingGenerator == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI writing assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI writing assistant is not configured.")) return } @@ -149,10 +149,10 @@ func (h *Handler) GenerateWriting(c *gin.Context) { } } if errors.Is(gerr, generation.ErrNotConfigured) { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI writing assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI writing assistant is not configured.")) return } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The writing assistant is temporarily unavailable. Your credit was not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "The writing assistant is temporarily unavailable. Your credit was not charged.")) return } diff --git a/internal/api/handler/generation_ai_variable.go b/internal/api/handler/generation_ai_variable.go index 0e028b511..d194f19ae 100644 --- a/internal/api/handler/generation_ai_variable.go +++ b/internal/api/handler/generation_ai_variable.go @@ -80,7 +80,7 @@ func (h *Handler) GenerateAIVariable(c *gin.Context) { return } if h.AIProvider == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI generation is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI generation is not configured.")) return } @@ -210,7 +210,7 @@ func (h *Handler) GenerateAIVariable(c *gin.Context) { remaining = bal } } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI generation is temporarily unavailable. Your credit was not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI generation is temporarily unavailable. Your credit was not charged.")) return } diff --git a/internal/api/handler/generation_edit.go b/internal/api/handler/generation_edit.go index 4bb6e0e61..d78735260 100644 --- a/internal/api/handler/generation_edit.go +++ b/internal/api/handler/generation_edit.go @@ -100,7 +100,7 @@ func (h *Handler) GenerateEdit(c *gin.Context) { return } if h.AIProvider == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI writing assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI writing assistant is not configured.")) return } @@ -159,10 +159,10 @@ func (h *Handler) GenerateEdit(c *gin.Context) { } } if errors.Is(gerr, generation.ErrNotConfigured) { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "AI writing assistant is not configured.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "AI writing assistant is not configured.")) return } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The writing assistant is temporarily unavailable. Your credit was not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "The writing assistant is temporarily unavailable. Your credit was not charged.")) return } diff --git a/internal/api/handler/integration.go b/internal/api/handler/integration.go index b848585b3..5058202db 100644 --- a/internal/api/handler/integration.go +++ b/internal/api/handler/integration.go @@ -183,7 +183,7 @@ func (h *Handler) StartIntegrationOAuth(c *gin.Context) { resp, err := h.IntegrationService.OAuthStart(c.Request.Context(), orgID, userID, provider, p.Label) if err != nil { if errors.Is(err, integration.ErrOAuthNotConfigured) { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "This provider isn't available yet — OAuth credentials are not configured on the server.")) + errx.JSON(c, errx.New(errx.NotImplemented, "This provider isn't available yet — OAuth credentials are not configured on the server.")) return } errx.JSON(c, errx.New(errx.BadRequest, err.Error())) @@ -249,6 +249,12 @@ func (h *Handler) IntegrationOAuthCallback(c *gin.Context) { } // json.Marshal escapes <, >, & so the blob is safe to inline in ` + // This page is one inline script that hands the code to the opener and + // closes. It loads nothing and submits nothing, so the policy says so; + // 'unsafe-inline' covers the script that is the page itself. + // Cross-Origin-Opener-Policy is relaxed here because talking to the + // opener is the whole job, and the message is addressed to one origin. + c.Header("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'; style-src 'unsafe-inline'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'") + c.Header("Cross-Origin-Opener-Policy", "unsafe-none") c.Header("Content-Type", "text/html; charset=utf-8") c.String(http.StatusOK, html) } diff --git a/internal/api/handler/internal_blobs.go b/internal/api/handler/internal_blobs.go index f0d54806c..149e53faa 100644 --- a/internal/api/handler/internal_blobs.go +++ b/internal/api/handler/internal_blobs.go @@ -93,11 +93,15 @@ func (h *Handler) InternalPresignBlob(c *gin.Context) { return } if !keyAllowedForNode(req.Key) { + // The clearest probe signal the instance produces: a real node only + // ever asks for prefixes it uses. + logBrokerAccess(c, "blob.presign."+string(op), req.Key, false, "key outside the node prefixes") c.JSON(http.StatusForbidden, gin.H{ "error": "key " + req.Key + " is outside the prefixes a node may reach", }) return } + logBrokerAccess(c, "blob.presign."+string(op), req.Key, true, "") url, err := h.Storage.PresignedURL(c.Request.Context(), op, req.Key, req.ContentType, blobPresignTTL) if err != nil { diff --git a/internal/api/handler/internal_dek.go b/internal/api/handler/internal_dek.go index 574f90708..f061f391d 100644 --- a/internal/api/handler/internal_dek.go +++ b/internal/api/handler/internal_dek.go @@ -130,9 +130,13 @@ func (h *Handler) InternalDecryptDEK(c *gin.Context) { if err != nil { // The reason is not echoed: this answers an unauthenticated-by-org // caller, and KMS errors distinguish "not a key of ours" from "malformed", - // which is exactly what a prober wants to learn. + // which is exactly what a prober wants to learn. It is recorded, though: + // a run of failures here is the signal that someone holding the token is + // trying keys. + logBrokerAccess(c, "dek.decrypt", "", false, "kms refused the ciphertext") c.JSON(http.StatusBadRequest, gin.H{"error": "could not decrypt data key"}) return } + logBrokerAccess(c, "dek.decrypt", "", true, "") c.JSON(http.StatusOK, dekDecryptResponse{DataKey: base64.StdEncoding.EncodeToString(key)}) } diff --git a/internal/api/handler/internal_form.go b/internal/api/handler/internal_form.go index 3bc4a0767..4f4bb913a 100644 --- a/internal/api/handler/internal_form.go +++ b/internal/api/handler/internal_form.go @@ -124,7 +124,7 @@ func (h *Handler) InternalSubmitForm(c *gin.Context) { } // Message only: the errx prefix ("Bad Request (400):") is for logs, // not for a visitor's inline error. - c.JSON(http.StatusBadRequest, formwire.SubmitError{Error: "form_submit_failed", Message: xerr.UserMessage()}) + c.JSON(http.StatusBadRequest, formwire.SubmitError{Error: "form_submit_failed", Message: xerr.Message}) return } c.JSON(http.StatusOK, formwire.SubmitResult{Message: res.Message, RedirectURL: res.RedirectURL}) diff --git a/internal/api/handler/limit_requests.go b/internal/api/handler/limit_requests.go index 10cbd2f24..2b148ac9c 100644 --- a/internal/api/handler/limit_requests.go +++ b/internal/api/handler/limit_requests.go @@ -39,12 +39,17 @@ func (h *Handler) SubmitLimitIncreaseRequest(c *gin.Context) { // ListOrgLimitRequests is GET /v1/organizations/:orgId/limit-requests. func (h *Handler) ListOrgLimitRequests(c *gin.Context) { + session := middleware.GetSession(c) + if session == nil { + errx.JSON(c, errx.ErrUnauthorized) + return + } orgID, err := uuid.Parse(c.Param("orgId")) if err != nil { errx.JSON(c, errx.New(errx.BadRequest, "invalid organization ID")) return } - rows, xerr := h.OrganizationService.ListLimitRequestsForOrg(c.Request.Context(), orgID) + rows, xerr := h.OrganizationService.ListLimitRequestsForOrg(c.Request.Context(), orgID, session.UserID) if xerr != nil { errx.JSON(c, xerr) return diff --git a/internal/api/handler/mcp_server.go b/internal/api/handler/mcp_server.go index 03c3413c1..76c6269ac 100644 --- a/internal/api/handler/mcp_server.go +++ b/internal/api/handler/mcp_server.go @@ -29,7 +29,7 @@ type jsonRPCRequest struct { // MCPEndpoint — POST /api/v1/mcp. Handles one JSON-RPC message. func (h *Handler) MCPEndpoint(c *gin.Context) { if h.AITools == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "MCP is not available")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "MCP is not available")) return } var req jsonRPCRequest diff --git a/internal/api/handler/organization.go b/internal/api/handler/organization.go index 777aa98a4..575d17f81 100644 --- a/internal/api/handler/organization.go +++ b/internal/api/handler/organization.go @@ -310,6 +310,11 @@ func (h *Handler) RemoveMember(c *gin.Context) { // TransferOwnership transfers organization ownership to another member func (h *Handler) TransferOwnership(c *gin.Context) { + session := middleware.GetSession(c) + if session == nil { + errx.JSON(c, errx.ErrUnauthorized) + return + } orgID := middleware.GetOrganizationID(c) if orgID == nil { errx.JSON(c, errx.New(errx.BadRequest, "no organization selected")) @@ -322,7 +327,7 @@ func (h *Handler) TransferOwnership(c *gin.Context) { return } - if xerr := h.OrganizationService.TransferOwnership(c.Request.Context(), *orgID, req.NewOwnerUserID); xerr != nil { + if xerr := h.OrganizationService.TransferOwnership(c.Request.Context(), *orgID, session.UserID, req.NewOwnerUserID); xerr != nil { errx.JSON(c, xerr) return } @@ -351,6 +356,11 @@ func (h *Handler) GetPendingInvitations(c *gin.Context) { // CancelInvitation cancels a pending invitation func (h *Handler) CancelInvitation(c *gin.Context) { + orgID := middleware.GetOrganizationID(c) + if orgID == nil { + errx.JSON(c, errx.ErrUnauthorized) + return + } invIDStr := c.Param("id") invID, err := uuid.Parse(invIDStr) if err != nil { @@ -358,7 +368,7 @@ func (h *Handler) CancelInvitation(c *gin.Context) { return } - if xerr := h.OrganizationService.CancelInvitation(c.Request.Context(), invID); xerr != nil { + if xerr := h.OrganizationService.CancelInvitation(c.Request.Context(), *orgID, invID); xerr != nil { errx.JSON(c, xerr) return } diff --git a/internal/api/handler/poollink.go b/internal/api/handler/poollink.go index 77b37d68d..753a2785c 100644 --- a/internal/api/handler/poollink.go +++ b/internal/api/handler/poollink.go @@ -14,7 +14,7 @@ import ( func (h *Handler) poolLinkReady(c *gin.Context) bool { if h.PoolLinkService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Pool link is not enabled on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "pool link is not enabled on this instance")) return false } return true diff --git a/internal/api/handler/poollink_checkout.go b/internal/api/handler/poollink_checkout.go index 1ca38eb74..705f65c90 100644 --- a/internal/api/handler/poollink_checkout.go +++ b/internal/api/handler/poollink_checkout.go @@ -54,7 +54,7 @@ func (h *Handler) PoolLinkOffer(c *gin.Context) { // would be the only thing deciding what the customer is charged. func (h *Handler) PoolLinkCheckout(c *gin.Context) { if h.SubscriptionService == nil || h.StripeService == nil { - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "Billing is not enabled on this instance.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "billing is not enabled on this instance")) return } uid, err := uuid.Parse(c.GetString("user_id")) diff --git a/internal/api/handler/public_object.go b/internal/api/handler/public_object.go index 7a157c876..e9439595b 100644 --- a/internal/api/handler/public_object.go +++ b/internal/api/handler/public_object.go @@ -42,12 +42,31 @@ func (h *Handler) ServePublicObject(c *gin.Context) { } defer body.Close() - if ct := mime.TypeByExtension(filepath.Ext(key)); ct != "" { + // The Content-Type is derived from the key's extension, and every upload + // handler forces that extension from a server-side image allowlist. An + // extension outside the allowlist therefore means the key did not come from + // an upload handler, and the only safe thing to serve is a download. + ct := mime.TypeByExtension(filepath.Ext(key)) + if ct != "" && servableInline[strings.ToLower(filepath.Ext(key))] { c.Header("Content-Type", ct) + c.Header("Content-Disposition", "inline") + } else { + c.Header("Content-Type", "application/octet-stream") + c.Header("Content-Disposition", "attachment") } // These are user uploads served from our own origin, so the browser must // not be free to decide they are something executable. c.Header("X-Content-Type-Options", "nosniff") + // Belt and braces behind the extension allowlist: even if something + // script-capable reached a public key, this origin holds no session cookie + // and the sandbox denies it an origin to act in. + c.Header("Content-Security-Policy", "default-src 'none'; img-src 'self' data:; sandbox; frame-ancestors 'none'") + // These objects exist to be loaded from somewhere else: an email image is + // fetched by the recipient's mail client, an avatar by a page on another + // host. The API-wide same-site policy would block exactly that, so this + // route opts out. Safe because the objects are public by definition and the + // origin carries no cookie. + c.Header("Cross-Origin-Resource-Policy", "cross-origin") // Keys are content-addressed (they carry an epoch suffix), so they're safe // to cache immutably. c.Header("Cache-Control", "public, max-age=31536000, immutable") @@ -55,6 +74,18 @@ func (h *Handler) ServePublicObject(c *gin.Context) { _, _ = io.Copy(c.Writer, body) } +// servableInline is the set of extensions the upload handlers can produce. A +// public object outside it is handed over as a download rather than rendered, +// so a key that somehow carries .svg or .html cannot become script on this +// origin. +var servableInline = map[string]bool{ + ".png": true, + ".jpg": true, + ".jpeg": true, + ".gif": true, + ".webp": true, +} + // isPublicKey guards the /public route to the key prefixes PutPublic writes, so // it can't be turned into a reader for arbitrary blob keys. func isPublicKey(key string) bool { diff --git a/internal/api/handler/reauth.go b/internal/api/handler/reauth.go new file mode 100644 index 000000000..4e2c567a5 --- /dev/null +++ b/internal/api/handler/reauth.go @@ -0,0 +1,130 @@ +package handler + +import ( + "net/http" + + "github.com/gin-gonic/gin" + "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/api/middleware" + "github.com/warmbly/warmbly/internal/app/token" + "github.com/warmbly/warmbly/internal/errx" + "github.com/warmbly/warmbly/internal/pkg/argon2" +) + +type reauthRequest struct { + // Password is the account password. Optional for an account that has none + // (passkey or SSO only), which confirms with Code instead. + Password string `json:"password"` + // Code is a current TOTP or recovery code. + Code string `json:"code"` +} + +type reauthResponse struct { + // ValidForSeconds is how long the confirmation lasts, so the client can + // decide whether to ask again rather than letting the next call fail. + ValidForSeconds int `json:"valid_for_seconds"` +} + +// Reauth re-proves the account holder behind a live session. +// +// Sensitive changes (minting an API key, registering a passkey, transferring a +// workspace, scheduling a deletion) require a recent confirmation; this is +// where it is given. Either factor is accepted: an account with no password +// confirms with its authenticator, and an account with no 2FA confirms with its +// password. +func (h *Handler) Reauth(c *gin.Context) { + session := middleware.GetSession(c) + if session == nil { + errx.Handle(c, errx.ErrUnauthorized) + return + } + uid, err := uuid.Parse(middleware.GetUserID(c)) + if err != nil { + errx.Handle(c, errx.ErrUnauthorized) + return + } + + var req reauthRequest + if berr := c.ShouldBindJSON(&req); berr != nil { + errx.Handle(c, errx.ErrInvalid) + return + } + + // An account created through Google, Apple or SSO has no password, and + // until it enrols 2FA it has no second factor either. There is nothing for + // it to confirm with, and silently accepting the live session instead would + // turn a stolen token into a permanent API key. Say what to do rather than + // refusing a credential the account does not have. + if !h.hasReauthFactor(c, uid) { + errx.Handle(c, errx.NewWithIdentifier(errx.BadRequest, "reauth_no_factor", + "This account has no password and no two-factor authentication, so there is nothing to confirm with. "+ + "Turn on two-factor authentication under Settings > Security, or set a password, then try again.")) + return + } + + if req.Password == "" && req.Code == "" { + errx.Handle(c, errx.New(errx.BadRequest, "provide your password or a two-factor code")) + return + } + + // This endpoint checks a password, so it is a second place to guess one. + // Refused before the hash comparison, so a caller past the budget cannot + // measure Argon2's timing either. + ctx := c.Request.Context() + if h.AuthService.ReauthFailureExceeded(ctx, uid) { + errx.Handle(c, errx.ErrAuthLimit) + return + } + + if !h.reauthProofValid(c, uid, req) { + h.AuthService.RecordReauthFailure(ctx, uid) + // One message for both factors: which one matched is not something an + // attacker holding a token should learn here. + errx.Handle(c, errx.ErrCredentials) + return + } + h.AuthService.ClearReauthFailures(ctx, uid) + + if xerr := h.TokenService.StampReauth(c.Request.Context(), session.ID); xerr != nil { + errx.Handle(c, xerr) + return + } + + c.JSON(http.StatusOK, reauthResponse{ValidForSeconds: int(token.ReauthWindow.Seconds())}) +} + +// hasReauthFactor reports whether the account has anything to re-authenticate +// with: a stored password, or an enrolled authenticator. +func (h *Handler) hasReauthFactor(c *gin.Context, uid uuid.UUID) bool { + ctx := c.Request.Context() + + if h.TwoFAService != nil { + if enabled, err := h.TwoFAService.IsEnabled(ctx, uid); err == nil && enabled { + return true + } + } + hash, xerr := h.AuthService.PasswordHashFor(ctx, uid) + return xerr == nil && hash != "" +} + +// reauthProofValid checks whichever factor the caller offered. +func (h *Handler) reauthProofValid(c *gin.Context, uid uuid.UUID, req reauthRequest) bool { + ctx := c.Request.Context() + + if req.Code != "" && h.TwoFAService != nil { + if h.TwoFAService.VerifyCurrentCode(ctx, uid, req.Code) { + return true + } + } + + if req.Password != "" { + hash, xerr := h.AuthService.PasswordHashFor(ctx, uid) + if xerr != nil || hash == "" { + return false + } + ok, verr := argon2.Verify(req.Password, hash) + return verr == nil && ok + } + + return false +} diff --git a/internal/api/handler/subscription.go b/internal/api/handler/subscription.go index 5594aeb84..23e17c395 100644 --- a/internal/api/handler/subscription.go +++ b/internal/api/handler/subscription.go @@ -83,7 +83,12 @@ func (h *Handler) CreateCheckoutSession(c *gin.Context) { return } - session, errX := h.StripeService.CreateCheckoutSession(c.Request.Context(), uid, *orgID, req.PriceID, req.SuccessURL, req.CancelURL, req.DiscountCode) + // Pinned to this instance's dashboard: Stripe will redirect the customer + // to whatever is set here. + successURL := billingReturnURL(req.SuccessURL, "/app/settings/billing?checkout=done") + cancelURL := billingReturnURL(req.CancelURL, "/app/settings/billing") + + session, errX := h.StripeService.CreateCheckoutSession(c.Request.Context(), uid, *orgID, req.PriceID, successURL, cancelURL, req.DiscountCode) if errX != nil { errx.JSON(c, errX) return @@ -122,7 +127,8 @@ func (h *Handler) CreateBillingPortalSession(c *gin.Context) { return } - portalURL, errX := h.StripeService.CreatePortalSession(c.Request.Context(), sub.StripeCustomerID, req.ReturnURL) + portalURL, errX := h.StripeService.CreatePortalSession(c.Request.Context(), sub.StripeCustomerID, + billingReturnURL(req.ReturnURL, "/app/settings/billing")) if errX != nil { errx.JSON(c, errX) return @@ -219,7 +225,7 @@ func (h *Handler) GetTrialStatus(c *gin.Context) { } if h.TrialService == nil { - errx.JSON(c, errx.NewPublic(errx.Internal, "Trial service not available.")) + errx.JSON(c, errx.New(errx.Internal, "trial service not available")) return } @@ -241,7 +247,7 @@ func (h *Handler) GetFeatureStatus(c *gin.Context) { } if h.FeatureGateService == nil { - errx.JSON(c, errx.NewPublic(errx.Internal, "Feature gate service not available.")) + errx.JSON(c, errx.New(errx.Internal, "feature gate service not available")) return } diff --git a/internal/api/handler/template_analyze.go b/internal/api/handler/template_analyze.go index 6cc3fd2ee..af67d3b82 100644 --- a/internal/api/handler/template_analyze.go +++ b/internal/api/handler/template_analyze.go @@ -132,7 +132,7 @@ func (h *Handler) AnalyzeTemplateContent(c *gin.Context) { "The spam analyzer is temporarily unavailable, and the credits it reserved could not be returned automatically. Contact support and they will be refunded.")) return } - errx.JSON(c, errx.NewPublic(errx.ServiceUnavailable, "The spam analyzer is temporarily unavailable. Your credits were not charged.")) + errx.JSON(c, errx.New(errx.ServiceUnavailable, "The spam analyzer is temporarily unavailable. Your credits were not charged.")) return } diff --git a/internal/api/handler/unibox.go b/internal/api/handler/unibox.go index 303fae06e..679e8bf4e 100644 --- a/internal/api/handler/unibox.go +++ b/internal/api/handler/unibox.go @@ -484,6 +484,10 @@ func (h *Handler) UniboxReply(c *gin.Context) { errx.Handle(c, errx.ErrUuid) return } + if xerr := mailboxAllowed(c, accountID); xerr != nil { + errx.Handle(c, xerr) + return + } // The composer only knows the provider thread id, but a thread id is // meaningless outside the sending mailbox: the recipient's client threads diff --git a/internal/api/handler/unsubscribe.go b/internal/api/handler/unsubscribe.go index ba277537b..c4ac8ffb6 100644 --- a/internal/api/handler/unsubscribe.go +++ b/internal/api/handler/unsubscribe.go @@ -229,6 +229,10 @@ func renderUnsubPage(c *gin.Context, status int, v unsubView) { c.Header("Cache-Control", "no-store") c.Header("X-Robots-Tag", "noindex") c.Status(status) + // A static page with one form that posts back to this origin. No script, + // no images, nothing embedded, and it must not be framed: the whole page + // is a one-click state change. + c.Header("Content-Security-Policy", "default-src 'none'; style-src 'unsafe-inline'; frame-ancestors 'none'; base-uri 'none'; form-action 'self'") c.Header("Content-Type", "text/html; charset=utf-8") _ = unsubTemplate.Execute(c.Writer, v) } diff --git a/internal/api/middleware/admin.go b/internal/api/middleware/admin.go index 41390bf0e..ec4019299 100644 --- a/internal/api/middleware/admin.go +++ b/internal/api/middleware/admin.go @@ -38,6 +38,22 @@ func (h *Handler) AdminMiddleware() gin.HandlerFunc { return } + // The admin panel is an internet-reachable administrative interface, so + // every account that reaches it has to have presented a second factor + // (CASA 3.3.1). Enforced on the session rather than on enrolment: an + // admin who has 2FA switched on but signed in before switching it on + // is still holding a single-factor session. + // + // This refuses admin routes only. The rest of the dashboard, including + // Settings > Security, stays reachable, which is what lets someone + // enrol and then come back. + if !session.MFAVerified { + errx.JSON(c, errx.NewWithIdentifier(errx.Forbidden, "admin_mfa_required", + "Administrative access requires two-factor authentication. Turn on 2FA or add a passkey under Settings > Security, then sign in again.")) + c.Abort() + return + } + // Store admin permissions in context c.Set(AdminPermissionsKey, perms) c.Set(AdminUserIDKey, session.UserID) diff --git a/internal/api/middleware/fresh_auth.go b/internal/api/middleware/fresh_auth.go new file mode 100644 index 000000000..bb13d73d9 --- /dev/null +++ b/internal/api/middleware/fresh_auth.go @@ -0,0 +1,54 @@ +package middleware + +import ( + "time" + + "github.com/gin-gonic/gin" + "github.com/warmbly/warmbly/internal/app/token" + "github.com/warmbly/warmbly/internal/errx" +) + +// RequireFreshAuth refuses a request whose session has not re-proved the +// account holder recently. +// +// CASA 2.4.1 asks for a full session plus re-authentication or a secondary +// check before a sensitive account change. Changing a password and disabling +// 2FA already demand a current credential; the actions gated here are the rest +// of that set. Each either hands out a credential that outlives the session +// that created it (an API key, a passkey registered to a device) or cannot be +// reversed by the person it was done to (ownership transfer, scheduled +// deletion), which is more than a live token alone should carry. +// +// The caller re-authenticates at POST /v1/auth/reauth and retries. +// +// This applies to session callers only. An API key and an OAuth token have no +// session and no way to present a second factor, and they are not the threat +// this addresses: the risk is a browser token lifted from a machine somebody +// walked away from. A key is already a deliberate, scoped, revocable grant that +// was itself minted from a confirmed session, its use is audited, and the +// permission gate on the route decides what it may do. Refusing them here would +// break every automation, the CLI included, to exceed what the control asks +// for. +func RequireFreshAuth() gin.HandlerFunc { + return func(c *gin.Context) { + if authType, _ := c.Get(AuthTypeKey); authType == AuthTypeAPIKey || authType == AuthTypeOAuth { + c.Next() + return + } + + session := GetSession(c) + if session == nil { + errx.JSON(c, errx.NewWithIdentifier(errx.Unauthorized, "reauth_required", + "This action needs a signed-in session. Sign in and try again.")) + c.Abort() + return + } + if session.ReauthAt == nil || time.Since(*session.ReauthAt) > token.ReauthWindow { + errx.JSON(c, errx.NewWithIdentifier(errx.Forbidden, "reauth_required", + "Confirm it is you before making this change.")) + c.Abort() + return + } + c.Next() + } +} diff --git a/internal/api/middleware/idempotency.go b/internal/api/middleware/idempotency.go index fd906b4cd..d569aed96 100644 --- a/internal/api/middleware/idempotency.go +++ b/internal/api/middleware/idempotency.go @@ -29,7 +29,7 @@ func (h *Handler) IdempotencyMiddleware() gin.HandlerFunc { return } if h.IdempotencyService == nil { - errx.Handle(c, errx.NewPublic(errx.ServiceUnavailable, "Idempotency service is not available.")) + errx.Handle(c, errx.New(errx.ServiceUnavailable, "idempotency service is not available")) c.Abort() return } diff --git a/internal/api/middleware/oidc.go b/internal/api/middleware/oidc.go index e1d775221..8bdc464b0 100644 --- a/internal/api/middleware/oidc.go +++ b/internal/api/middleware/oidc.go @@ -18,6 +18,11 @@ type OidcHandler struct { ServiceAccount string KeySet keyfunc.Keyfunc AppEnv string + // Audience is this instance's public URL, which Cloud Tasks puts in the + // token it mints for the webhook. Without it any token that service + // account holds for any audience is accepted here. Empty leaves the check + // off, for a deployment that cannot name its own URL. + Audience string } func (h *OidcHandler) Middleware() gin.HandlerFunc { @@ -43,7 +48,16 @@ func (h *OidcHandler) Middleware() gin.HandlerFunc { tokenStr := strings.TrimPrefix(auth, "Bearer ") - token, err := jwt.Parse(tokenStr, h.KeySet.Keyfunc, jwt.WithLeeway(10*time.Second)) + opts := []jwt.ParserOption{ + jwt.WithLeeway(10 * time.Second), + jwt.WithValidMethods([]string{"RS256"}), + jwt.WithExpirationRequired(), + } + if h.Audience != "" { + opts = append(opts, jwt.WithAudience(h.Audience)) + } + + token, err := jwt.Parse(tokenStr, h.KeySet.Keyfunc, opts...) if err != nil { errx.Handle(c, errx.ErrForbidden) return diff --git a/internal/api/middleware/poollink.go b/internal/api/middleware/poollink.go index fbdfc964d..35100cfd9 100644 --- a/internal/api/middleware/poollink.go +++ b/internal/api/middleware/poollink.go @@ -14,7 +14,7 @@ const PoolLinkInstanceKey = "pool_link_instance" func (h *Handler) PoolLinkAuthMiddleware() gin.HandlerFunc { return func(c *gin.Context) { if h.PoolLinkService == nil { - errx.JSON(c, errx.NewPublic(errx.NotImplemented, "Pool link is not enabled on this instance.")) + errx.JSON(c, errx.New(errx.NotImplemented, "pool link is not enabled on this instance")) c.Abort() return } diff --git a/internal/api/middleware/ratelimit_ip.go b/internal/api/middleware/ratelimit_ip.go index 579009f94..56ff58c23 100644 --- a/internal/api/middleware/ratelimit_ip.go +++ b/internal/api/middleware/ratelimit_ip.go @@ -27,14 +27,35 @@ const ( // allowance below covers two concurrent sign-ins from one NAT with slack. cliAuthIPWindow = 15 * time.Minute cliAuthIPDefaultLimit = 500 + + // The remaining public routes (unsubscribe, invitation preview, fleet + // enrolment, the analytics proxy) carry their authorization in a + // high-entropy token rather than a session, so this budget is not what + // stops an attacker reading someone else's data. It stops an unmetered + // write: every one of those requests reaches Postgres or an upstream, and + // none of them had a ceiling of any kind. It is deliberately loose, because + // a mail provider retrying one-click unsubscribe and an office behind one + // NAT opening invitations both look like bursts. + publicIPWindow = 15 * time.Minute + publicIPDefaultLimit = 600 ) +// PublicIPRateLimitMiddleware bounds the unauthenticated, token-addressed +// routes that sit outside the /auth group. +func (h *Handler) PublicIPRateLimitMiddleware() gin.HandlerFunc { + // Unlike the auth limiter this counts reads too: the invitation preview and + // the unsubscribe confirm page both reach Postgres, and the analytics proxy + // relays a request upstream whatever the method. + return h.ipRateLimiter("public_ip:", publicIPDefaultLimit, "PUBLIC_IP_RATE_LIMIT", publicIPWindow, + "Too many requests from this address. Try again shortly.", true) +} + // CLIAuthIPRateLimitMiddleware throttles the public CLI sign-in handshake per // source IP, on a key of its own so a long poll cannot lock the same address // out of signing in through the browser. func (h *Handler) CLIAuthIPRateLimitMiddleware() gin.HandlerFunc { return h.ipRateLimiter("cli_auth_ip:", cliAuthIPDefaultLimit, "CLI_AUTH_IP_RATE_LIMIT", cliAuthIPWindow, - "Too many CLI sign-in requests from this address. Try again later.") + "Too many CLI sign-in requests from this address. Try again later.", false) } // AuthIPRateLimitMiddleware throttles the public /auth group per source IP. @@ -49,12 +70,12 @@ func (h *Handler) CLIAuthIPRateLimitMiddleware() gin.HandlerFunc { // user out of their own instance. func (h *Handler) AuthIPRateLimitMiddleware() gin.HandlerFunc { return h.ipRateLimiter("auth_ip:", authIPDefaultLimit, "AUTH_IP_RATE_LIMIT", authIPWindow, - "Too many authentication attempts from this address. Try again later.") + "Too many authentication attempts from this address. Try again later.", false) } // ipRateLimiter is the shared fixed-window limiter behind both. Each caller // brings its own Redis key prefix, so budgets never bleed into each other. -func (h *Handler) ipRateLimiter(prefix string, defaultLimit int, env string, window time.Duration, message string) gin.HandlerFunc { +func (h *Handler) ipRateLimiter(prefix string, defaultLimit int, env string, window time.Duration, message string, countReads bool) gin.HandlerFunc { limit := defaultLimit if v := os.Getenv(env); v != "" { if parsed, err := strconv.Atoi(v); err == nil && parsed > 0 { @@ -67,8 +88,10 @@ func (h *Handler) ipRateLimiter(prefix string, defaultLimit int, env string, win c.Next() return } - // Reads are cheap and the login screen makes one on every load. - if c.Request.Method == http.MethodGet { + // Reads are cheap and the login screen makes one on every load, so the + // auth limiter lets them past. A limiter whose routes read the database + // on GET asks for them to be counted. + if !countReads && c.Request.Method == http.MethodGet { c.Next() return } diff --git a/internal/api/middleware/request_log.go b/internal/api/middleware/request_log.go new file mode 100644 index 000000000..87ae35602 --- /dev/null +++ b/internal/api/middleware/request_log.go @@ -0,0 +1,35 @@ +package middleware + +import ( + "fmt" + "io" + + "github.com/gin-gonic/gin" +) + +// RequestLogger is gin's standard access log with the query string removed. +// +// gin.Logger() prints the full request URI, and several routes carry a +// credential there because the provider or the mail client puts it there: +// OAuth `code` and `state` on the callback bouncers, the team invitation token +// on the preview lookup, the socket ticket on /v1/getaway's reply, the form +// prefill ticket. Those end up in stdout, in the container log, and in whatever +// aggregates it, which is a place none of them should reach. +// +// The path is kept because that is what the log is for. Nothing downstream +// needs the query: a request that has to be traced has X-Request-Id. +func RequestLogger() gin.HandlerFunc { + return gin.LoggerWithConfig(gin.LoggerConfig{ + Formatter: func(p gin.LogFormatterParams) string { + return fmt.Sprintf("[GIN] %v | %3d | %13v | %15s | %-7s %#v\n", + p.TimeStamp.Format("2006/01/02 - 15:04:05"), + p.StatusCode, + p.Latency, + p.ClientIP, + p.Method, + p.Path, + ) + }, + Output: io.Writer(gin.DefaultWriter), + }) +} diff --git a/internal/api/middleware/security_headers.go b/internal/api/middleware/security_headers.go new file mode 100644 index 000000000..ae9f52516 --- /dev/null +++ b/internal/api/middleware/security_headers.go @@ -0,0 +1,67 @@ +package middleware + +import ( + "strings" + + "github.com/gin-gonic/gin" +) + +// SecurityHeaders sets the response headers that tell a browser what it may do +// with an API response. None of them were being sent by any layer: not the Go +// services, not the nginx images, not the edge. +// +// The API answers JSON, so the policy can be the strictest one there is. It +// loads nothing, frames nothing, and may not be framed. That matters because +// the same origin also serves /public (customer uploads) and the OAuth bouncer +// pages, and those are the responses an attacker would want rendered. +// +// HSTS is only emitted on a request that actually arrived over TLS. Sending it +// over plain HTTP is ignored by browsers anyway, and a self-hosted instance +// deliberately running on a LAN without TLS must not be pinned to a scheme it +// does not serve. +func SecurityHeaders() gin.HandlerFunc { + return func(c *gin.Context) { + h := c.Writer.Header() + + // A browser must never guess a content type here: /public serves + // customer uploads from this origin. + h.Set("X-Content-Type-Options", "nosniff") + h.Set("X-Frame-Options", "DENY") + h.Set("Referrer-Policy", "strict-origin-when-cross-origin") + h.Set("Cross-Origin-Opener-Policy", "same-origin") + h.Set("Cross-Origin-Resource-Policy", "same-site") + h.Set("Permissions-Policy", "camera=(), microphone=(), geolocation=(), interest-cohort=()") + + // default-src 'none' suits a JSON API. The handful of routes that + // return HTML (the OAuth bouncers, the unsubscribe page) set their own + // policy over this one, and /public sets an image sandbox. + if _, already := h["Content-Security-Policy"]; !already { + h.Set("Content-Security-Policy", "default-src 'none'; frame-ancestors 'none'; base-uri 'none'; form-action 'none'") + } + + if requestIsHTTPS(c) { + h.Set("Strict-Transport-Security", "max-age=31536000; includeSubDomains") + } + + c.Next() + } +} + +// requestIsHTTPS reports whether the client reached us over TLS. Termination is +// always upstream (Railway, Caddy, nginx), so the forwarded header is the +// signal. +// +// The header is read directly: gin's trusted-proxy handling covers ClientIP, +// not arbitrary headers. That is acceptable here because the only thing it +// decides is whether to send HSTS, a browser cannot set the header on a request +// it makes, and a non-browser client that sets it receives a header it ignores. +// Nothing is authorized on this value. +func requestIsHTTPS(c *gin.Context) bool { + if c.Request.TLS != nil { + return true + } + if proto := c.GetHeader("X-Forwarded-Proto"); proto != "" { + return strings.EqualFold(strings.TrimSpace(strings.Split(proto, ",")[0]), "https") + } + return false +} diff --git a/internal/api/middleware/security_headers_test.go b/internal/api/middleware/security_headers_test.go new file mode 100644 index 000000000..28c8a5eed --- /dev/null +++ b/internal/api/middleware/security_headers_test.go @@ -0,0 +1,76 @@ +package middleware + +import ( + "net/http" + "net/http/httptest" + "testing" + + "github.com/gin-gonic/gin" +) + +func TestSecurityHeadersAreSet(t *testing.T) { + gin.SetMode(gin.TestMode) + r := gin.New() + r.Use(SecurityHeaders()) + r.GET("/x", func(c *gin.Context) { c.Status(http.StatusOK) }) + + w := httptest.NewRecorder() + r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/x", nil)) + + want := map[string]string{ + "X-Content-Type-Options": "nosniff", + "X-Frame-Options": "DENY", + "Referrer-Policy": "strict-origin-when-cross-origin", + "Cross-Origin-Opener-Policy": "same-origin", + "Cross-Origin-Resource-Policy": "same-site", + } + for k, v := range want { + if got := w.Header().Get(k); got != v { + t.Errorf("%s = %q, want %q", k, got, v) + } + } + if w.Header().Get("Content-Security-Policy") == "" { + t.Error("a default Content-Security-Policy should be set") + } +} + +// HSTS over plain HTTP is ignored by browsers and would pin a self-hosted LAN +// instance to a scheme it does not serve, so it is only sent on a TLS request. +func TestHSTSOnlyOverTLS(t *testing.T) { + gin.SetMode(gin.TestMode) + r := gin.New() + r.Use(SecurityHeaders()) + r.GET("/x", func(c *gin.Context) { c.Status(http.StatusOK) }) + + plain := httptest.NewRecorder() + r.ServeHTTP(plain, httptest.NewRequest(http.MethodGet, "/x", nil)) + if got := plain.Header().Get("Strict-Transport-Security"); got != "" { + t.Errorf("no HSTS expected over plain HTTP, got %q", got) + } + + forwarded := httptest.NewRecorder() + req := httptest.NewRequest(http.MethodGet, "/x", nil) + req.Header.Set("X-Forwarded-Proto", "https") + r.ServeHTTP(forwarded, req) + if got := forwarded.Header().Get("Strict-Transport-Security"); got == "" { + t.Error("HSTS expected when the edge reports https") + } +} + +// A handler that sets its own policy keeps it: the OAuth bouncer pages need +// script-src 'unsafe-inline' for the one script that is the page. +func TestHandlerCSPWins(t *testing.T) { + gin.SetMode(gin.TestMode) + r := gin.New() + r.Use(SecurityHeaders()) + r.GET("/page", func(c *gin.Context) { + c.Header("Content-Security-Policy", "default-src 'none'; script-src 'unsafe-inline'") + c.Status(http.StatusOK) + }) + + w := httptest.NewRecorder() + r.ServeHTTP(w, httptest.NewRequest(http.MethodGet, "/page", nil)) + if got := w.Header().Get("Content-Security-Policy"); got != "default-src 'none'; script-src 'unsafe-inline'" { + t.Errorf("handler policy should survive, got %q", got) + } +} diff --git a/internal/api/routes.go b/internal/api/routes.go index 826332389..dbf85e0c6 100644 --- a/internal/api/routes.go +++ b/internal/api/routes.go @@ -39,7 +39,7 @@ func Run( // ours, which reports the panic with its request context before returning // the same 500. Everything else about the pair is unchanged. r := gin.New() - r.Use(gin.Logger()) + r.Use(middleware.RequestLogger()) r.Use(middleware.Recovery()) // Gin trusts every proxy by default, which makes X-Forwarded-For (and so @@ -55,6 +55,10 @@ func Run( _ = r.SetTrustedProxies(nil) } + // Registered before every route, including the public ones below, so the + // headers reach the OAuth bouncer pages and /public as well as the API. + r.Use(middleware.SecurityHeaders()) + r.Use(middleware.RequestIDMiddleware()) r.Use(middleware.APIVersionMiddleware(middleware.APIVersion)) @@ -93,7 +97,7 @@ func Run( // token rather than an operator session, because the machine running it // has no credentials yet. r.GET("/join.sh", h.ServeJoinScript) - r.POST("/api/v1/fleet/join", h.FleetJoin) + r.POST("/api/v1/fleet/join", m.PublicIPRateLimitMiddleware(), h.FleetJoin) // Public OAuth-bouncer pages used by the mailbox onboarding popup. // The provider redirects here; the page postMessages the code/state @@ -109,13 +113,13 @@ func Run( // Public recipient unsubscribe (RFC 8058 one-click and the link in the // email). The path token is signed per recipient; GET only shows a // confirm page, POST suppresses. Unauthenticated by design. - r.GET("/unsubscribe/:token", h.UnsubscribePage) - r.POST("/unsubscribe/:token", h.UnsubscribeSubmit) - r.POST("/unsubscribe/:token/resubscribe", h.UnsubscribeUndo) + r.GET("/unsubscribe/:token", m.PublicIPRateLimitMiddleware(), h.UnsubscribePage) + r.POST("/unsubscribe/:token", m.PublicIPRateLimitMiddleware(), h.UnsubscribeSubmit) + r.POST("/unsubscribe/:token/resubscribe", m.PublicIPRateLimitMiddleware(), h.UnsubscribeUndo) // Public invitation preview for the /invite landing page. Unauthenticated: // the secret token in the query is the capability. - r.GET("/invitations/lookup", h.PreviewInvitation) + r.GET("/invitations/lookup", m.PublicIPRateLimitMiddleware(), h.PreviewInvitation) // On-demand TLS gate for the reverse proxy in front of this instance // (Caddy's `ask`). Unauthenticated because the proxy has no credential to @@ -126,7 +130,7 @@ func Run( // PostHog reverse proxy. Content blockers drop requests to posthog.com, so // the frontends are pointed here and this forwards them. Public by // necessity: it serves the browser before anyone has signed in. - r.Any("/ingest/*path", h.PostHogProxy) + r.Any("/ingest/*path", m.PublicIPRateLimitMiddleware(), h.PostHogProxy) // Internal backend-to-backend endpoints. Workers call these instead of // touching Postgres directly, per the no-direct-data-services rule in @@ -401,12 +405,21 @@ func Run( protectedAuth.POST("/2fa/enroll/confirm", h.TwoFAEnrollConfirm) protectedAuth.DELETE("/2fa", h.TwoFADisable) + // Re-prove the account holder behind a live session. What the routes + // marked RequireFreshAuth below are waiting for. + protectedAuth.POST("/reauth", h.Reauth) + // Passkey enrollment + management require an authenticated session. - protectedAuth.POST("/passkey/register/begin", h.PasskeyRegisterBegin) - protectedAuth.POST("/passkey/register/finish", h.PasskeyRegisterFinish) + // + // Registering a passkey adds a credential that signs in on its own, so + // it is a sensitive change in the CASA 2.4.1 sense: a stolen token must + // not be enough to leave a permanent way back in. Listing and renaming + // are not. + protectedAuth.POST("/passkey/register/begin", middleware.RequireFreshAuth(), h.PasskeyRegisterBegin) + protectedAuth.POST("/passkey/register/finish", middleware.RequireFreshAuth(), h.PasskeyRegisterFinish) protectedAuth.GET("/passkey/credentials", h.PasskeyListCredentials) protectedAuth.PATCH("/passkey/credentials/:id", h.PasskeyRenameCredential) - protectedAuth.DELETE("/passkey/credentials/:id", h.PasskeyDeleteCredential) + protectedAuth.DELETE("/passkey/credentials/:id", middleware.RequireFreshAuth(), h.PasskeyDeleteCredential) } // The full customer-facing API surface (the API-key-capable `protected` @@ -836,7 +849,11 @@ func Run( apiKeys.Use(m.RateLimitMiddleware(models.RateLimitWrite)) { apiKeys.GET("", h.ListAPIKeys) - apiKeys.POST("", h.CreateAPIKey) + // A new key is a durable credential that outlives the session + // that made it, so a session caller confirms first. A key or + // OAuth caller has no session to confirm and passes through to + // the permission gate. + apiKeys.POST("", middleware.RequireFreshAuth(), h.CreateAPIKey) apiKeys.GET("/permissions", h.ListAPIPermissions) apiKeys.GET("/usage/summary", h.GetAPIKeyUsageSummary) apiKeys.GET("/usage/analytics", h.GetAPIKeyAnalytics) @@ -1216,7 +1233,7 @@ func Run( org.DELETE("/invitations/:id", m.RequireOrganization(), m.RequirePermission(models.PermManageTeam), h.CancelInvitation) org.GET("/invitations/:id/link", m.RequireOrganization(), m.RequirePermission(models.PermManageTeam), h.GetInvitationLink) - org.POST("/transfer-ownership", m.RequireOrganization(), m.RequirePermission(models.PermTransferOwnership), h.TransferOwnership) + org.POST("/transfer-ownership", m.RequireOrganization(), m.RequirePermission(models.PermTransferOwnership), middleware.RequireFreshAuth(), h.TransferOwnership) org.POST("/avatar", m.RequireOrganization(), h.UploadOrganizationAvatar) org.DELETE("/avatar", m.RequireOrganization(), h.DeleteOrganizationAvatar) @@ -1238,7 +1255,7 @@ func Run( org.GET("/current/import/:id", m.RequireOrganization(), h.GetOrgImport) org.GET("/current/danger-zone", m.RequireOrganization(), h.GetOrganizationDangerZone) - org.POST("/current/danger-zone/delete", m.RequireOrganization(), h.ScheduleOrganizationDeletion) + org.POST("/current/danger-zone/delete", m.RequireOrganization(), middleware.RequireFreshAuth(), h.ScheduleOrganizationDeletion) org.DELETE("/current/danger-zone/delete", m.RequireOrganization(), h.CancelOrganizationDeletion) // Customer-facing limit-increase requests. The "current @@ -1279,7 +1296,7 @@ func Run( account := jwtOnly.Group("/me") { account.GET("/danger-zone", h.GetAccountDangerZone) - account.POST("/danger-zone/delete", h.ScheduleAccountDeletion) + account.POST("/danger-zone/delete", middleware.RequireFreshAuth(), h.ScheduleAccountDeletion) account.DELETE("/danger-zone/delete", h.CancelAccountDeletion) } diff --git a/internal/app/admin/service.go b/internal/app/admin/service.go index fd33c633e..d817b62ab 100644 --- a/internal/app/admin/service.go +++ b/internal/app/admin/service.go @@ -74,10 +74,20 @@ type AdminService interface { LogAdminAction(ctx context.Context, adminID uuid.UUID, action, targetType string, targetID *uuid.UUID, details map[string]any, ipAddress, userAgent string) } +// SessionRevoker ends a user's live sessions. Implemented by the token +// service, which also clears the Redis session cache: a database-only revoke +// stays invisible to every request served from cache, which is most of them. +type SessionRevoker interface { + RevokeOtherSessions(ctx context.Context, userID, currentSessionID uuid.UUID) *errx.Error +} + type adminService struct { repo repository.AdminRepository // The owner-visible campaign activity feed. campaignLogRepo repository.CampaignLogRepository + // sessions ends a banned user's live sessions. Nil-safe: without it a ban + // still lands, it just does not take effect until the tokens expire. + sessions SessionRevoker } // NewService creates a new admin service @@ -85,6 +95,9 @@ func NewService(repo repository.AdminRepository, campaignLogRepo repository.Camp return &adminService{repo: repo, campaignLogRepo: campaignLogRepo} } +// WithSessionRevoker wires the session revoker used when a login ban lands. +func (s *adminService) WithSessionRevoker(r SessionRevoker) { s.sessions = r } + // logAction logs an admin action func (s *adminService) logAction(ctx context.Context, adminID uuid.UUID, action, targetType string, targetID uuid.UUID, details map[string]any, ipAddress, userAgent string) { log := &models.AdminAuditLog{ @@ -199,6 +212,18 @@ func (s *adminService) BanUser(ctx context.Context, adminID, userID uuid.UUID, r return errx.New(errx.Internal, "failed to ban user") } + // A login ban that leaves live sessions alone bans nothing for up to twelve + // hours: the access token keeps working, the refresh token mints new ones + // from it, and the websocket keeps streaming. uuid.Nil matches no session, + // so every one of them is revoked. + if models.BanScope(scope).Has(models.BanScopeLogin) && s.sessions != nil { + if rerr := s.sessions.RevokeOtherSessions(ctx, userID, uuid.Nil); rerr != nil { + // The ban is already recorded; report the leftover sessions rather + // than failing the ban and leaving the account unbanned. + errs.CaptureException(rerr) + } + } + s.logAction(ctx, adminID, "ban_user", "user", userID, map[string]any{"reason": reason, "scope": uint32(scope)}, ipAddress, userAgent) return nil } @@ -570,6 +595,22 @@ func (s *adminService) GrantAdminPermissions(ctx context.Context, adminID, targe return errx.New(errx.BadRequest, "cannot modify your own permissions") } + // An admin may only hand out permissions they hold themselves, so holding + // grant_admin_access is not by itself a route to every other bit, directly + // or in two hops through a colleague. A super admin holds every bit, so this + // never blocks them. + granter, gerr := s.repo.GetUserDetail(ctx, adminID) + if gerr != nil { + errs.CaptureException(gerr) + return errx.New(errx.Internal, "failed to check admin permissions") + } + if granter == nil { + return errx.ErrForbidden + } + if permissions&^granter.AdminPermissions != 0 { + return errx.New(errx.Forbidden, "cannot grant an admin permission you do not hold yourself") + } + if err := s.repo.UpdateUserAdminPermissions(ctx, targetUserID, uint32(permissions), adminID); err != nil { errs.CaptureException(err) return errx.New(errx.Internal, "failed to grant admin permissions") @@ -585,6 +626,25 @@ func (s *adminService) RevokeAdminPermissions(ctx context.Context, adminID, targ return errx.New(errx.BadRequest, "cannot modify your own permissions") } + // Refuse to remove the last super admin. warmblyctl already guards this; + // the API did not, so the instance could be left with nobody able to grant + // admin access back, recoverable only with database access. + target, terr := s.repo.GetUserDetail(ctx, targetUserID) + if terr != nil { + errs.CaptureException(terr) + return errx.New(errx.Internal, "failed to load user") + } + if target != nil && target.AdminPermissions.IsSuperAdmin() { + remaining, cerr := s.repo.CountSuperAdmins(ctx) + if cerr != nil { + errs.CaptureException(cerr) + return errx.New(errx.Internal, "failed to count admins") + } + if remaining <= 1 { + return errx.New(errx.BadRequest, "this is the last super admin; grant another one before revoking this one") + } + } + if err := s.repo.UpdateUserAdminPermissions(ctx, targetUserID, 0, adminID); err != nil { errs.CaptureException(err) return errx.New(errx.Internal, "failed to revoke admin permissions") diff --git a/internal/app/advanced/service.go b/internal/app/advanced/service.go index b1f3314c2..0dc7377d4 100644 --- a/internal/app/advanced/service.go +++ b/internal/app/advanced/service.go @@ -1570,6 +1570,60 @@ func ptrTime(t time.Time) *time.Time { return &t } +// verifyEventOwnership refuses a deliverability event whose campaign, contact +// or task belongs to another organization. Anything absent is fine; anything +// present has to resolve inside the caller's workspace. +func (s *service) verifyEventOwnership(ctx context.Context, organizationID uuid.UUID, req *models.IngestDeliverabilityEventRequest) *errx.Error { + foreign := errx.New(errx.NotFound, "campaign, contact or task not found") + + if req.CampaignID != nil { + campaign, err := s.campaignRepo.GetByID(ctx, *req.CampaignID) + if err != nil || campaign == nil || campaign.OrganizationID == nil || *campaign.OrganizationID != organizationID { + return foreign + } + } + + if req.ContactID != nil { + owned, xerr := s.contactRepo.GetByIDsAndOrganization(ctx, organizationID, []uuid.UUID{*req.ContactID}) + if xerr != nil || len(owned) == 0 { + return foreign + } + } + + if req.TaskID != nil { + ct, err := s.taskRepo.GetCampaignTask(ctx, *req.TaskID) + switch { + case err == nil && ct != nil && ct.CampaignID != nil: + // The task names its own campaign, so the pair has to agree: a real + // task id combined with a different campaign id describes a step + // that does not exist. + if req.CampaignID != nil && *ct.CampaignID != *req.CampaignID { + return foreign + } + taskCampaign, cErr := s.campaignRepo.GetByID(ctx, *ct.CampaignID) + if cErr != nil || taskCampaign == nil || taskCampaign.OrganizationID == nil || *taskCampaign.OrganizationID != organizationID { + return foreign + } + default: + // Not every task belongs to a campaign: a test send and an inbound + // bounce resolved by message id both reach here with a task that has + // no campaign row. Those still have to belong to the caller, so + // fall back to the mailbox that owns the task rather than refusing + // and silently dropping real bounce processing. + task, tErr := s.taskRepo.GetTask(ctx, *req.TaskID) + if tErr != nil || task == nil { + return foreign + } + account, aErr := s.emailRepo.GetByID(ctx, task.EmailAccountID) + if aErr != nil || account == nil || account.OrganizationID == nil || *account.OrganizationID != organizationID { + return foreign + } + } + } + + return nil +} + func (s *service) IngestDeliverabilityEvent(ctx context.Context, organizationID uuid.UUID, req *models.IngestDeliverabilityEventRequest) *errx.Error { if req == nil { return errx.New(errx.BadRequest, "event payload is required") @@ -1590,6 +1644,16 @@ func (s *service) IngestDeliverabilityEvent(ctx context.Context, organizationID return errx.New(errx.BadRequest, "invalid event_type") } + // Every id in the body is caller-supplied, and a campaign, contact and task + // id are all visible to the recipient of a campaign email: the task id is in + // the tracking pixel URL. They therefore prove nothing on their own, and + // each has to be resolved inside the caller's workspace before this event is + // allowed to move progress counters, A/B assignment, the auto-pause breaker + // or warmup health. + if xerr := s.verifyEventOwnership(ctx, organizationID, req); xerr != nil { + return xerr + } + idempotencyKey := strings.TrimSpace(req.IdempotencyKey) if idempotencyKey == "" { idempotencyKey = uuid.NewString() diff --git a/internal/app/advisor/fixer.go b/internal/app/advisor/fixer.go index 796b47e1e..7436096c9 100644 --- a/internal/app/advisor/fixer.go +++ b/internal/app/advisor/fixer.go @@ -136,7 +136,7 @@ var fixTools = map[models.AdvisorCategory][]string{ // FixWithAgent resolves one finding by running a bounded agent against it. func (s *service) FixWithAgent(ctx context.Context, inv aitools.Invocation, id uuid.UUID) (*models.AdvisorAgentResult, *errx.Error) { if s.agent == nil || s.toolList == nil { - return nil, errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured on this server.") + return nil, errx.New(errx.ServiceUnavailable, "the AI assistant is not configured on this server") } f, xerr := s.Get(ctx, inv.OrgID, id) if xerr != nil { diff --git a/internal/app/aiagent/service.go b/internal/app/aiagent/service.go index 3bd9a275a..61ae331d8 100644 --- a/internal/app/aiagent/service.go +++ b/internal/app/aiagent/service.go @@ -326,7 +326,7 @@ var ( func (s *service) RunMessage(ctx context.Context, inv aitools.Invocation, sessionID uuid.UUID, messageID, text, page, resource string, emit func(StreamEvent)) *errx.Error { if s.provider == nil { - return errx.NewPublic(errx.ServiceUnavailable, "The AI assistant is not configured.") + return errx.New(errx.ServiceUnavailable, "the AI assistant is not configured") } owner := s.sessionScope(ctx, inv.OrgID, inv.UserID, sessionID) sess, err := s.repo.GetSession(ctx, inv.OrgID, owner, sessionID) diff --git a/internal/app/aitools/tools_apikeys.go b/internal/app/aitools/tools_apikeys.go index 8612d6f0d..3706cf8f7 100644 --- a/internal/app/aitools/tools_apikeys.go +++ b/internal/app/aitools/tools_apikeys.go @@ -3,6 +3,7 @@ package aitools import ( "context" "encoding/json" + "errors" "github.com/warmbly/warmbly/internal/models" "github.com/warmbly/warmbly/internal/pkg/generation" @@ -88,32 +89,20 @@ func (d Deps) listAPIKeys(ctx context.Context, inv Invocation, args json.RawMess return jsonResult(res) } -func (d Deps) createAPIKey(ctx context.Context, inv Invocation, args json.RawMessage) (string, error) { - in, err := decodeArgs[struct { - Name string `json:"name"` - Description *string `json:"description"` - Preset string `json:"preset"` - }](args) - if err != nil { - return "", err - } - if in.Name == "" { - return "", ErrInvalidArgs - } - perms := models.APIPermReadOnly - if in.Preset == "full_access" { - perms = models.APIPermFullAccess - } - key, xerr := d.APIKeys.Create(ctx, inv.OrgID, inv.UserID, &models.CreateAPIKey{ - Name: in.Name, - Description: in.Description, - Permissions: perms, - }) - if xerr != nil { - return "", fromErrx(xerr) - } - d.logAudit(ctx, inv, models.AuditActionCreate, models.AuditEntityAPIKey, &key.ID, map[string]string{"name": in.Name}) - return jsonResult(key) +// createAPIKey refuses, deliberately. +// +// Creating a key through the API requires a confirmation newer than the session +// (RequireFreshAuth on POST /api-keys), because a key outlives the session that +// made it and a stolen token must not be able to leave a durable credential +// behind. This tool reaches the service directly, so honouring it would be a +// way around that gate. +// +// It stays registered rather than being removed so the assistant can say what +// to do instead of reporting an unknown tool. +func (d Deps) createAPIKey(_ context.Context, _ Invocation, _ json.RawMessage) (string, error) { + return "", errors.New( + "creating an API key needs you to confirm it is you, and that cannot be collected in a chat. " + + "Open Settings > API keys in the dashboard and create it there") } func (d Deps) updateAPIKey(ctx context.Context, inv Invocation, args json.RawMessage) (string, error) { diff --git a/internal/app/aitools/tools_contacts.go b/internal/app/aitools/tools_contacts.go index 2ff8e4cd1..4dbce9e1d 100644 --- a/internal/app/aitools/tools_contacts.go +++ b/internal/app/aitools/tools_contacts.go @@ -273,7 +273,7 @@ func (d Deps) getContactSentEmails(ctx context.Context, inv Invocation, args jso if limit <= 0 || limit > 100 { limit = 50 } - res, xerr := d.Contacts.ListSentEmails(ctx, inv.UserID, cid, limit, nil, nil) + res, xerr := d.Contacts.ListSentEmails(ctx, inv.OrgID, cid, limit, nil, nil) if xerr != nil { return "", fromErrx(xerr) } diff --git a/internal/app/aitools/tools_mailboxes.go b/internal/app/aitools/tools_mailboxes.go index 091dc68a0..38ccae30e 100644 --- a/internal/app/aitools/tools_mailboxes.go +++ b/internal/app/aitools/tools_mailboxes.go @@ -290,7 +290,7 @@ func (d Deps) disconnectMailbox(ctx context.Context, inv Invocation, args json.R if err != nil { return "", err } - if xerr := d.Emails.Delete(ctx, inv.OrgID.String(), in.EmailAccountID); xerr != nil { + if xerr := d.Emails.Delete(ctx, inv.UserID.String(), in.EmailAccountID); xerr != nil { return "", fromErrx(xerr) } d.logAudit(ctx, inv, models.AuditActionDisconnect, models.AuditEntityEmailAccount, &aid, nil) diff --git a/internal/app/aitools/tools_team.go b/internal/app/aitools/tools_team.go index 6f737eb04..5b1f1c4cf 100644 --- a/internal/app/aitools/tools_team.go +++ b/internal/app/aitools/tools_team.go @@ -222,7 +222,7 @@ func (d Deps) cancelInvitation(ctx context.Context, inv Invocation, args json.Ra if err != nil { return "", err } - if xerr := d.Org.CancelInvitation(ctx, iid); xerr != nil { + if xerr := d.Org.CancelInvitation(ctx, inv.OrgID, iid); xerr != nil { return "", fromErrx(xerr) } d.logAudit(ctx, inv, models.AuditActionRemove, models.AuditEntityInvitation, &iid, nil) diff --git a/internal/app/analytics/warmup_ramp_live_test.go b/internal/app/analytics/warmup_ramp_live_test.go index ccb80c8f3..f02f5434c 100644 --- a/internal/app/analytics/warmup_ramp_live_test.go +++ b/internal/app/analytics/warmup_ramp_live_test.go @@ -60,12 +60,7 @@ func newRampFixture(t *testing.T, daysWarming, base, increase, max int) *rampFix VALUES ($1, $2, $3, $4, 'Ramp', '', '', 'smtp_imap', 'active', 50, 600, 'UTC', $5, $6, $7, $8)`, f.mailbox, f.user, f.org, "ramp-"+f.mailbox.String()[:8]+"@test.local", - // The column is timestamp without time zone and the app anchors it - // with the database's now(); pgx writes a local time's wall clock, so - // on a machine east of UTC the anchor lands hours late and the ramp - // reads a day short. A few hours into the day, not on its boundary, - // so a freeze shorter than a day cannot cross it either. - time.Now().UTC().Add(-time.Duration(daysWarming)*24*time.Hour-6*time.Hour), base, increase, max) + time.Now().Add(-time.Duration(daysWarming)*24*time.Hour), base, increase, max) t.Cleanup(func() { c := context.Background() diff --git a/internal/app/auth/cache.go b/internal/app/auth/cache.go index 1d08cfdd6..cb1fac36a 100644 --- a/internal/app/auth/cache.go +++ b/internal/app/auth/cache.go @@ -32,6 +32,22 @@ func getPasswordResetLimitKey(email string) string { return "password_reset_limit:" + crypt.SHA256(email) } +// getLoginFailureKey counts wrong passwords for one address. Keyed on the +// address rather than the user id because the lookup that would resolve the id +// is the thing being throttled, and a miss must cost the guesser the same as a +// hit. +func getLoginFailureKey(email string) string { + return "login_fail:" + crypt.SHA256(email) +} + +// getReauthFailureKey counts failed confirmations for one account. The +// re-authentication endpoint checks a password, so without its own budget it is +// a second, unthrottled place to guess one: the per-IP limiter allows a few +// hundred an hour and the per-account login counter does not see this path. +func getReauthFailureKey(userID uuid.UUID) string { + return "reauth_fail:" + userID.String() +} + func getLoginSessionKey(sessionID uuid.UUID) string { return "login_sess:" + sessionID.String() } @@ -259,3 +275,78 @@ func (s *authService) deletePasswordResetSession(ctx context.Context, sessionID return nil } + +// loginFailureExceeded reports whether this address has spent its hourly budget +// of wrong passwords. It fails OPEN on a cache error: the limiter is a brake on +// guessing, and a Redis outage must not lock every customer out of their own +// account. +func (s *authService) loginFailureExceeded(ctx context.Context, email string) bool { + count, err := s.cache.Get(ctx, getLoginFailureKey(email)).Int64() + if err != nil { + if !errors.Is(err, redis.Nil) { + errs.CaptureException(err) + } + return false + } + return count >= LoginFailureLimit +} + +// recordLoginFailure charges one wrong password to the address. +func (s *authService) recordLoginFailure(ctx context.Context, email string) { + key := getLoginFailureKey(email) + count, err := s.cache.Incr(ctx, key).Result() + if err != nil { + errs.CaptureException(err) + return + } + if count == 1 { + if err := s.cache.Expire(ctx, key, LoginFailureTTL).Err(); err != nil { + errs.CaptureException(err) + } + } +} + +// clearLoginFailures forgives the count once the right password arrives, so a +// person who mistypes a few times and then gets it right starts clean. +func (s *authService) clearLoginFailures(ctx context.Context, email string) { + if err := s.cache.Del(ctx, getLoginFailureKey(email)).Err(); err != nil { + errs.CaptureException(err) + } +} + +// ReauthFailureExceeded reports whether this account has spent its budget of +// failed confirmations. Fails open on a cache error, like the login counter: +// the budget is a brake on guessing, and a Redis outage must not stop someone +// confirming their own change. +func (s *authService) ReauthFailureExceeded(ctx context.Context, userID uuid.UUID) bool { + count, err := s.cache.Get(ctx, getReauthFailureKey(userID)).Int64() + if err != nil { + if !errors.Is(err, redis.Nil) { + errs.CaptureException(err) + } + return false + } + return count >= LoginFailureLimit +} + +// RecordReauthFailure charges one failed confirmation to the account. +func (s *authService) RecordReauthFailure(ctx context.Context, userID uuid.UUID) { + key := getReauthFailureKey(userID) + count, err := s.cache.Incr(ctx, key).Result() + if err != nil { + errs.CaptureException(err) + return + } + if count == 1 { + if err := s.cache.Expire(ctx, key, LoginFailureTTL).Err(); err != nil { + errs.CaptureException(err) + } + } +} + +// ClearReauthFailures forgives the count once a confirmation succeeds. +func (s *authService) ClearReauthFailures(ctx context.Context, userID uuid.UUID) { + if err := s.cache.Del(ctx, getReauthFailureKey(userID)).Err(); err != nil { + errs.CaptureException(err) + } +} diff --git a/internal/app/auth/config.go b/internal/app/auth/config.go index 93d4d83af..83d799c77 100644 --- a/internal/app/auth/config.go +++ b/internal/app/auth/config.go @@ -4,9 +4,26 @@ import "time" const ( SessionTTL = 10 * time.Minute - AuthLimit = 45 * time.Minute AuthAttempts = 3 + // LoginFailureLimit and LoginFailureTTL bound password guessing against one + // account, which the per-IP limiter cannot: a guesser with a botnet spends a + // fresh 60-request budget per source address while the account it is aimed + // at counts nothing. + // + // The figure is the 100 per hour CASA 1.1.1 names, not something tighter. A + // counter keyed on an address is a lockout anyone can trigger by typing a + // wrong password at somebody else's account, so the number has to sit above + // what a person hits by mistake and below what a guesser needs. Ten was + // both: within reach of a shared office retyping a password, and cheap to + // aim at a known address. + // + // The count is also cleared by a correct password and by a completed + // password reset, so someone locked out has two ways back that do not + // involve waiting, and an attacker cannot hold the lock open. + LoginFailureLimit = 100 + LoginFailureTTL = 1 * time.Hour + AuthSessionTTL = 10 * time.Minute AuthEmailTTL = 30 * time.Minute AuthEmailLimit = 5 diff --git a/internal/app/auth/gen.go b/internal/app/auth/gen.go index 0792f6cb9..6e8ec6f14 100644 --- a/internal/app/auth/gen.go +++ b/internal/app/auth/gen.go @@ -5,6 +5,7 @@ import ( "time" "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/app/token" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/models" "github.com/warmbly/warmbly/internal/observability/errs" @@ -32,7 +33,7 @@ func (s *authService) GenerateLoginSession(ctx context.Context, userID uuid.UUID return "", err } - sessionToken, err := s.tokenService.GenerateToken(userID, sessID, "", "", issuedAt, expiresAt) + sessionToken, err := s.tokenService.GenerateTokenFor(token.PurposeLoginCode, userID, sessID, "", "", issuedAt, expiresAt) if err != nil { errs.CaptureException(err) return "", errx.InternalError() diff --git a/internal/app/auth/login.go b/internal/app/auth/login.go index 5af19d05d..e5ead7d69 100644 --- a/internal/app/auth/login.go +++ b/internal/app/auth/login.go @@ -2,6 +2,7 @@ package auth import ( "context" + "errors" "github.com/warmbly/warmbly/internal/app/authrisk" "time" @@ -31,10 +32,20 @@ func (s *authService) LoginStart(ctx context.Context, data *AuthData, ipaddr, us // this string, so it is folded once here rather than at each of them. data.Email = normalizeEmail(data.Email) + // Spent budgets are refused before the hash comparison, so a guesser past + // the limit cannot even measure argon2's timing. + if s.loginFailureExceeded(ctx, data.Email) { + return nil, errx.ErrAuthLimit + } + uid, err := s.authRepository.IsValidCredentials(ctx, data.Email, data.Password) if err != nil { + if errors.Is(err, errx.ErrCredentials) { + s.recordLoginFailure(ctx, data.Email) + } return nil, err } + s.clearLoginFailures(ctx, data.Email) // The emailed code is a step in the login, not a second factor: NIST // SP 800-63B and OWASP ASVS both decline to count email as one. When it is @@ -101,7 +112,7 @@ func (s *authService) LoginStart(ctx context.Context, data *AuthData, ipaddr, us AnomalyReason: verdict.Reason, } - sessionToken, xerr := s.tokenService.GenerateToken(uid, sessionID, "", nonce, issuedAt, expiresAt) + sessionToken, xerr := s.tokenService.GenerateTokenFor(token.PurposeLoginCode, uid, sessionID, "", nonce, issuedAt, expiresAt) if xerr != nil { errs.CaptureException(xerr) return nil, errx.InternalError() @@ -149,7 +160,7 @@ func (s *authService) loginCodeRequired(ctx context.Context, userID uuid.UUID, u } func (s *authService) LoginConfirm(ctx context.Context, data *ConfirmData, session, ipaddr string, userAgent string) (*models.LoginResult, *errx.Error) { - atoken, err := s.tokenService.VerifyToken(session) + atoken, err := s.tokenService.VerifyTokenFor(token.PurposeLoginCode, session) if err != nil { return nil, err } diff --git a/internal/app/auth/registration.go b/internal/app/auth/registration.go index 16339dbb3..2a62a3c90 100644 --- a/internal/app/auth/registration.go +++ b/internal/app/auth/registration.go @@ -5,6 +5,7 @@ import ( "time" "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/app/token" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/models" "github.com/warmbly/warmbly/internal/notify/templates" @@ -32,8 +33,8 @@ func (s *authService) RegistrationStart(ctx context.Context, data *AuthData, ori return nil, xerr } - if !crypt.ValidatePassword(data.Password) { - return nil, errx.ErrPassword + if perr := crypt.PasswordError(data.Password); perr != nil { + return nil, perr } passwordHash, xerr := argon2.Hash(data.Password) @@ -111,7 +112,7 @@ func (s *authService) RegistrationStart(ctx context.Context, data *AuthData, ori return nil, err } - sessionToken, xerr := s.tokenService.GenerateToken(uuid.Nil, sessionID, data.Email, nonce, issuedAt, expiresAt) + sessionToken, xerr := s.tokenService.GenerateTokenFor(token.PurposeRegistration, uuid.Nil, sessionID, data.Email, nonce, issuedAt, expiresAt) if xerr != nil { errs.CaptureException(xerr) return nil, errx.InternalError() @@ -124,18 +125,18 @@ func (s *authService) RegistrationStart(ctx context.Context, data *AuthData, ori } func (s *authService) RegistrationConfirm(ctx context.Context, data *ConfirmData, session string, origin SignupOrigin) (*models.AuthSession, *errx.Error) { - token, err := s.tokenService.VerifyToken(session) + claims, err := s.tokenService.VerifyTokenFor(token.PurposeRegistration, session) if err != nil { return nil, err } - if token.ExpiresAt.Before(time.Now()) { + if claims.ExpiresAt.Before(time.Now()) { return nil, errx.ErrSession } - sess, err := s.getRegistrationSession(ctx, token.SessionID) + sess, err := s.getRegistrationSession(ctx, claims.SessionID) if err != nil { return nil, err } - if sess == nil || sess.Nonce != token.Nonce { + if sess == nil || sess.Nonce != claims.Nonce { return nil, errx.ErrSession } @@ -151,13 +152,13 @@ func (s *authService) RegistrationConfirm(ctx context.Context, data *ConfirmData if !v { sess.Tries++ - _ = s.saveRegistrationSession(ctx, token.SessionID, sess, token.ExpiresAt.Time) + _ = s.saveRegistrationSession(ctx, claims.SessionID, sess, claims.ExpiresAt.Time) return nil, errx.ErrCode } // Re-check the policy: a session minted while signups were open must not // outlive a lockdown applied before the code came back. - if err := s.signupAllowed(ctx, token.Email, sess.Invite); err != nil { + if err := s.signupAllowed(ctx, claims.Email, sess.Invite); err != nil { return nil, err } @@ -165,7 +166,7 @@ func (s *authService) RegistrationConfirm(ctx context.Context, data *ConfirmData if sess.Acquisition != nil { attr.Acquisition = *sess.Acquisition } - u, cerr := s.createAccount(ctx, token.Email, sess.PasswordHash, attr, origin) + u, cerr := s.createAccount(ctx, claims.Email, sess.PasswordHash, attr, origin) if cerr != nil { return nil, cerr } diff --git a/internal/app/auth/reset_password.go b/internal/app/auth/reset_password.go index c3cc86b88..f8b9da259 100644 --- a/internal/app/auth/reset_password.go +++ b/internal/app/auth/reset_password.go @@ -7,6 +7,7 @@ import ( "github.com/google/uuid" "github.com/rs/zerolog/log" + tokenpkg "github.com/warmbly/warmbly/internal/app/token" "github.com/warmbly/warmbly/internal/config" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/notify/templates" @@ -83,7 +84,7 @@ func (s *authService) startPasswordReset(ctx context.Context, data *ResetPasswor issuedAt := time.Now() expiresAt := issuedAt.Add(PasswordResetTTL) - token, err := s.tokenService.GenerateToken(user.ID, sessionID, data.Email, nonce, issuedAt, expiresAt) + token, err := s.tokenService.GenerateTokenFor(tokenpkg.PurposePasswordReset, user.ID, sessionID, data.Email, nonce, issuedAt, expiresAt) if err != nil { errs.CaptureException(err) return errx.InternalError() @@ -139,7 +140,7 @@ func (s *authService) ResetPasswordConfirm(ctx context.Context, data *ResetPassw return err } - sess, err := s.tokenService.VerifyToken(session) + sess, err := s.tokenService.VerifyTokenFor(tokenpkg.PurposePasswordReset, session) if err != nil { return err } @@ -161,8 +162,13 @@ func (s *authService) ResetPasswordConfirm(ctx context.Context, data *ResetPassw return err } - if !crypt.ValidatePassword(data.Password) { - return errx.ErrPassword + // Proving control of the mailbox clears any lockout that wrong passwords + // accumulated, so a person who was locked out is not still locked out after + // resetting, and an attacker cannot keep the lock on by guessing. + s.clearLoginFailures(ctx, normalizeEmail(sess.Email)) + + if perr := crypt.PasswordError(data.Password); perr != nil { + return perr } passwordHash, hashErr := argon2.Hash(data.Password) @@ -209,8 +215,8 @@ func (s *authService) ChangePassword(ctx context.Context, userID, currentSession return errx.ErrCredentials } - if !crypt.ValidatePassword(data.NewPassword) { - return errx.ErrPassword + if perr := crypt.PasswordError(data.NewPassword); perr != nil { + return perr } if data.NewPassword == data.CurrentPassword { return errx.New(errx.BadRequest, "the new password must be different") @@ -237,3 +243,8 @@ func (s *authService) ChangePassword(ctx context.Context, userID, currentSession } return nil } + +// PasswordHashFor returns the stored argon2 hash for a user. +func (s *authService) PasswordHashFor(ctx context.Context, userID uuid.UUID) (string, *errx.Error) { + return s.authRepository.GetPasswordHash(ctx, userID) +} diff --git a/internal/app/auth/service.go b/internal/app/auth/service.go index d4528d0f9..1479efcfa 100644 --- a/internal/app/auth/service.go +++ b/internal/app/auth/service.go @@ -64,6 +64,15 @@ type InstanceSettings interface { type AuthService interface { LoginStart(ctx context.Context, data *AuthData, ipaddr, userAgent string) (*models.AuthSession, *errx.Error) + // PasswordHashFor returns the stored argon2 hash, or empty for an account + // that has no password (passkey or SSO only). Used by the re-auth endpoint + // to confirm the account holder without starting a new login. + PasswordHashFor(ctx context.Context, userID uuid.UUID) (string, *errx.Error) + // The re-authentication endpoint's per-account budget. It checks a + // password, so it needs the same brake the login path has. + ReauthFailureExceeded(ctx context.Context, userID uuid.UUID) bool + RecordReauthFailure(ctx context.Context, userID uuid.UUID) + ClearReauthFailures(ctx context.Context, userID uuid.UUID) LoginConfirm(ctx context.Context, data *ConfirmData, session, ipaddr, userAgent string) (*models.LoginResult, *errx.Error) // WireTwoFA attaches the 2FA challenger (post-construction; nil = 2FA off). WireTwoFA(t TwoFAChallenger) diff --git a/internal/app/bootstrap/bootstrap.go b/internal/app/bootstrap/bootstrap.go index a5dd9ae71..f3d07f9bc 100644 --- a/internal/app/bootstrap/bootstrap.go +++ b/internal/app/bootstrap/bootstrap.go @@ -261,8 +261,8 @@ func (s *Service) Claim(ctx context.Context, token, address, password, firstName if perr != nil { return nil, errx.ErrEmail } - if !crypt.ValidatePassword(password) { - return nil, errx.ErrPassword + if perr := crypt.PasswordError(password); perr != nil { + return nil, perr } // Refuse on an instance that already has accounts, even with a valid diff --git a/internal/app/cloudlink/disconnect_managed_test.go b/internal/app/cloudlink/disconnect_managed_test.go index b80d08c0c..78fff637d 100644 --- a/internal/app/cloudlink/disconnect_managed_test.go +++ b/internal/app/cloudlink/disconnect_managed_test.go @@ -45,12 +45,12 @@ type revokingEmails struct { refused *[]*errx.Error } -func (s revokingEmails) Delete(ctx context.Context, orgID, accountID string) *errx.Error { +func (s revokingEmails) Delete(ctx context.Context, userID, accountID string) *errx.Error { if xerr := s.svc.RevokeForDelete(ctx, s.org, uuid.MustParse(accountID)); xerr != nil { *s.refused = append(*s.refused, xerr) return xerr } - return s.stubEmailDeletes.Delete(ctx, orgID, accountID) + return s.stubEmailDeletes.Delete(ctx, userID, accountID) } // Disconnect revokes the instance before it deletes the managed mirrors, so the diff --git a/internal/app/cloudlink/managed.go b/internal/app/cloudlink/managed.go index e200d8336..12666313e 100644 --- a/internal/app/cloudlink/managed.go +++ b/internal/app/cloudlink/managed.go @@ -105,7 +105,7 @@ func (s *service) mirror(ctx context.Context, l *models.CloudLink, orgID, userID } if _, err := s.repo.Enroll(ctx, acc.ID, state.RemoteID, true); err != nil { if s.emailSvc != nil { - _ = s.emailSvc.Delete(ctx, orgID.String(), acc.ID.String()) + _ = s.emailSvc.Delete(ctx, userID.String(), acc.ID.String()) } // Release the cloud side too: a mailbox left linked to this instance // with no mirror here is hidden from the adoptable list and refused on @@ -193,7 +193,7 @@ func (s *service) forgetToken(accountID uuid.UUID) { } // removeManaged deletes the local mirror; the cloud keeps the mailbox in the workspace. -func (s *service) removeManaged(ctx context.Context, orgID uuid.UUID, m *models.CloudLinkMailbox) *errx.Error { +func (s *service) removeManaged(ctx context.Context, userID string, m *models.CloudLinkMailbox) *errx.Error { if l, err := s.repo.Get(ctx); err == nil && l != nil { if xerr := s.clientFor(l).do(ctx, http.MethodDelete, "/instance/mailboxes/"+m.RemoteID.String(), nil, nil); xerr != nil && xerr.Identifier != "pool_link_mailbox_not_found" { return xerr @@ -201,7 +201,7 @@ func (s *service) removeManaged(ctx context.Context, orgID uuid.UUID, m *models. } s.forgetToken(m.EmailAccountID) if s.emailSvc != nil { - if xerr := s.emailSvc.Delete(ctx, orgID.String(), m.EmailAccountID.String()); xerr != nil && xerr != errx.ErrNotFound { + if xerr := s.emailSvc.Delete(ctx, userID, m.EmailAccountID.String()); xerr != nil && xerr != errx.ErrNotFound { return xerr } } diff --git a/internal/app/cloudlink/service.go b/internal/app/cloudlink/service.go index d5aefe395..4caa557cb 100644 --- a/internal/app/cloudlink/service.go +++ b/internal/app/cloudlink/service.go @@ -310,9 +310,9 @@ func (s *service) Disconnect(ctx context.Context) *errx.Error { if s.emailSvc == nil { continue } - if acc, xerr := s.emails.GetByID(ctx, m.EmailAccountID); xerr == nil && acc != nil && acc.OrganizationID != nil { + if acc, xerr := s.emails.GetByID(ctx, m.EmailAccountID); xerr == nil { s.forgetToken(m.EmailAccountID) - _ = s.emailSvc.Delete(ctx, acc.OrganizationID.String(), acc.ID.String()) + _ = s.emailSvc.Delete(ctx, acc.UserID, acc.ID.String()) } } if err := s.repo.UnenrollAll(ctx); err != nil { @@ -483,7 +483,8 @@ func (s *service) Enroll(ctx context.Context, orgID, accountID uuid.UUID) (*mode } func (s *service) Unenroll(ctx context.Context, orgID, accountID uuid.UUID) *errx.Error { - if _, xerr := s.ownedAccount(ctx, orgID, accountID); xerr != nil { + acc, xerr := s.ownedAccount(ctx, orgID, accountID) + if xerr != nil { return xerr } m, err := s.repo.GetByAccount(ctx, accountID) @@ -494,7 +495,7 @@ func (s *service) Unenroll(ctx context.Context, orgID, accountID uuid.UUID) *err return nil } if m.Managed { - return s.removeManaged(ctx, orgID, m) + return s.removeManaged(ctx, acc.UserID, m) } // Local row first, so a failed cloud call can be retried from a consistent // state instead of leaving the mailbox with no warmup anywhere. diff --git a/internal/app/consumer/warmup_reply_back.go b/internal/app/consumer/warmup_reply_back.go index cd3c011be..aa40b3bf4 100644 --- a/internal/app/consumer/warmup_reply_back.go +++ b/internal/app/consumer/warmup_reply_back.go @@ -20,9 +20,7 @@ const ( // scheduleWarmupReplyBack occasionally points the RECIPIENT's next warmup send // back at the sender. It re-points an already-pending task and only ever pulls -// it earlier; health gating is untouched, and a send pulled into a day that is -// already spent is held to the next opening by the send-time budget check, -// aim intact. +// it earlier, so budgets and health gating are untouched. func (s *JobsService) scheduleWarmupReplyBack(ctx context.Context, token *models.WarmupToken, recipientAccountID uuid.UUID) { if s.TaskRepo == nil || s.EmailRepository == nil || token == nil { return diff --git a/internal/app/contact/handler.go b/internal/app/contact/handler.go index 8839fe164..f67a09601 100644 --- a/internal/app/contact/handler.go +++ b/internal/app/contact/handler.go @@ -215,8 +215,8 @@ func (s *contactService) GetByEmail(ctx context.Context, orgID *uuid.UUID, email return s.contactRepository.GetByEmailAndOrganization(ctx, *orgID, email) } -func (s *contactService) ListSentEmails(ctx context.Context, userID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) { - return s.contactRepository.ListSentEmails(ctx, userID, contactID, limit, beforeSentAt, beforeTaskID) +func (s *contactService) ListSentEmails(ctx context.Context, orgID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) { + return s.contactRepository.ListSentEmails(ctx, orgID, contactID, limit, beforeSentAt, beforeTaskID) } func (s *contactService) ListTimeline(ctx context.Context, orgID, contactID uuid.UUID, limit int, cursor *models.ContactTimelineKey) (*models.ContactTimelineResult, *errx.Error) { diff --git a/internal/app/contact/import.go b/internal/app/contact/import.go index bf17f4416..36c4ea00f 100644 --- a/internal/app/contact/import.go +++ b/internal/app/contact/import.go @@ -27,6 +27,14 @@ import ( // a second time on commit; storing the parsed buffer between calls // would either pin memory or require a tmp store, neither of which is // worth it for the typical (small) file size. +// XLSX decompression budgets. A contact import is a list of people, so even a +// very large one is tens of megabytes of text; these are generous for that and +// far below what a zip bomb needs. +const ( + xlsxUnzipLimitBytes = 512 << 20 // 512 MiB total uncompressed + xlsxUnzipXMLLimitBytes = 64 << 20 // 64 MiB for any single XML part +) + func (s *contactService) ImportPreview(ctx context.Context, r io.Reader, filename string) (*models.ContactImportPreview, *errx.Error) { rows, format, xerr := parseSpreadsheet(r, filename) if xerr != nil { @@ -730,7 +738,25 @@ func appendUnique(dst []string, add ...string) []string { // parseSpreadsheet returns rows as a 2-D slice and the detected format. // CSV is decoded with the stdlib (forgiving about trailing commas / // quoting), XLSX is decoded with excelize. Anything else 400s. -func parseSpreadsheet(r io.Reader, filename string) ([][]string, string, *errx.Error) { +// parseSpreadsheet turns an uploaded file into rows. +// +// It recovers from a panic in the parser. The XLSX reader is a third-party +// parser of a zip of XML written by whoever uploaded the file, and it carries +// at least one open advisory with no fix available (a negative shared-string +// index panics). The request middleware would catch that and answer 500, but a +// malformed workbook is the caller's problem and should read as one, not as an +// instance fault that pages the error tracker. +func parseSpreadsheet(r io.Reader, filename string) (rows [][]string, kind string, xerr *errx.Error) { + defer func() { + if rec := recover(); rec != nil { + rows, kind = nil, "" + xerr = errx.New(errx.BadRequest, "this file could not be read as a spreadsheet; export it again from your spreadsheet application and retry") + } + }() + return parseSpreadsheetInner(r, filename) +} + +func parseSpreadsheetInner(r io.Reader, filename string) ([][]string, string, *errx.Error) { ext := strings.ToLower(filepath.Ext(filename)) switch ext { case ".csv", ".tsv", ".txt", "": @@ -746,7 +772,16 @@ func parseSpreadsheet(r io.Reader, filename string) ([][]string, string, *errx.E } return rows, "csv", nil case ".xlsx", ".xlsm": - f, err := excelize.OpenReader(r) + // An XLSX is a zip of XML, so its uncompressed size is unrelated to the + // upload cap. excelize defaults to a 16 GB unzip budget, and GetRows + // materialises the whole sheet before the row cap is ever applied, so a + // small file with a sparse dimension and a large shared-strings table + // could exhaust memory on the backend. Bound the decompression, then + // stream the rows and stop at the cap. + f, err := excelize.OpenReader(r, excelize.Options{ + UnzipSizeLimit: xlsxUnzipLimitBytes, + UnzipXMLSizeLimit: xlsxUnzipXMLLimitBytes, + }) if err != nil { return nil, "xlsx", errx.New(errx.BadRequest, "failed to parse XLSX: "+err.Error()) } @@ -759,10 +794,29 @@ func parseSpreadsheet(r io.Reader, filename string) ([][]string, string, *errx.E } sheetName = names[0] } - rows, err := f.GetRows(sheetName) + it, err := f.Rows(sheetName) if err != nil { return nil, "xlsx", errx.New(errx.BadRequest, "failed to read XLSX rows: "+err.Error()) } + defer it.Close() + + // One row past the cap, so the caller can still tell "too many rows" + // from "exactly at the limit". + limit := models.MaxContactImportRows + 1 + rows := make([][]string, 0, 256) + for it.Next() { + cols, cerr := it.Columns() + if cerr != nil { + return nil, "xlsx", errx.New(errx.BadRequest, "failed to read XLSX rows: "+cerr.Error()) + } + rows = append(rows, cols) + if len(rows) >= limit { + break + } + } + if err := it.Error(); err != nil { + return nil, "xlsx", errx.New(errx.BadRequest, "failed to read XLSX rows: "+err.Error()) + } return rows, "xlsx", nil } return nil, "", errx.New(errx.BadRequest, "unsupported file type: "+ext) diff --git a/internal/app/contact/service.go b/internal/app/contact/service.go index 62734933f..5b1a36fdf 100644 --- a/internal/app/contact/service.go +++ b/internal/app/contact/service.go @@ -71,7 +71,7 @@ type ContactService interface { // ListSentEmails enumerates every send (or attempted send) we made // to the contact, newest first. - ListSentEmails(ctx context.Context, userID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) + ListSentEmails(ctx context.Context, orgID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) // ListTimeline returns a merged, reverse-chronological feed of all // engagement + CRM events for the contact. diff --git a/internal/app/email/broker.go b/internal/app/email/broker.go index 8291810e2..047d033d6 100644 --- a/internal/app/email/broker.go +++ b/internal/app/email/broker.go @@ -39,6 +39,20 @@ func (s *emailService) OAuthConnectWithCode(ctx context.Context, userID string, if err != nil { return nil, errx.ErrEmailOnboardExchange } + + // The same two guards the first-party connect applies. Without them a + // brokered mailbox could be stored after a consent the person half granted, + // or with no refresh token at all, and it would read as connected until its + // first send failed days later. + if xerr := checkGrantedScopes(ctx, provider, cfg.Scopes, tok); xerr != nil { + return nil, xerr + } + if strings.TrimSpace(tok.RefreshToken) == "" { + return nil, errx.New(errx.BadRequest, + "The provider did not return a long-lived token for this mailbox, so it would stop working within the hour. "+ + "Remove Warmbly's access in your account settings and connect it again.") + } + owner, xerr := fetchInboxOwner(ctx, provider, tok.AccessToken) if xerr != nil { return nil, xerr diff --git a/internal/app/email/bulk.go b/internal/app/email/bulk.go index 3136abb81..9c8c20063 100644 --- a/internal/app/email/bulk.go +++ b/internal/app/email/bulk.go @@ -29,7 +29,7 @@ func (s *emailService) OnboardSMTPIMAPBulk(ctx context.Context, userID string, o fail := func(i int, xerr *errx.Error) { res.Data[i] = models.MailboxBulkRow{ Row: i, Email: rows[i].Email, Status: models.MailboxBulkFailed, - Code: bulkCode(xerr), Message: xerr.UserMessage(), + Code: bulkCode(xerr), Message: xerr.Message, } } @@ -116,12 +116,12 @@ func (s *emailService) OnboardSMTPIMAPBulk(ctx context.Context, userID string, o case errors.Is(xerr, errx.ErrEmailOnboardAlreadyExists): res.Data[i] = models.MailboxBulkRow{ Row: i, Email: row.Email, Status: models.MailboxBulkSkipped, - Code: "already_connected", Message: xerr.UserMessage(), + Code: "already_connected", Message: xerr.Message, } default: res.Data[i] = models.MailboxBulkRow{ Row: i, Email: row.Email, Status: models.MailboxBulkFailed, - Code: bulkCode(xerr), Message: xerr.UserMessage(), + Code: bulkCode(xerr), Message: xerr.Message, } } }(i) diff --git a/internal/app/email/cache.go b/internal/app/email/cache.go index 51e1ac153..d847288a4 100644 --- a/internal/app/email/cache.go +++ b/internal/app/email/cache.go @@ -39,7 +39,10 @@ func (s *emailService) takeOnboardingState(ctx context.Context, state string) (* if s.r == nil { return nil, errx.InternalError() } - raw, err := s.r.Get(ctx, onboardingStateKey(state)).Bytes() + // GetDel, not Get-then-Del: with two statements, two callbacks arriving at + // once both read the state before either deletes it, and "single use" + // stops being true. The SSO path already uses this; this one did not. + raw, err := s.r.GetDel(ctx, onboardingStateKey(state)).Bytes() if err != nil { if errors.Is(err, redis.Nil) { return nil, errx.ErrEmailOnboardState @@ -47,10 +50,6 @@ func (s *emailService) takeOnboardingState(ctx context.Context, state string) (* errs.CaptureException(err) return nil, errx.InternalError() } - // Single-use: remove immediately to prevent replay even on later errors. - if err := s.r.Del(ctx, onboardingStateKey(state)).Err(); err != nil { - errs.CaptureException(err) - } var out models.EmailOnboardingState if err := json.Unmarshal(raw, &out); err != nil { errs.CaptureException(err) diff --git a/internal/app/email/cloud_unenroll_delete_test.go b/internal/app/email/cloud_unenroll_delete_test.go index ca3307e02..183187ba8 100644 --- a/internal/app/email/cloud_unenroll_delete_test.go +++ b/internal/app/email/cloud_unenroll_delete_test.go @@ -57,7 +57,7 @@ func TestDeleteRevokesTheCloudEnrollmentBeforeTheRowGoes(t *testing.T) { f := newRemovalFixture(t) u := withCloudEnrollment(f, false) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(u.calls) != 1 || u.calls[0] != f.mailbox { @@ -84,7 +84,7 @@ func TestDeleteKeepsTheMailboxWhenTheCloudRefusesTheRevocation(t *testing.T) { u := withCloudEnrollment(f, false) u.err = errx.InternalError() - xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()) + xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()) if xerr == nil { t.Fatal("the mailbox was deleted while the pool still held its password") } @@ -106,7 +106,7 @@ func TestDeleteKeepsTheMailboxWhenTheEnrollmentCannotBeRead(t *testing.T) { withCloudEnrollment(f, false) f.svc.cloudLink = &stubCloudLinkRepo{err: errors.New("db down")} - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr == nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr == nil { t.Fatal("the mailbox was deleted on an unreadable cloud enrollment") } if f.repo.deleteCalls != 0 { @@ -127,7 +127,7 @@ func TestDeleteKeepsTheMailboxWhenCloudRevocationIsNotWired(t *testing.T) { f := newRemovalFixture(t) tc.setup(f.svc) - xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()) + xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()) if xerr == nil || xerr.Identifier != ErrCloudEnrollmentStuck.Identifier { t.Fatalf("error = %v, want %q", xerr, ErrCloudEnrollmentStuck.Identifier) } @@ -145,7 +145,7 @@ func TestDeleteReleasesTheCloudLinkForAManagedMailbox(t *testing.T) { f := newRemovalFixture(t) u := withCloudEnrollment(f, true) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(u.calls) != 1 || u.calls[0] != f.mailbox { @@ -176,7 +176,7 @@ func TestDeleteSkipsTheCloudWhenTheMailboxIsNotEnrolled(t *testing.T) { u := withCloudEnrollment(f, false) f.svc.cloudLink = &stubCloudLinkRepo{} - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(u.calls) != 0 { diff --git a/internal/app/email/handler.go b/internal/app/email/handler.go index b4494892e..c93377708 100644 --- a/internal/app/email/handler.go +++ b/internal/app/email/handler.go @@ -291,10 +291,18 @@ func (s *emailService) RefreshDomainAuth(ctx context.Context, orgID, emailAccoun // Persist best-effort: the caller asked for a live check and gets the live // answer either way. A failed write only means the sweep re-derives it. - _, _ = s.emailRepository.UpdateDomainAuthState( - ctx, domain, res.State(), res.SPFFound, res.DKIMFound, res.DMARCFound, - res.DMARCPolicy, res.Summary, time.Now(), - ) + // + // Confined to the caller's workspace. The verdict comes from public DNS so + // it cannot be poisoned, but one workspace pressing "check again" should + // not rewrite auth state on every other workspace's mailboxes that happen + // to sit on the same domain (gmail.com, say). The background sweep still + // covers them all. + if org, perr := uuid.Parse(orgID); perr == nil { + _, _ = s.emailRepository.UpdateDomainAuthStateForOrg( + ctx, org, domain, res.State(), res.SPFFound, res.DKIMFound, res.DMARCFound, + res.DMARCPolicy, res.Summary, time.Now(), + ) + } return res, nil } @@ -321,33 +329,25 @@ func (s *emailService) resolveDomainAuth(ctx context.Context, orgID, emailAccoun // Delete disconnects a mailbox. The worker is told to drop it BEFORE the row // goes, because afterwards no assignment is left to read and nothing can repair // a missed removal, so a removal that cannot be sent fails the whole delete. -// -// Scoped to the workspace, like every other mailbox route: the list shows a -// teammate every mailbox in it and the route is gated on manage_emails, so a -// delete that only the connecting member could perform answered 404 to -// everyone else on a row they could see. -func (s *emailService) Delete(ctx context.Context, orgID, emailAccountID string) *errx.Error { +func (s *emailService) Delete(ctx context.Context, userID, emailAccountID string) *errx.Error { accountID, err := uuid.Parse(emailAccountID) if err != nil { return errx.ErrUuid } - org, err := uuid.Parse(orgID) - if err != nil { - return errx.ErrUuid - } - // Ownership is proved here, before the removal below is publishable, and - // the repository deletes by id on the strength of it. + // Read by id: Get is scoped by organization and was being handed a user id, + // so it never found the mailbox and every side effect below was skipped. + // Ownership moves here, or the removal below would be publishable for a + // mailbox the caller does not own. account, xerr := s.emailRepository.GetByID(ctx, accountID) if xerr != nil { return xerr } - if account == nil || account.OrganizationID == nil || *account.OrganizationID != org { + if account == nil || !sameUser(account.UserID, userID) { return errx.ErrNotFound } - // The owner's id, not the caller's: the consumer's unibox cleanup is keyed on it. - if xerr := s.dropFromWorker(ctx, account.UserID, accountID); xerr != nil { + if xerr := s.dropFromWorker(ctx, userID, accountID); xerr != nil { return xerr } @@ -361,7 +361,7 @@ func (s *emailService) Delete(ctx context.Context, orgID, emailAccountID string) // nulls worker_id, so a worker not credited here stays charged for a // mailbox that no longer exists, unrepairably. refund := worker.MailboxWeight(account.Provider, account.Warmup != nil) - if xerr := s.emailRepository.Delete(ctx, emailAccountID, refund); xerr != nil { + if xerr := s.emailRepository.Delete(ctx, userID, emailAccountID, refund); xerr != nil { // The removal already went out and the mailbox is still active: put it // back now instead of leaving it dark until the reconciler's next pass. s.loadAccountBestEffort(ctx, accountID) @@ -416,6 +416,14 @@ func (s *emailService) unenrollFromCloud(ctx context.Context, account *models.Em return nil } +// sameUser compares user ids as uuids, the way the delete's own WHERE clause +// does, so formatting alone never reads as a different owner. +func sameUser(a, b string) bool { + left, aerr := uuid.Parse(a) + right, berr := uuid.Parse(b) + return aerr == nil && berr == nil && left == right +} + func (s *emailService) syncWarmupPoolMembership(ctx context.Context, account *models.Email) { if s.warmupService == nil || account == nil { return diff --git a/internal/app/email/mailbox_erasure_live_test.go b/internal/app/email/mailbox_erasure_live_test.go index 2b1cba856..a6715f809 100644 --- a/internal/app/email/mailbox_erasure_live_test.go +++ b/internal/app/email/mailbox_erasure_live_test.go @@ -60,7 +60,7 @@ func TestLiveDeleteRecordsTheErasureItCannotPerform(t *testing.T) { exec(t, f, `INSERT INTO email_accounts_oauth (email_account_id, access_token, refresh_token, expires_at) VALUES ($1, 'sealed-access', 'sealed-refresh', now() + interval '1 hour')`, f.mailbox) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if f.mailboxExists(t) { @@ -91,7 +91,7 @@ func TestLiveDeleteQueuesErasureForAMailboxWithNoGrant(t *testing.T) { f := newRemovalLiveFixture(t) cleanErasure(t, f) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } row := readErasure(t, f) @@ -110,7 +110,7 @@ func TestLiveAFailedDeleteQueuesNoErasure(t *testing.T) { cleanErasure(t, f) f.pub.removeErr = errBusDown - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr == nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr == nil { t.Fatal("the delete was reported as succeeding") } if !f.mailboxExists(t) { @@ -157,7 +157,7 @@ func TestLiveDeleteTakesTheRowsThatHadNoForeignKey(t *testing.T) { exec(t, f, `INSERT INTO warmup_pending_engagements (email_account_id, payload, fire_at) VALUES ($1, '{}'::jsonb, now())`, f.mailbox) - if xerr := f.svc.Delete(ctx, f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(ctx, f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } @@ -222,7 +222,7 @@ func TestLiveDeleteClearsLabelsOnThreadsItEmptied(t *testing.T) { f.user, m.thread) } - if xerr := f.svc.Delete(ctx, f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(ctx, f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } diff --git a/internal/app/email/onboarding.go b/internal/app/email/onboarding.go index 2191f5383..f2942c385 100644 --- a/internal/app/email/onboarding.go +++ b/internal/app/email/onboarding.go @@ -45,16 +45,23 @@ func (s *emailService) OAuthStart(ctx context.Context, userID string, orgID *uui return nil, errx.InternalError() } + // PKCE. The verifier stays in the server-side state and the browser only + // ever carries the challenge, so an authorization code lifted from the + // redirect cannot be redeemed by whoever lifted it. + verifier := oauth2.GenerateVerifier() + if xerr := s.saveOnboardingState(ctx, state, &models.EmailOnboardingState{ UserID: userID, OrganizationID: orgID, Provider: string(provider), Nonce: state, + CodeVerifier: verifier, }); xerr != nil { return nil, xerr } - url := cfg.AuthCodeURL(state, authCodeOptions(provider, "")...) + opts := append(authCodeOptions(provider, ""), oauth2.S256ChallengeOption(verifier)) + url := cfg.AuthCodeURL(state, opts...) return &models.EmailOnboardingStartResponse{URL: url, State: state}, nil } @@ -131,7 +138,15 @@ func (s *emailService) OAuthFinish(ctx context.Context, userID, code, state stri return nil, false, xerr } - tok, err := cfg.Exchange(ctx, code) + // The verifier proves this is the same party that started the flow. Absent + // only for a state written before PKCE existed, where the exchange has to + // go ahead without it or an in-flight consent dies on deploy. + var exchangeOpts []oauth2.AuthCodeOption + if sess.CodeVerifier != "" { + exchangeOpts = append(exchangeOpts, oauth2.VerifierOption(sess.CodeVerifier)) + } + + tok, err := cfg.Exchange(ctx, code, exchangeOpts...) if err != nil { return nil, false, errx.ErrEmailOnboardExchange } @@ -469,6 +484,11 @@ var scopeSatisfiedBy = map[string][]string{ "https://www.googleapis.com/auth/gmail.modify", "https://mail.google.com/", }, + // settings.basic is not implied by anything: mail.google.com is full + // mailbox access and does not confer settings either. + "https://www.googleapis.com/auth/gmail.settings.basic": { + "https://www.googleapis.com/auth/gmail.settings.basic", + }, } // scopeLabel names a permission the way the consent screen does, so the error diff --git a/internal/app/email/reauth.go b/internal/app/email/reauth.go index 7e7471e52..9f4853057 100644 --- a/internal/app/email/reauth.go +++ b/internal/app/email/reauth.go @@ -58,17 +58,23 @@ func (s *emailService) OAuthReauth(ctx context.Context, userID string, orgID *uu return nil, errx.InternalError() } + // PKCE, same as the first-connect path: the verifier never leaves the + // server, so an intercepted code is not redeemable. + verifier := oauth2.GenerateVerifier() + if xerr := s.saveOnboardingState(ctx, state, &models.EmailOnboardingState{ UserID: userID, OrganizationID: orgID, Provider: string(provider), Nonce: state, EmailAccountID: &accountID, + CodeVerifier: verifier, }); xerr != nil { return nil, xerr } - url := cfg.AuthCodeURL(state, authCodeOptions(provider, account.Email)...) + opts := append(authCodeOptions(provider, account.Email), oauth2.S256ChallengeOption(verifier)) + url := cfg.AuthCodeURL(state, opts...) return &models.EmailOnboardingStartResponse{URL: url, State: state}, nil } diff --git a/internal/app/email/service.go b/internal/app/email/service.go index 771d10741..4648debac 100644 --- a/internal/app/email/service.go +++ b/internal/app/email/service.go @@ -60,7 +60,7 @@ type EmailService interface { // lift the cold-send and warmup gate, so it sits behind the write // permission while CheckDomainAuth stays readable. RefreshDomainAuth(ctx context.Context, orgID, emailAccountID string) (*dnsauth.Result, *errx.Error) - Delete(ctx context.Context, orgID, emailAccountID string) *errx.Error + Delete(ctx context.Context, userID, emailAccountID string) *errx.Error // GetSendIdentity reports which addresses the mailbox's provider will let // it send as, which one is in use, and where the stored signature came @@ -344,8 +344,8 @@ func (s *emailService) publishAccountEvent(ctx context.Context, eventType pubsub // GetSyncState returns the persisted sync state and the policy currently in // force. It goes through Get so ownership is checked the same way as every // other per-mailbox read. -func (s *emailService) GetSyncState(ctx context.Context, userID, emailID string) (*models.SyncState, models.SyncPolicy, *errx.Error) { - acc, xerr := s.Get(ctx, userID, emailID) +func (s *emailService) GetSyncState(ctx context.Context, orgID, emailID string) (*models.SyncState, models.SyncPolicy, *errx.Error) { + acc, xerr := s.Get(ctx, orgID, emailID) if xerr != nil { return nil, models.SyncPolicy{}, xerr } diff --git a/internal/app/email/validate_credentials.go b/internal/app/email/validate_credentials.go index 03a76f77c..f46140b3b 100644 --- a/internal/app/email/validate_credentials.go +++ b/internal/app/email/validate_credentials.go @@ -63,13 +63,8 @@ func (s *emailService) ValidateCredentials(ctx context.Context, orgID uuid.UUID, if errors.Is(err, context.DeadlineExceeded) { return errx.ErrEmailValidation } - // Anything else is the channel the worker answers on, not the - // mailbox: a cache that timed out or refused the read says - // nothing about the credentials, and answering "Something went - // wrong" left the person who typed them with no idea whether - // they were wrong or whether we had simply not looked. - errs.CaptureException(err, errs.Tag("stage", "mailbox_validation_subscribe")) - return errx.ErrEmailValidationUnavailable + errs.CaptureException(err) + return errx.InternalError() } switch msg.Payload { diff --git a/internal/app/email/worker_removal_live_test.go b/internal/app/email/worker_removal_live_test.go index f9638f893..308bd7af0 100644 --- a/internal/app/email/worker_removal_live_test.go +++ b/internal/app/email/worker_removal_live_test.go @@ -159,7 +159,7 @@ func TestLiveDisablingAMailboxRemovesItFromItsWorker(t *testing.T) { func TestLiveDeletingAMailboxRemovesItFromItsWorkerFirst(t *testing.T) { f := newRemovalLiveFixture(t) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } @@ -183,26 +183,25 @@ func TestLiveDeletingAMailboxRemovesItFromItsWorkerFirst(t *testing.T) { // The refund shares the delete's transaction, so a delete that matches no row // must leave the worker's capacity exactly as it was. Driven through the -// repository, because the service refuses a mailbox outside the caller's -// workspace before it gets here. +// repository, because the service refuses a foreign owner before it gets here. func TestLiveDeleteThatMatchesNoRowRefundsNothing(t *testing.T) { f := newRemovalLiveFixture(t) - if xerr := f.svc.emailRepository.Delete(context.Background(), uuid.New().String(), 1); xerr != errx.ErrNotFound { + if xerr := f.svc.emailRepository.Delete(context.Background(), uuid.New().String(), f.mailbox.String(), 1); xerr != errx.ErrNotFound { t.Fatalf("error = %v, want not found", xerr) } if count, score := f.workerLoad(t); count != 1 || score != 1 { t.Errorf("capacity was refunded for a mailbox that was not deleted: account_count=%d load_score=%v", count, score) } if !f.mailboxExists(t) { - t.Error("a delete of an unknown id removed a different mailbox") + t.Error("the mailbox was deleted by a caller that does not own it") } } -// The lookup that finds the mailbox is deliberately unscoped, so the workspace -// is checked in the service. Another workspace's id must not delete this -// mailbox or publish a removal for it. -func TestLiveDeleteRefusesAMailboxOfAnotherWorkspace(t *testing.T) { +// The lookup that finds the mailbox is deliberately unscoped, so ownership is +// checked in the service. A teammate's user id must not delete this mailbox or +// publish a removal for it. +func TestLiveDeleteRefusesAMailboxTheCallerDoesNotOwn(t *testing.T) { f := newRemovalLiveFixture(t) if xerr := f.svc.Delete(context.Background(), uuid.New().String(), f.mailbox.String()); xerr != errx.ErrNotFound { @@ -222,7 +221,7 @@ func TestLiveDeleteKeepsEverythingWhenTheWorkerCannotBeTold(t *testing.T) { f := newRemovalLiveFixture(t) f.pub.removeErr = errBusDown - xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()) + xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()) if xerr == nil || xerr.Code != errx.ServiceUnavailable { t.Fatalf("error = %v, want a 503 so the client retries", xerr) } @@ -259,7 +258,7 @@ func TestLiveDeletingAMailboxWithScheduledWork(t *testing.T) { t.Fatalf("fixture admin action: %v", err) } - if xerr := f.svc.Delete(ctx, f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(ctx, f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("disconnecting a mailbox that has scheduled work failed: %v", xerr) } if f.mailboxExists(t) { diff --git a/internal/app/email/worker_removal_test.go b/internal/app/email/worker_removal_test.go index 6f91a6be1..10fd4adcb 100644 --- a/internal/app/email/worker_removal_test.go +++ b/internal/app/email/worker_removal_test.go @@ -74,7 +74,7 @@ func (s *stubRemovalRepo) GetSMTPCredentials(ctx context.Context, emailAccountID return &repository.SMTPCredentials{SMTPHost: "smtp.test.local", SMTPPort: 587, IMAPHost: "imap.test.local", IMAPPort: 993}, nil } -func (s *stubRemovalRepo) Delete(ctx context.Context, emailAccountID string, workerLoadRefund float64) *errx.Error { +func (s *stubRemovalRepo) Delete(ctx context.Context, userID, emailAccountID string, workerLoadRefund float64) *errx.Error { s.deleteCalls++ s.refunded = append(s.refunded, workerLoadRefund) s.record("delete") @@ -269,7 +269,7 @@ func TestDisablingSucceedsEvenWhenTheBusIsDown(t *testing.T) { func TestDeleteTellsTheWorkerBeforeTheRowGoes(t *testing.T) { f := newRemovalFixture(t) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } @@ -294,7 +294,7 @@ func TestDeleteKeepsTheMailboxWhenTheWorkerCannotBeTold(t *testing.T) { f := newRemovalFixture(t) f.pub.removeErr = errBusDown - xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()) + xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()) if xerr == nil { t.Fatal("the mailbox was deleted without the worker ever being told") } @@ -315,7 +315,7 @@ func TestDeleteKeepsTheMailboxWhenTheAssignmentCannotBeRead(t *testing.T) { f := newRemovalFixture(t) f.repo.workerErr = errx.InternalError() - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr == nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr == nil { t.Fatal("the mailbox was deleted on an unreadable assignment") } if f.repo.deleteCalls != 0 { @@ -329,7 +329,7 @@ func TestDeleteWithoutAWorkerStillRemovesTheRow(t *testing.T) { f.repo.workerID = nil f.repo.account.WorkerID = nil - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(f.pub.removed) != 0 { @@ -347,7 +347,7 @@ func TestDeleteWithoutAWorkerStillRemovesTheRow(t *testing.T) { func TestDeleteGivesTheWorkerItsCapacityBack(t *testing.T) { f := newRemovalFixture(t) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(f.repo.refunded) != 1 || f.repo.refunded[0] != worker.MailboxWeight("smtp_imap", false) { @@ -363,7 +363,7 @@ func TestDeleteRefundsTheWeightTheMailboxWasChargedAt(t *testing.T) { f.repo.account.Provider = "gmail" f.repo.account.Warmup = &warming - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if len(f.repo.refunded) != 1 || f.repo.refunded[0] != worker.MailboxWeight("gmail", true) { @@ -373,40 +373,34 @@ func TestDeleteRefundsTheWeightTheMailboxWasChargedAt(t *testing.T) { // The removal must never be reachable for a mailbox the caller does not own: // the lookup that finds it is unscoped, so ownership is checked here. -func TestDeleteRefusesAMailboxOfAnotherWorkspace(t *testing.T) { +func TestDeleteRefusesAMailboxTheCallerDoesNotOwn(t *testing.T) { f := newRemovalFixture(t) - other := uuid.New() - f.repo.account.OrganizationID = &other + f.repo.account.UserID = uuid.New().String() - xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()) + xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()) if xerr != errx.ErrNotFound { t.Fatalf("error = %v, want not found", xerr) } if len(f.pub.removed) != 0 || f.repo.deleteCalls != 0 { - t.Errorf("acted on another workspace's mailbox: %d removals, %d deletes", len(f.pub.removed), f.repo.deleteCalls) + t.Errorf("acted on someone else's mailbox: %d removals, %d deletes", len(f.pub.removed), f.repo.deleteCalls) } } -// The mailbox belongs to the workspace, not to whoever connected it: a -// teammate with the permission can disconnect it, and the removal still names -// the owner, which is the id the consumer's unibox cleanup is keyed on. -func TestDeleteByATeammateNamesTheOwner(t *testing.T) { +// Owner ids arriving in different letter case are the same owner; Postgres +// compares them as uuids and so does this. +func TestDeleteAcceptsTheOwnerInAnyCase(t *testing.T) { f := newRemovalFixture(t) - owner := uuid.New().String() - f.repo.account.UserID = owner + f.repo.account.UserID = uuidUpper(f.user) - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { - t.Fatalf("a teammate was refused a mailbox in their own workspace: %v", xerr) - } - if len(f.pub.removed) != 1 || f.pub.removed[0].userID != owner { - t.Errorf("removal = %+v, want one naming owner %s", f.pub.removed, owner) + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { + t.Fatalf("the owner was refused their own mailbox: %v", xerr) } } func TestDeleteRejectsAMalformedID(t *testing.T) { f := newRemovalFixture(t) - if xerr := f.svc.Delete(context.Background(), f.org.String(), "not-a-uuid"); xerr != errx.ErrUuid { + if xerr := f.svc.Delete(context.Background(), f.user.String(), "not-a-uuid"); xerr != errx.ErrUuid { t.Fatalf("error = %v, want a uuid error", xerr) } if f.repo.deleteCalls != 0 { @@ -420,7 +414,7 @@ func TestDeleteOfAMissingMailboxPublishesNothing(t *testing.T) { f := newRemovalFixture(t) f.repo.getErr = errx.ErrNotFound - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != errx.ErrNotFound { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != errx.ErrNotFound { t.Fatalf("error = %v, want not found", xerr) } if len(f.pub.removed) != 0 || f.repo.deleteCalls != 0 { @@ -434,7 +428,7 @@ func TestDeleteWithNoPublisherWired(t *testing.T) { f := newRemovalFixture(t) f.svc.publisher = nil - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr != nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr != nil { t.Fatalf("delete: %v", xerr) } if f.repo.deleteCalls != 1 { @@ -445,6 +439,17 @@ func TestDeleteWithNoPublisherWired(t *testing.T) { } } +// uuidUpper renders an id the way a caller that upper-cases its ids would. +func uuidUpper(id uuid.UUID) string { + out := []rune(id.String()) + for i, r := range out { + if r >= 'a' && r <= 'f' { + out[i] = r - 32 + } + } + return string(out) +} + // A delete that fails after the removal was published leaves a mailbox that is // still active but no longer loaded anywhere. It goes straight back on rather // than waiting minutes for the reconciler. @@ -452,7 +457,7 @@ func TestAFailedDeletePutsTheMailboxBackOnItsWorker(t *testing.T) { f := newRemovalFixture(t) f.repo.deleteErr = errx.InternalError() - if xerr := f.svc.Delete(context.Background(), f.org.String(), f.mailbox.String()); xerr == nil { + if xerr := f.svc.Delete(context.Background(), f.user.String(), f.mailbox.String()); xerr == nil { t.Fatal("a failed delete was reported as success") } if len(f.pub.added) != 1 || f.pub.added[0] != f.mailbox { diff --git a/internal/app/emailsend/service.go b/internal/app/emailsend/service.go index 97e28ba3d..ce5974377 100644 --- a/internal/app/emailsend/service.go +++ b/internal/app/emailsend/service.go @@ -134,11 +134,16 @@ func (s *emailSendService) SendEmail(ctx context.Context, userID, orgID, account } } - // Validate email account exists and belongs to user/org + // GetByID is unscoped (the org-scoped Get omits worker_id, which the + // send needs), so the tenant check lives here: a foreign mailbox id is + // indistinguishable from a missing one. account, xerr := s.emailRepo.GetByID(ctx, accountID) if xerr != nil { return nil, xerr } + if account == nil || account.OrganizationID == nil || *account.OrganizationID != orgID { + return nil, errx.New(errx.NotFound, "email account not found") + } // Check CanUseUnibox feature gate if s.featureGate != nil { diff --git a/internal/app/form/service.go b/internal/app/form/service.go index ca350d2a8..d5ae11502 100644 --- a/internal/app/form/service.go +++ b/internal/app/form/service.go @@ -527,7 +527,11 @@ func buildSubmission(fields []models.FormField, answers map[string][]string) (ma if len(vals) > 0 { v = strings.TrimSpace(vals[0]) } - if f.Type == models.FormFieldHidden && v == "" { + // A hidden field's value is the owner's, not the submitter's: it carries + // the campaign tag, source or routing key they configured. The posted + // value is ignored so the form cannot be made to file a lead under + // something else. + if f.Type == models.FormFieldHidden { v = f.Value } if len(v) > models.FormMaxAnswerLen { diff --git a/internal/app/idempotency/service.go b/internal/app/idempotency/service.go index 33e3669bb..0a657ae5c 100644 --- a/internal/app/idempotency/service.go +++ b/internal/app/idempotency/service.go @@ -47,7 +47,7 @@ func NewService(db *pgxpool.Pool) Service { func (s *service) Begin(ctx context.Context, orgID uuid.UUID, key, method, path, requestHash string) (*Record, State, *errx.Error) { if s == nil || s.db == nil { - return nil, "", errx.NewPublic(errx.ServiceUnavailable, "Idempotency service is not available.") + return nil, "", errx.New(errx.ServiceUnavailable, "idempotency service is not available") } _, _ = s.db.Exec(ctx, ` @@ -86,7 +86,7 @@ func (s *service) Begin(ctx context.Context, orgID uuid.UUID, key, method, path, func (s *service) Complete(ctx context.Context, recordID uuid.UUID, statusCode int, responseBody []byte, contentType string) *errx.Error { if s == nil || s.db == nil { - return errx.NewPublic(errx.ServiceUnavailable, "Idempotency service is not available.") + return errx.New(errx.ServiceUnavailable, "idempotency service is not available") } _, err := s.db.Exec(ctx, ` UPDATE api_idempotency_keys diff --git a/internal/app/organization/service.go b/internal/app/organization/service.go index 601bb5265..c2fc62d55 100644 --- a/internal/app/organization/service.go +++ b/internal/app/organization/service.go @@ -90,10 +90,10 @@ type OrganizationService interface { // Invitations GetPendingInvitations(ctx context.Context, orgID uuid.UUID) ([]models.OrganizationInvitation, *errx.Error) GetUserPendingInvitations(ctx context.Context, email string) ([]models.OrganizationInvitation, *errx.Error) - CancelInvitation(ctx context.Context, invitationID uuid.UUID) *errx.Error + CancelInvitation(ctx context.Context, orgID, invitationID uuid.UUID) *errx.Error // Ownership transfer - TransferOwnership(ctx context.Context, orgID, newOwnerUserID uuid.UUID) *errx.Error + TransferOwnership(ctx context.Context, orgID, actorUserID, newOwnerUserID uuid.UUID) *errx.Error // Permission checks HasPermission(ctx context.Context, orgID, userID uuid.UUID, perm models.OrganizationPermission) (bool, *errx.Error) @@ -152,7 +152,7 @@ type OrganizationService interface { // RejectLimitRequest path. Approving rewrites the override row via // SetLimitOverrides so the audit story stays unified. SubmitLimitIncreaseRequest(ctx context.Context, orgID, submitterID uuid.UUID, req *models.CreateLimitIncreaseRequest) (*models.LimitIncreaseRequest, *errx.Error) - ListLimitRequestsForOrg(ctx context.Context, orgID uuid.UUID) ([]models.LimitIncreaseRequest, *errx.Error) + ListLimitRequestsForOrg(ctx context.Context, orgID, requesterID uuid.UUID) ([]models.LimitIncreaseRequest, *errx.Error) CancelLimitRequest(ctx context.Context, id, userID uuid.UUID) *errx.Error AdminListLimitRequests(ctx context.Context, search *models.AdminLimitRequestSearch) (*models.AdminLimitRequestsResult, *errx.Error) ApproveLimitRequest(ctx context.Context, id, reviewerID uuid.UUID, notes string) (*models.LimitIncreaseRequest, *errx.Error) @@ -548,6 +548,21 @@ func (s *organizationService) GetMembership(ctx context.Context, orgID, userID u return member, nil } +// requireMember is the membership gate for handlers that carry an org id in +// the path rather than taking it from the session. GetMembership answers +// (nil, nil) for a non-member, so callers that only test the error let +// everyone through; this is the form that fails closed. +func (s *organizationService) requireMember(ctx context.Context, orgID, userID uuid.UUID) *errx.Error { + member, xerr := s.GetMembership(ctx, orgID, userID) + if xerr != nil { + return xerr + } + if member == nil { + return errx.New(errx.Forbidden, "not a member of this organization") + } + return nil +} + // InviteMember invites a new member to the organization func (s *organizationService) InviteMember(ctx context.Context, orgID uuid.UUID, inviterID uuid.UUID, req *models.InviteMemberRequest) (*models.OrganizationInvitation, *errx.Error) { // Refuse to mint an invitation the recipient could never redeem. With @@ -687,9 +702,17 @@ func (s *organizationService) PreviewInvitation(ctx context.Context, token strin if inv == nil { return nil, errx.New(errx.NotFound, "invitation not found") } + // An expired invitation is answered with the fact that it expired and + // nothing else. The token is unguessable, but it can outlive its usefulness + // in an inbox or a log, and there is no reason for a stale one to keep + // handing out the invitee's address and the workspace's name. + if inv.IsExpired() { + return &models.InvitationPreview{Expired: true}, nil + } + preview := &models.InvitationPreview{ Email: inv.Email, - Expired: inv.IsExpired(), + Expired: false, } if inv.Organization != nil { preview.OrganizationName = inv.Organization.Name @@ -899,8 +922,19 @@ func (s *organizationService) GetUserPendingInvitations(ctx context.Context, ema return invitations, nil } -// CancelInvitation cancels a pending invitation -func (s *organizationService) CancelInvitation(ctx context.Context, invitationID uuid.UUID) *errx.Error { +// CancelInvitation cancels a pending invitation. The org id comes from the +// caller's session, never from the request, so the invitation id alone cannot +// address a row outside the caller's workspace. +func (s *organizationService) CancelInvitation(ctx context.Context, orgID, invitationID uuid.UUID) *errx.Error { + inv, err := s.orgRepo.GetInvitationByID(ctx, invitationID) + if err != nil { + errs.CaptureException(err) + return errx.New(errx.Internal, "failed to load invitation") + } + if inv == nil || inv.OrganizationID != orgID { + return errx.ErrNotFound + } + if err := s.orgRepo.DeleteInvitation(ctx, invitationID); err != nil { errs.CaptureException(err) return errx.New(errx.Internal, "failed to cancel invitation") @@ -909,7 +943,22 @@ func (s *organizationService) CancelInvitation(ctx context.Context, invitationID } // TransferOwnership transfers organization ownership -func (s *organizationService) TransferOwnership(ctx context.Context, orgID, newOwnerUserID uuid.UUID) *errx.Error { +func (s *organizationService) TransferOwnership(ctx context.Context, orgID, actorUserID, newOwnerUserID uuid.UUID) *errx.Error { + // Only the current owner may hand the workspace over. The route is gated + // on PermTransferOwnership, but that permission can sit in a custom role, + // and a delegate transferring ownership to themselves is an escalation. + org, oerr := s.orgRepo.GetByID(ctx, orgID) + if oerr != nil { + errs.CaptureException(oerr) + return errx.New(errx.Internal, "failed to load organization") + } + if org == nil { + return errx.ErrNotFound + } + if org.OwnerUserID != actorUserID { + return errx.New(errx.Forbidden, "only the workspace owner can transfer ownership") + } + // Verify new owner is a member member, err := s.orgRepo.GetMember(ctx, orgID, newOwnerUserID) if err != nil { @@ -1428,7 +1477,7 @@ func (s *organizationService) SubmitLimitIncreaseRequest(ctx context.Context, or // on its behalf. Owner check happens at the per-org-permission // layer for org-config writes; for limit requests any active // member is acceptable. - if _, xerr := s.GetMembership(ctx, orgID, submitterID); xerr != nil { + if xerr := s.requireMember(ctx, orgID, submitterID); xerr != nil { return nil, xerr } @@ -1484,7 +1533,10 @@ func (s *organizationService) SubmitLimitIncreaseRequest(ctx context.Context, or return lr, nil } -func (s *organizationService) ListLimitRequestsForOrg(ctx context.Context, orgID uuid.UUID) ([]models.LimitIncreaseRequest, *errx.Error) { +func (s *organizationService) ListLimitRequestsForOrg(ctx context.Context, orgID, requesterID uuid.UUID) ([]models.LimitIncreaseRequest, *errx.Error) { + if xerr := s.requireMember(ctx, orgID, requesterID); xerr != nil { + return nil, xerr + } rows, err := s.orgRepo.ListLimitRequestsForOrg(ctx, orgID) if err != nil { errs.CaptureException(err) diff --git a/internal/app/orgtransfer/blobkey.go b/internal/app/orgtransfer/blobkey.go new file mode 100644 index 000000000..8e91a1736 --- /dev/null +++ b/internal/app/orgtransfer/blobkey.go @@ -0,0 +1,177 @@ +package orgtransfer + +import ( + "context" + "path" + "strings" + + "github.com/google/uuid" + "github.com/jackc/pgx/v5" + "github.com/warmbly/warmbly/internal/models" +) + +// The object keys an archive may write, and nothing else. +// +// A key in the manifest is a string from a file the customer uploaded, so it is +// untrusted in exactly the way a filename is, and two properties of a key make +// that matter. A key carries its own workspace scope, so it has to be settled +// against the workspace doing the import rather than taken at its word. And a +// key under a public prefix is served from `/public` with a Content-Type +// derived from its extension, which is why every upload handler forces that +// extension from a server-side allowlist instead of trusting a filename. +// +// So a key is accepted only when it matches a shape this product actually +// mints, and is written under this destination workspace. +const maxBlobKeyLength = 512 + +// publicBlobExtensions is the set of extensions the upload handlers can produce +// under a public prefix. It is deliberately the same closed image set: anything +// a browser will execute is absent, and so is SVG, which is an image that can +// carry script. +var publicBlobExtensions = map[string]bool{ + ".png": true, + ".jpg": true, + ".jpeg": true, + ".gif": true, + ".webp": true, +} + +// avatarKinds mirrors the two avatar owners the product writes. +var avatarKinds = map[string]bool{"users": true, "organizations": true} + +// blobKeyScope carries what restoreBlobs needs to judge a key: the workspace +// being written to, and the campaigns that workspace owns after the rows have +// been imported. +type blobKeyScope struct { + orgID uuid.UUID + campaigns map[uuid.UUID]bool +} + +// loadBlobKeyScope reads the destination's campaign ids inside the import +// transaction. It runs after the tables are written, so a campaign that arrived +// in this very archive counts, and one belonging to another workspace does not. +func loadBlobKeyScope(ctx context.Context, tx pgx.Tx, orgID uuid.UUID) (blobKeyScope, error) { + scope := blobKeyScope{orgID: orgID, campaigns: map[uuid.UUID]bool{}} + rows, err := tx.Query(ctx, `SELECT id FROM campaigns WHERE organization_id = $1`, orgID) + if err != nil { + return scope, err + } + defer rows.Close() + for rows.Next() { + var id uuid.UUID + if err := rows.Scan(&id); err != nil { + return scope, err + } + scope.campaigns[id] = true + } + return scope, rows.Err() +} + +// plan decides whether the archive may write this key, and under what key it +// should actually be written. +// +// The two org-scoped public prefixes carry the SOURCE workspace's id, because +// that is the path the bytes lived at on the instance that exported them. On a +// cross-instance move the destination workspace has a different id, so the +// segment is rewritten rather than checked. Validating it would refuse every +// legitimate archive; taking it at its word would let the archive choose which +// workspace's prefix the bytes land in. Rewriting does both jobs at once. +// +// The caller has to store the returned key, not the one in the manifest, and +// repoint the row that references it. +func (s blobKeyScope) plan(key string) (string, bool) { + if !s.allows(key) { + return "", false + } + parts := strings.Split(key, "/") + switch parts[0] + "/" { + case models.EmailImageKeyPrefix, "form-assets/": + parts[1] = s.orgID.String() + return strings.Join(parts, "/"), true + } + return key, true +} + +// allows reports whether the archive may write this key on this instance. +func (s blobKeyScope) allows(key string) bool { + if key == "" || len(key) > maxBlobKeyLength { + return false + } + // Reject before normalising: "a/../b" cleaning down to a valid-looking key + // is not the key the archive named, and a key that needs cleaning is not + // one this product mints. + if strings.HasPrefix(key, "/") || strings.ContainsAny(key, "\\\x00") { + return false + } + parts := strings.Split(key, "/") + for _, p := range parts { + if p == "" || p == "." || p == ".." { + return false + } + } + + switch parts[0] + "/" { + case models.EmailImageKeyPrefix, "form-assets/": + // email-images//., form-assets//.. + // Both are served from /public, so the extension has to be an image. + // The workspace segment is not compared: it names the SOURCE workspace + // and plan rewrites it to this one, which is what decides the prefix the + // bytes land under. It still has to be a uuid, so the shape stays fixed. + if len(parts) != 3 || !publicImageName(parts[2]) { + return false + } + _, err := uuid.Parse(parts[1]) + return err == nil + + case "avatars/": + // avatars/{users,organizations}/.. Also public. + return len(parts) == 3 && avatarKinds[parts[1]] && publicImageName(parts[2]) + + case "attachments/": + // attachments//. Private, so the extension is the + // sender's business, but the campaign has to be one this workspace owns. + if len(parts) != 3 { + return false + } + campaignID, err := uuid.Parse(parts[1]) + if err != nil { + return false + } + return s.campaigns[campaignID] + } + + return false +} + +// publicImageName accepts a single path element that ends in an image +// extension. The extension decides the Content-Type the public route serves, so +// this is the check that keeps script off this origin. +func publicImageName(name string) bool { + if name == "" || strings.HasPrefix(name, ".") { + return false + } + return publicBlobExtensions[strings.ToLower(path.Ext(name))] +} + +// publicURLColumn reports whether (table, column) is a column the registry +// declares as holding a browser-loadable blob URL. +// +// Both values come out of the archive manifest, which is a file the customer +// uploaded, so neither may reach a query until it has been matched against the +// compiled registry. Matching here means the identifiers used later are the +// registry's own constants, not the archive's strings. +func publicURLColumn(table, column string) bool { + for i := range Tables { + t := &Tables[i] + if t.Name != table { + continue + } + for _, b := range t.Blobs { + if b.Column == column && b.Kind == BlobKindPublicURL { + return true + } + } + return false + } + return false +} diff --git a/internal/app/orgtransfer/blobkey_scope_test.go b/internal/app/orgtransfer/blobkey_scope_test.go new file mode 100644 index 000000000..4b9276877 --- /dev/null +++ b/internal/app/orgtransfer/blobkey_scope_test.go @@ -0,0 +1,110 @@ +package orgtransfer + +import ( + "testing" + + "github.com/google/uuid" +) + +func TestBlobKeyScopeAllows(t *testing.T) { + org := uuid.MustParse("11111111-1111-4111-8111-111111111111") + mine := uuid.MustParse("33333333-3333-4333-8333-333333333333") + theirs := uuid.MustParse("44444444-4444-4444-8444-444444444444") + s := blobKeyScope{orgID: org, campaigns: map[uuid.UUID]bool{mine: true}} + + ok := []string{ + "email-images/" + org.String() + "/a.png", + "form-assets/" + org.String() + "/logo.JPG", + "avatars/users/abc-1-2.png", + "avatars/organizations/abc-1-2.webp", + "attachments/" + mine.String() + "/x-report.pdf", + } + for _, k := range ok { + if !s.allows(k) { + t.Errorf("expected allowed: %q", k) + } + } + + bad := []string{ + "", + "form-assets/" + org.String() + "/evil.svg", // script-capable image + "form-assets/" + org.String() + "/evil.html", // stored HTML + "form-assets/" + org.String() + "/evil.png.html", + "attachments/" + theirs.String() + "/x.pdf", // another workspace's campaign + "attachments/not-a-uuid/x.pdf", + "users/" + org.String() + "/emails/x/y.emsg", // mailbox bodies never travel + "emails/anything", + "../../etc/passwd", + "form-assets/" + org.String() + "/../../avatars/users/x.png", + "/form-assets/" + org.String() + "/a.png", + "avatars/other/x.png", + "form-assets/" + org.String() + "/a.png/extra", + } + for _, k := range bad { + if s.allows(k) { + t.Errorf("expected refused: %q", k) + } + } +} + +// An archive made on another instance names the SOURCE workspace in the keys of +// its public objects, because that is the path the bytes lived at there. Those +// keys are rewritten to the importing workspace rather than refused: refusing +// would make every cross-instance import silently lose its images, and taking +// the source id at its word would let the archive choose the prefix. +func TestBlobKeyScopeRewritesTheWorkspaceSegment(t *testing.T) { + dest := uuid.MustParse("11111111-1111-4111-8111-111111111111") + source := uuid.MustParse("22222222-2222-4222-8222-222222222222") + campaign := uuid.MustParse("33333333-3333-4333-8333-333333333333") + s := blobKeyScope{orgID: dest, campaigns: map[uuid.UUID]bool{campaign: true}} + + cases := []struct{ in, want string }{ + {"email-images/" + source.String() + "/a.png", "email-images/" + dest.String() + "/a.png"}, + {"form-assets/" + source.String() + "/logo.png", "form-assets/" + dest.String() + "/logo.png"}, + // Already ours: unchanged, which is the same-instance restore case. + {"email-images/" + dest.String() + "/a.png", "email-images/" + dest.String() + "/a.png"}, + // Not workspace-scoped, so nothing to rewrite. + {"attachments/" + campaign.String() + "/x.pdf", "attachments/" + campaign.String() + "/x.pdf"}, + {"avatars/users/a-1-2.png", "avatars/users/a-1-2.png"}, + } + for _, tc := range cases { + got, ok := s.plan(tc.in) + if !ok { + t.Errorf("plan(%q) refused a legitimate key", tc.in) + continue + } + if got != tc.want { + t.Errorf("plan(%q) = %q, want %q", tc.in, got, tc.want) + } + } + + for _, bad := range []string{ + "form-assets/" + source.String() + "/evil.svg", + "users/" + source.String() + "/emails/x/y.emsg", + "attachments/44444444-4444-4444-8444-444444444444/x.pdf", + "form-assets/not-a-uuid/a.png", + } { + if _, ok := s.plan(bad); ok { + t.Errorf("plan(%q) should have refused", bad) + } + } +} + +// The registry gate is what keeps an archive's table and column strings out of +// a query. +func TestPublicURLColumnMatchesTheRegistryOnly(t *testing.T) { + if !publicURLColumn("forms", "logo_url") { + t.Error("forms.logo_url is a declared public-URL blob column") + } + for _, tc := range [][2]string{ + {"forms", "name"}, // real table, not a blob column + {"campaign_attachments", "s3_key"}, // a blob column, but a key not a URL + {"users", "email"}, // not a blob-carrying table + {`forms"; DROP TABLE forms; --`, "logo_url"}, + {"forms", `logo_url"; DROP TABLE forms; --`}, + } { + if publicURLColumn(tc[0], tc[1]) { + t.Errorf("publicURLColumn(%q, %q) should be false", tc[0], tc[1]) + } + } +} diff --git a/internal/app/orgtransfer/import.go b/internal/app/orgtransfer/import.go index abbb068f5..72c853055 100644 --- a/internal/app/orgtransfer/import.go +++ b/internal/app/orgtransfer/import.go @@ -660,9 +660,29 @@ func (s *service) restoreBlobs(ctx context.Context, tx pgx.Tx, orgID uuid.UUID, "Object storage is not configured here, so %d attachment(s) in the archive were not restored.", len(m.Blobs))} } - var failed int - var imageKeys, imageURLs []string + // The keys come out of the archive, which is a file the customer uploaded, + // so the archive does not get to choose where the bytes land. A key is only + // written when it matches a shape this product mints, and a public one is + // re-scoped to this workspace with its extension checked. + scope, err := loadBlobKeyScope(ctx, tx, orgID) + if err != nil { + return []string{"Attachments were not restored: this instance could not confirm which objects the archive is allowed to write."} + } + + var failed, refused int + // Keys under the two org-scoped public prefixes are rewritten to this + // workspace, so the rows that name them have to be repointed or the bytes + // are orphaned at a path nothing reads. + var imageOldKeys, imageNewKeys, imageURLs []string + type urlRewrite struct{ table, column, oldKey, newURL string } + var urlRewrites []urlRewrite + for _, b := range m.Blobs { + destKey, ok := scope.plan(b.Key) + if !ok { + refused++ + continue + } entry, ok := entries[b.Path] if !ok { failed++ @@ -676,15 +696,26 @@ func (s *service) restoreBlobs(ctx context.Context, tx pgx.Tx, orgID uuid.UUID, // A key under a public prefix has to be written public-read again, or // the avatars, form assets and email-body images that reference it by // URL resolve to a 403 on an S3 backend after the move. - if isPublicBlobKey(b.Key) { + if isPublicBlobKey(destKey) { var url string - url, err = s.blobs.PutPublic(ctx, b.Key, rc, "") - if err == nil && url != "" && strings.HasPrefix(b.Key, models.EmailImageKeyPrefix) { - imageKeys = append(imageKeys, b.Key) - imageURLs = append(imageURLs, url) + url, err = s.blobs.PutPublic(ctx, destKey, rc, "") + if err == nil && url != "" { + switch { + case strings.HasPrefix(destKey, models.EmailImageKeyPrefix): + imageOldKeys = append(imageOldKeys, b.Key) + imageNewKeys = append(imageNewKeys, destKey) + imageURLs = append(imageURLs, url) + case publicURLColumn(b.Table, b.Column): + // A form's logo, cover or background is referenced by URL, + // and that URL still names the instance it came from. The + // bytes are here now, so the row is repointed at this one. + // The table and column are the archive's strings, so they + // are only used after matching the compiled registry. + urlRewrites = append(urlRewrites, urlRewrite{b.Table, b.Column, b.Key, url}) + } } } else { - err = s.blobs.Put(ctx, b.Key, rc, "") + err = s.blobs.Put(ctx, destKey, rc, "") } _ = rc.Close() if err != nil { @@ -692,22 +723,47 @@ func (s *service) restoreBlobs(ctx context.Context, tx pgx.Tx, orgID uuid.UUID, } } - warnings := make([]string, 0, 2) - // An imported image row still carries the URL the source instance served - // it from, so a body composed here would point every recipient at the old - // host. The bytes now live here, so the row is repointed at this one. - if len(imageKeys) > 0 { + warnings := make([]string, 0, 3) + // An imported image row still carries the key and the URL the source + // instance used. The bytes now live here, under a key scoped to this + // workspace, so the row is repointed at both. Matching on the OLD key is + // what makes this work: that is still what the row holds at this point. + if len(imageOldKeys) > 0 { if _, err := tx.Exec(ctx, ` - UPDATE email_images SET url = fresh.url - FROM (SELECT unnest($2::text[]) AS storage_key, unnest($3::text[]) AS url) AS fresh - WHERE email_images.organization_id = $1 AND email_images.storage_key = fresh.storage_key - `, orgID, imageKeys, imageURLs); err != nil { + UPDATE email_images SET storage_key = fresh.new_key, url = fresh.url + FROM ( + SELECT unnest($2::text[]) AS old_key, + unnest($3::text[]) AS new_key, + unnest($4::text[]) AS url + ) AS fresh + WHERE email_images.organization_id = $1 AND email_images.storage_key = fresh.old_key + `, orgID, imageOldKeys, imageNewKeys, imageURLs); err != nil { warnings = append(warnings, "Email images were restored but still name the instance they came from; re-upload them if that host goes away.") } } + + // Form logos, covers and backgrounds are referenced by URL rather than by + // key. The table and column were matched against the compiled registry + // above, so they are this binary's own identifiers; the values are bound. + for _, rw := range urlRewrites { + stmt := fmt.Sprintf( + `UPDATE %s SET %s = $1 WHERE organization_id = $2 AND %s LIKE $3`, + pgx.Identifier{rw.table}.Sanitize(), + pgx.Identifier{rw.column}.Sanitize(), + pgx.Identifier{rw.column}.Sanitize(), + ) + if _, err := tx.Exec(ctx, stmt, rw.newURL, orgID, "%"+rw.oldKey); err != nil { + warnings = append(warnings, "Some form images were restored but still name the instance they came from; re-upload them if that host goes away.") + break + } + } if failed > 0 { warnings = append(warnings, fmt.Sprintf("%d attachment(s) could not be restored to object storage.", failed)) } + if refused > 0 { + warnings = append(warnings, fmt.Sprintf( + "%d object(s) in the archive named a storage location this workspace does not own, so they were not written.", refused)) + } return warnings } diff --git a/internal/app/orgtransfer/jobs.go b/internal/app/orgtransfer/jobs.go index 47cbce75a..4e9e30c26 100644 --- a/internal/app/orgtransfer/jobs.go +++ b/internal/app/orgtransfer/jobs.go @@ -387,7 +387,7 @@ func (s *service) RequestImport( key := uploadObjectKey(orgID, uuid.New()) if err := s.blobs.Put(ctx, key, io.NewSectionReader(archive, 0, size), "application/zip"); err != nil { errs.CaptureException(err) - return nil, errx.NewPublic(errx.Internal, "The archive could not be stored for import.") + return nil, errx.New(errx.Internal, "The archive could not be stored for import.") } job.ArchiveKey = &key } diff --git a/internal/app/orgtransfer/spec.go b/internal/app/orgtransfer/spec.go index a3570f49d..e0a3adcf8 100644 --- a/internal/app/orgtransfer/spec.go +++ b/internal/app/orgtransfer/spec.go @@ -227,6 +227,12 @@ var Tables = []Table{ Name: "webhook_endpoints", Group: models.OrgDataGroupCore, Scope: scopeOrg, ResetOnImport: []string{"last_success_at", "last_failure_at", "last_failure_reason", "consecutive_failures", "first_failure_at", "auto_disabled_at", "disabled_reason"}, + // The signing secret is sealed under the instance key, so it has to be + // re-sealed on the way across or the destination hands the receiver + // signatures computed from ciphertext it could not read. + Secrets: []SecretColumn{ + {Column: "secret", Domain: KeyDomainInstance}, + }, }, { Name: "outreach_settings", Group: models.OrgDataGroupCore, diff --git a/internal/app/passkey/cache.go b/internal/app/passkey/cache.go index 305884f58..0af3e3387 100644 --- a/internal/app/passkey/cache.go +++ b/internal/app/passkey/cache.go @@ -33,8 +33,8 @@ func (s *service) saveSession(ctx context.Context, key string, data *webauthn.Se } if err := s.cache.Set(ctx, key, raw, CeremonyTTL).Err(); err != nil { - errs.CaptureException(err, errs.Tag("cache.key", "webauthn"), errs.Tag("cache.op", "set")) - return errx.ErrPasskeyUnavailable + errs.CaptureException(err) + return errx.InternalError() } return nil @@ -49,11 +49,8 @@ func (s *service) takeSession(ctx context.Context, key string) (*webauthn.Sessio if errors.Is(err, redis.Nil) { return nil, errx.ErrPasskeySession } - // A store that could not be read is not an expired ceremony: saying - // "your passkey request expired" would send someone to start again - // into the same failure. - errs.CaptureException(err, errs.Tag("cache.key", "webauthn"), errs.Tag("cache.op", "getdel")) - return nil, errx.ErrPasskeyUnavailable + errs.CaptureException(err) + return nil, errx.InternalError() } var data webauthn.SessionData diff --git a/internal/app/passkey/login.go b/internal/app/passkey/login.go index 79deb9f76..1482b13c6 100644 --- a/internal/app/passkey/login.go +++ b/internal/app/passkey/login.go @@ -85,7 +85,10 @@ func (s *service) FinishLogin(ctx context.Context, session string, credential [] // Social sign-in is the opposite case and does run the 2FA gate // (auth.finishLoginAs), because there the second factor is the identity // provider's business, not something this deployment can observe. - tok, xerr := s.token.GenerateSession(ctx, user.ID, user.Email, ipaddr, userAgent, token.AuthProviderWebAuthn) + // A passkey is itself multi-factor: the credential never leaves the device + // and the platform unlocks it with a biometric or a PIN. That is why this + // path skips the TOTP gate, and it is why the session counts as verified. + tok, xerr := s.token.GenerateMFASession(ctx, user.ID, user.Email, ipaddr, userAgent, token.AuthProviderWebAuthn) if xerr != nil { return nil, xerr } diff --git a/internal/app/poollink/oauth.go b/internal/app/poollink/oauth.go index 81ad6fb36..bdccaed34 100644 --- a/internal/app/poollink/oauth.go +++ b/internal/app/poollink/oauth.go @@ -179,7 +179,7 @@ func (s *service) connectBrokered(ctx context.Context, st brokerState, code stri } remoteID := uuid.New() if err := s.repo.EnrollMailbox(ctx, &models.PoolLinkMailbox{InstanceID: inst.ID, RemoteID: remoteID, EmailAccountID: acc.ID, Managed: true}); err != nil { - _ = s.emailSvc.Delete(ctx, orgID.String(), acc.ID.String()) + _ = s.emailSvc.Delete(ctx, userID, acc.ID.String()) return uuid.Nil, errx.InternalError() } s.startWarmup(ctx, userID, acc.ID) diff --git a/internal/app/poollink/service.go b/internal/app/poollink/service.go index e35ad200d..d7bcd6e34 100644 --- a/internal/app/poollink/service.go +++ b/internal/app/poollink/service.go @@ -463,7 +463,7 @@ func (s *service) Enroll(ctx context.Context, inst *models.PoolLinkInstance, req } if err := s.repo.EnrollMailbox(ctx, &models.PoolLinkMailbox{InstanceID: inst.ID, RemoteID: req.RemoteID, EmailAccountID: acc.ID}); err != nil { - _ = s.emailSvc.Delete(ctx, orgID.String(), acc.ID.String()) + _ = s.emailSvc.Delete(ctx, userID, acc.ID.String()) return nil, errx.InternalError() } @@ -645,7 +645,11 @@ func (s *service) Unenroll(ctx context.Context, inst *models.PoolLinkInstance, r } // A managed mailbox belongs to the workspace; only the link goes. if !m.Managed { - if xerr := s.emailSvc.Delete(ctx, inst.OrganizationID.String(), m.EmailAccountID.String()); xerr != nil && xerr != errx.ErrNotFound { + userID, xerr := s.ownerUserID(ctx, inst) + if xerr != nil { + return xerr + } + if xerr := s.emailSvc.Delete(ctx, userID, m.EmailAccountID.String()); xerr != nil && xerr != errx.ErrNotFound { return xerr } } diff --git a/internal/app/research/service.go b/internal/app/research/service.go index 922b16865..7a9681f81 100644 --- a/internal/app/research/service.go +++ b/internal/app/research/service.go @@ -94,7 +94,7 @@ func (s *service) ListRuns(ctx context.Context, orgID, contactID uuid.UUID, limi func (s *service) RunResearch(ctx context.Context, inv aitools.Invocation, contactID uuid.UUID, objective, idempotencyKey string) (*models.ContactResearchRun, *errx.Error) { if s.provider == nil { - return nil, errx.NewPublic(errx.ServiceUnavailable, "AI research is not configured") + return nil, errx.New(errx.ServiceUnavailable, "AI research is not configured") } // Pre-check balance AND the abuse caps so an out-of-credits or rate-capped // org never does free research work (the charge happens on save, after the diff --git a/internal/app/socket/cache.go b/internal/app/socket/cache.go index 099376704..9848857c3 100644 --- a/internal/app/socket/cache.go +++ b/internal/app/socket/cache.go @@ -5,6 +5,7 @@ import ( "time" "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/observability/errs" ) @@ -12,20 +13,10 @@ func getTokenKey(id uuid.UUID) string { return "ws_verify:" + id.String() } -// saveToken records the handshake nonce, and is best-effort on purpose. -// -// The nonce is already inside the signed token, and the realtime service -// verifies the token's signature and claims rather than looking this key up -// (realtime/lib/realtime/auth.ex). So the key is written for a revocation path -// that does not exist yet, and refusing to issue a token when it could not be -// written made an unreadable cache the single thing standing between every -// signed-in tab and live updates: a Redis provider over its request quota took -// realtime down for everyone and filed 2,815 issues doing it. -// -// It is still written, and still reported, so the day something does read it -// the key is there and an operator has been told when it was not. -func (s *socketService) saveToken(ctx context.Context, id uuid.UUID, nonce string, expiresAt time.Time) { +func (s *socketService) saveToken(ctx context.Context, id uuid.UUID, nonce string, expiresAt time.Time) *errx.Error { if err := s.cache.SetEx(ctx, getTokenKey(id), nonce, time.Until(expiresAt)).Err(); err != nil { - errs.CaptureException(err, errs.Tag("cache.key", "ws_verify")) + errs.CaptureException(err) + return errx.InternalError() } + return nil } diff --git a/internal/app/socket/gen.go b/internal/app/socket/gen.go index 74d7971dd..9709a2362 100644 --- a/internal/app/socket/gen.go +++ b/internal/app/socket/gen.go @@ -5,6 +5,7 @@ import ( "time" "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/app/token" "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/observability/errs" "github.com/warmbly/warmbly/internal/pkg/crypt" @@ -20,13 +21,15 @@ func (s *socketService) GenerateWebsocketToken(ctx context.Context, userID uuid. return "", errx.InternalError() } - wsToken, err := s.tokenService.GenerateToken(userID, id, "", nonce, issuedAt, expiresAt) + wsToken, err := s.tokenService.GenerateTokenFor(token.PurposeWebSocket, userID, id, "", nonce, issuedAt, expiresAt) if err != nil { errs.CaptureException(err) return "", errx.InternalError() } - s.saveToken(ctx, id, nonce, expiresAt) + if err := s.saveToken(ctx, id, nonce, expiresAt); err != nil { + return "", err + } return wsToken, nil } diff --git a/internal/app/stripe/service.go b/internal/app/stripe/service.go index 9992e9136..e62f2cdbf 100644 --- a/internal/app/stripe/service.go +++ b/internal/app/stripe/service.go @@ -403,7 +403,7 @@ func (s *stripeService) CreateCreditCheckoutSession(ctx context.Context, userID, priceID = s.cfg.CreditPackPriceIDs[packKey] } if priceID == "" { - return nil, errx.NewPublic(errx.ServiceUnavailable, "Credit packs are not configured.") + return nil, errx.New(errx.ServiceUnavailable, "credit packs are not configured") } sub, err := s.subRepo.GetByOrganizationID(ctx, orgID) diff --git a/internal/app/token/config.go b/internal/app/token/config.go index efec9f5ac..bb0cb0fc9 100644 --- a/internal/app/token/config.go +++ b/internal/app/token/config.go @@ -16,3 +16,22 @@ const ( // their own values, so the security page can name what was actually used. AuthProviderOIDC = "oidc" ) + +// Token purposes. Every JWT this service signs carries one, and each verifier +// requires the purpose it expects. +// +// Without it, all of these tokens were interchangeable: they share one signing +// key and one claim shape, so a password-reset link token or the challenge +// token issued after a password but before the emailed code would open a +// websocket and stream a workspace's events. The Go side was safe only because +// each token is separately bound to a nonce in Redis or a row in `sessions`; +// the realtime service checks neither, and had nothing else to go on. +const ( + PurposeAccess = "access" + PurposeRefresh = "refresh" + PurposeWebSocket = "ws" + PurposeLoginCode = "login" + PurposeRegistration = "registration" + PurposePasswordReset = "reset" + PurposeTwoFAPending = "2fa" +) diff --git a/internal/app/token/gen.go b/internal/app/token/gen.go index c708226d1..457573f7b 100644 --- a/internal/app/token/gen.go +++ b/internal/app/token/gen.go @@ -20,15 +20,27 @@ type TokenClaims struct { SessionID uuid.UUID `json:"sid"` Email string `json:"email"` Nonce string `json:"nonce"` + // Purpose names what this token may be spent on. See the Purpose* + // constants: one signing key issues all of them, so this is what keeps a + // password-reset token from being accepted as a session. + Purpose string `json:"purpose,omitempty"` jwt.RegisteredClaims } +// GenerateToken mints a token for a purpose. Callers use the Purpose* +// constants; a token minted with the wrong one is refused at the verifier that +// expects a different one. func (s *tokenService) GenerateToken(userID, sessionID uuid.UUID, email, nonce string, issuedAt, expiresAt time.Time) (string, error) { + return s.GenerateTokenFor(PurposeAccess, userID, sessionID, email, nonce, issuedAt, expiresAt) +} + +func (s *tokenService) GenerateTokenFor(purpose string, userID, sessionID uuid.UUID, email, nonce string, issuedAt, expiresAt time.Time) (string, error) { claims := TokenClaims{ UserID: userID, SessionID: sessionID, Email: email, Nonce: nonce, + Purpose: purpose, RegisteredClaims: jwt.RegisteredClaims{ ExpiresAt: jwt.NewNumericDate(expiresAt), IssuedAt: jwt.NewNumericDate(issuedAt), @@ -40,11 +52,8 @@ func (s *tokenService) GenerateToken(userID, sessionID uuid.UUID, email, nonce s func (s *tokenService) VerifyToken(tokenStr string) (*TokenClaims, *errx.Error) { token, err := jwt.ParseWithClaims(tokenStr, &TokenClaims{}, func(token *jwt.Token) (any, error) { - if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { - return nil, errx.ErrToken - } return []byte(s.AuthSecret), nil - }) + }, jwt.WithValidMethods([]string{"HS256"}), jwt.WithExpirationRequired()) if err != nil { return nil, errx.ErrToken @@ -63,10 +72,20 @@ func (s *tokenService) VerifyToken(tokenStr string) (*TokenClaims, *errx.Error) } func (s *tokenService) GenerateSession(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string) (*models.Token, *errx.Error) { - return s.GenerateSessionWithOrg(ctx, userID, email, ipaddr, userAgent, authProvider, nil) + return s.generateSession(ctx, userID, email, ipaddr, userAgent, authProvider, nil, false) +} + +// GenerateMFASession marks the session as having presented a second factor. +// Only the TOTP and passkey paths may call it. +func (s *tokenService) GenerateMFASession(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string) (*models.Token, *errx.Error) { + return s.generateSession(ctx, userID, email, ipaddr, userAgent, authProvider, nil, true) } func (s *tokenService) GenerateSessionWithOrg(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string, orgID *uuid.UUID) (*models.Token, *errx.Error) { + return s.generateSession(ctx, userID, email, ipaddr, userAgent, authProvider, orgID, false) +} + +func (s *tokenService) generateSession(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string, orgID *uuid.UUID, mfaVerified bool) (*models.Token, *errx.Error) { // A session always starts inside a workspace. Without one the caller would // reach org-scoped writes with no tenant, and the rows they create are the // ones that later skip suppression and the entitlement gate (issue #168). @@ -124,6 +143,7 @@ func (s *tokenService) GenerateSessionWithOrg(ctx context.Context, userID uuid.U OSName: userAgentInfo.OS, AuthProvider: authProvider, + MFAVerified: mfaVerified, } tx, err := s.db.Begin(ctx) @@ -145,7 +165,7 @@ func (s *tokenService) GenerateSessionWithOrg(ctx context.Context, userID uuid.U } session.AccessNonce = accessNonce - accessToken, err := s.GenerateToken(userID, session.ID, email, accessNonce, issuedAt, accessTokenExpiresAt) + accessToken, err := s.GenerateTokenFor(PurposeAccess, userID, session.ID, email, accessNonce, issuedAt, accessTokenExpiresAt) if err != nil { errs.CaptureException(err) return nil, errx.InternalError() @@ -160,7 +180,7 @@ func (s *tokenService) GenerateSessionWithOrg(ctx context.Context, userID uuid.U } session.RefreshNonce = refreshNonce - refreshToken, err := s.GenerateToken(userID, session.ID, email, refreshNonce, issuedAt, refreshTokenExpiresAt) + refreshToken, err := s.GenerateTokenFor(PurposeRefresh, userID, session.ID, email, refreshNonce, issuedAt, refreshTokenExpiresAt) if err != nil { errs.CaptureException(err) return nil, errx.InternalError() diff --git a/internal/app/token/purpose_test.go b/internal/app/token/purpose_test.go new file mode 100644 index 000000000..69329cba2 --- /dev/null +++ b/internal/app/token/purpose_test.go @@ -0,0 +1,130 @@ +package token + +import ( + "testing" + "time" + + "github.com/google/uuid" +) + +// A token minted for one flow must not be spendable on another. This is the +// regression for the realtime socket accepting a password-reset link token, +// and for anything else that shares the signing key. +func TestTokenPurposeIsEnforced(t *testing.T) { + s := &tokenService{AuthSecret: "test-secret-at-least-32-characters-long"} + + userID, sessionID := uuid.New(), uuid.New() + now := time.Now() + exp := now.Add(10 * time.Minute) + + purposes := []string{ + PurposeAccess, + PurposeRefresh, + PurposeWebSocket, + PurposeLoginCode, + PurposeRegistration, + PurposePasswordReset, + PurposeTwoFAPending, + } + + for _, minted := range purposes { + tok, err := s.GenerateTokenFor(minted, userID, sessionID, "", "nonce", now, exp) + if err != nil { + t.Fatalf("mint %s: %v", minted, err) + } + + if _, xerr := s.VerifyTokenFor(minted, tok); xerr != nil { + t.Errorf("a %s token should verify as %s, got %v", minted, minted, xerr) + } + + for _, other := range purposes { + if other == minted { + continue + } + if _, xerr := s.VerifyTokenFor(other, tok); xerr == nil { + t.Errorf("a %s token must not be accepted as %s", minted, other) + } + } + } +} + +// Tokens issued before the purpose claim existed are still inside their window +// during a deploy, so they read as access tokens rather than signing everyone +// out. They must not satisfy any other purpose. +func TestLegacyTokenIsAccessOnly(t *testing.T) { + s := &tokenService{AuthSecret: "test-secret-at-least-32-characters-long"} + now := time.Now() + + legacy, err := s.GenerateTokenFor("", uuid.New(), uuid.New(), "", "nonce", now, now.Add(time.Minute)) + if err != nil { + t.Fatalf("mint: %v", err) + } + + if _, xerr := s.VerifyTokenFor(PurposeAccess, legacy); xerr != nil { + t.Errorf("a token with no purpose should still work as an access token: %v", xerr) + } + if _, xerr := s.VerifyTokenFor(PurposeWebSocket, legacy); xerr == nil { + t.Error("a token with no purpose must not open a websocket") + } + if _, xerr := s.VerifyTokenFor(PurposePasswordReset, legacy); xerr == nil { + t.Error("a token with no purpose must not pass as a password reset") + } +} + +// The verifier pins HS256 rather than accepting the HMAC family, and requires +// an expiry. +func TestVerifierRejectsUnsignedAndUnexpiring(t *testing.T) { + s := &tokenService{AuthSecret: "test-secret-at-least-32-characters-long"} + + // alg=none, the classic. + const none = "eyJhbGciOiJub25lIiwidHlwIjoiSldUIn0.eyJzdWIiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDAifQ." + if _, xerr := s.VerifyToken(none); xerr == nil { + t.Error("an unsigned token must be refused") + } + + expired, err := s.GenerateTokenFor(PurposeAccess, uuid.New(), uuid.New(), "", "n", + time.Now().Add(-2*time.Hour), time.Now().Add(-time.Hour)) + if err != nil { + t.Fatalf("mint: %v", err) + } + if _, xerr := s.VerifyToken(expired); xerr == nil { + t.Error("an expired token must be refused") + } +} + +// Rotation has to mint a refresh token this same function will accept next +// time. Minting it through GenerateToken, which defaults to PurposeAccess, +// produced a session that survived exactly one refresh and then signed the +// person out for good about a day after every login. +func TestRotatedRefreshTokenVerifiesAsRefresh(t *testing.T) { + s := &tokenService{AuthSecret: "test-secret-at-least-32-characters-long"} + + userID, sessionID := uuid.New(), uuid.New() + now := time.Now() + + // What refresh.go mints on rotation, for both halves of the pair. + access, err := s.GenerateTokenFor(PurposeAccess, userID, sessionID, "", "a", now, now.Add(AccessTokenLifeTime)) + if err != nil { + t.Fatalf("mint access: %v", err) + } + refresh, err := s.GenerateTokenFor(PurposeRefresh, userID, sessionID, "", "r", now, now.Add(RefreshTokenLifeTime)) + if err != nil { + t.Fatalf("mint refresh: %v", err) + } + + // The rotated refresh token must satisfy the check RefreshToken performs. + if _, xerr := s.VerifyTokenFor(PurposeRefresh, refresh); xerr != nil { + t.Errorf("a rotated refresh token must verify as a refresh token: %v", xerr) + } + // And the rotated access token must satisfy ValidateAccessToken's check. + if _, xerr := s.VerifyTokenFor(PurposeAccess, access); xerr != nil { + t.Errorf("a rotated access token must verify as an access token: %v", xerr) + } + // They are still not interchangeable. + if _, xerr := s.VerifyTokenFor(PurposeAccess, refresh); xerr == nil { + t.Error("a refresh token must not pass as an access token") + } + if _, xerr := s.VerifyTokenFor(PurposeRefresh, access); xerr == nil { + t.Error("an access token must not pass as a refresh token") + } +} diff --git a/internal/app/token/reauth.go b/internal/app/token/reauth.go new file mode 100644 index 000000000..d87142520 --- /dev/null +++ b/internal/app/token/reauth.go @@ -0,0 +1,31 @@ +package token + +import ( + "context" + "time" + + "github.com/google/uuid" + "github.com/warmbly/warmbly/internal/errx" + "github.com/warmbly/warmbly/internal/observability/errs" +) + +// ReauthWindow is how long a re-authentication counts for. +// +// Long enough to complete the thing you re-authenticated in order to do (mint a +// key, register a passkey, hand over a workspace), short enough that walking +// away from an unlocked laptop does not leave the window open. +const ReauthWindow = 5 * time.Minute + +// StampReauth records that this session just re-proved the account holder. +func (s *tokenService) StampReauth(ctx context.Context, sessionID uuid.UUID) *errx.Error { + now := time.Now() + if err := s.tokenRepository.StampReauth(ctx, sessionID, now); err != nil { + errs.CaptureException(err) + return errx.InternalError() + } + // The cached copy still says "never", and the middleware reads the cache. + if err := s.deleteSession(ctx, sessionID); err != nil { + return err + } + return nil +} diff --git a/internal/app/token/refresh.go b/internal/app/token/refresh.go index 2b178729f..623908b4d 100644 --- a/internal/app/token/refresh.go +++ b/internal/app/token/refresh.go @@ -11,7 +11,7 @@ import ( ) func (s *tokenService) RefreshToken(ctx context.Context, refreshToken string) (*models.Token, *errx.Error) { - t, err := s.VerifyToken(refreshToken) + t, err := s.VerifyTokenFor(PurposeRefresh, refreshToken) if err != nil { return nil, err } @@ -43,7 +43,7 @@ func (s *tokenService) RefreshToken(ctx context.Context, refreshToken string) (* return nil, errx.InternalError() } - newAccessToken, xerr := s.GenerateToken(sess.UserID, sess.ID, "", accessNonce, issuedAt, accessTokenExpiresAt) + newAccessToken, xerr := s.GenerateTokenFor(PurposeAccess, sess.UserID, sess.ID, "", accessNonce, issuedAt, accessTokenExpiresAt) if xerr != nil { errs.CaptureException(xerr) return nil, errx.InternalError() @@ -56,7 +56,11 @@ func (s *tokenService) RefreshToken(ctx context.Context, refreshToken string) (* return nil, errx.InternalError() } - newRefreshToken, xerr := s.GenerateToken(sess.UserID, sess.ID, "", refreshNonce, issuedAt, refreshTokenExpiresAt) + // Explicitly PurposeRefresh. GenerateToken defaults to PurposeAccess, so + // minting the rotated refresh token through it produced one this very + // function would refuse on the next call: the session survived one refresh + // and died on the second, about a day after every sign-in. + newRefreshToken, xerr := s.GenerateTokenFor(PurposeRefresh, sess.UserID, sess.ID, "", refreshNonce, issuedAt, refreshTokenExpiresAt) if xerr != nil { errs.CaptureException(xerr) return nil, errx.InternalError() diff --git a/internal/app/token/service.go b/internal/app/token/service.go index 69625af3f..47d8d8bad 100644 --- a/internal/app/token/service.go +++ b/internal/app/token/service.go @@ -15,9 +15,20 @@ import ( type TokenService interface { GenerateToken(userID, sessionID uuid.UUID, email, nonce string, issuedAt, expiresAt time.Time) (string, error) + // GenerateTokenFor mints a token for a named purpose (see the Purpose* + // constants). Every verifier requires the purpose it expects, so a token + // minted for one flow cannot be spent on another. + GenerateTokenFor(purpose string, userID, sessionID uuid.UUID, email, nonce string, issuedAt, expiresAt time.Time) (string, error) VerifyToken(tokenStr string) (*TokenClaims, *errx.Error) + // VerifyTokenFor also requires the token to have been minted for this + // purpose, so one flow's token cannot be spent on another. + VerifyTokenFor(purpose, tokenStr string) (*TokenClaims, *errx.Error) GenerateSession(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string) (*models.Token, *errx.Error) GenerateSessionWithOrg(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string, orgID *uuid.UUID) (*models.Token, *errx.Error) + // GenerateMFASession is GenerateSession for a sign-in that presented a + // second factor. The flag is recorded on the session so a later request can + // require it, which is what the admin panel does. + GenerateMFASession(ctx context.Context, userID uuid.UUID, email, ipaddr, userAgent, authProvider string) (*models.Token, *errx.Error) WireSignInAlerter(a SignInAlerter) GetSession(ctx context.Context, sessionID uuid.UUID) (*models.Session, *errx.Error) ValidateAccessToken(ctx context.Context, accessToken string) (*models.Session, *errx.Error) @@ -30,6 +41,9 @@ type TokenService interface { ListSessions(ctx context.Context, userID, currentSessionID uuid.UUID) ([]SessionView, *errx.Error) RevokeSessionByID(ctx context.Context, userID, sessionID, currentSessionID uuid.UUID) *errx.Error RevokeOtherSessions(ctx context.Context, userID, currentSessionID uuid.UUID) *errx.Error + // StampReauth records that this session just re-proved the account holder, + // which is what RequireFreshAuth checks before a sensitive change. + StampReauth(ctx context.Context, sessionID uuid.UUID) *errx.Error // Organization switching SwitchOrganization(ctx context.Context, sessionID uuid.UUID, orgID *uuid.UUID) *errx.Error diff --git a/internal/app/token/sessions.go b/internal/app/token/sessions.go index c59470225..fd50da003 100644 --- a/internal/app/token/sessions.go +++ b/internal/app/token/sessions.go @@ -21,6 +21,7 @@ type SessionView struct { Country string `json:"location_country"` CountryCode string `json:"country_code"` AuthProvider string `json:"auth_provider"` + MFAVerified bool `json:"mfa_verified"` CreatedAt time.Time `json:"created_at"` LastActiveAt time.Time `json:"last_active_at"` } @@ -40,6 +41,7 @@ func toSessionView(sess *models.Session, currentID uuid.UUID) SessionView { Country: sess.LocationCountry, CountryCode: sess.LocationCountryCode, AuthProvider: sess.AuthProvider, + MFAVerified: sess.MFAVerified, CreatedAt: sess.CreatedAt, LastActiveAt: lastActive, } diff --git a/internal/app/token/verify.go b/internal/app/token/verify.go index d8a46775b..84f28a720 100644 --- a/internal/app/token/verify.go +++ b/internal/app/token/verify.go @@ -39,7 +39,7 @@ func sameTokenIssueTime(a, b time.Time) bool { } func (s *tokenService) ValidateAccessToken(ctx context.Context, accessToken string) (*models.Session, *errx.Error) { - t, err := s.VerifyToken(accessToken) + t, err := s.VerifyTokenFor(PurposeAccess, accessToken) if err != nil { return nil, err } @@ -66,3 +66,26 @@ func (s *tokenService) ValidateAccessToken(ctx context.Context, accessToken stri return session, nil } + +// VerifyTokenFor is VerifyToken plus the check that the token was minted for +// this flow. +// +// A token with no purpose is treated as an access token: tokens issued before +// the claim existed are still inside their 12-hour window during a deploy, and +// refusing them would sign everybody out. Every other flow demands its purpose +// explicitly, so that leniency cannot be used to spend a reset or challenge +// token as a session. +func (s *tokenService) VerifyTokenFor(purpose, tokenStr string) (*TokenClaims, *errx.Error) { + claims, err := s.VerifyToken(tokenStr) + if err != nil { + return nil, err + } + got := claims.Purpose + if got == "" { + got = PurposeAccess + } + if got != purpose { + return nil, errx.ErrToken + } + return claims, nil +} diff --git a/internal/app/twofa/login.go b/internal/app/twofa/login.go index f21c40dd4..d5bdf728e 100644 --- a/internal/app/twofa/login.go +++ b/internal/app/twofa/login.go @@ -22,7 +22,7 @@ func (s *service) CreatePendingChallenge(ctx context.Context, userID uuid.UUID) return "", 0, errx.InternalError() } now := time.Now() - pendTok, terr := s.tokens.GenerateToken(userID, sid, "", nonce, now, now.Add(pendingTTL)) + pendTok, terr := s.tokens.GenerateTokenFor(token.PurposeTwoFAPending, userID, sid, "", nonce, now, now.Add(pendingTTL)) if terr != nil { return "", 0, errx.InternalError() } @@ -35,7 +35,7 @@ func (s *service) CreatePendingChallenge(ctx context.Context, userID uuid.UUID) // VerifyLogin validates the pending token + code (TOTP or recovery) and, on // success, mints a real session via the SAME path as a normal login. func (s *service) VerifyLogin(ctx context.Context, pendingToken, code, ipaddr, userAgent string) (*models.Token, *errx.Error) { - claims, xerr := s.tokens.VerifyToken(pendingToken) + claims, xerr := s.tokens.VerifyTokenFor(token.PurposeTwoFAPending, pendingToken) if xerr != nil { return nil, errx.New(errx.BadRequest, "Invalid or expired session") } @@ -74,5 +74,7 @@ func (s *service) VerifyLogin(ctx context.Context, pendingToken, code, ipaddr, u // Single-use: delete the pending record BEFORE minting (delete-then-mint // closes a double-spend race). s.deletePending(ctx, claims.SessionID) - return s.tokens.GenerateSession(ctx, claims.UserID, "", ipaddr, userAgent, token.AuthProviderEmail) + // The password was checked before the challenge was minted and a TOTP or + // recovery code has just been checked here, so this session has two factors. + return s.tokens.GenerateMFASession(ctx, claims.UserID, "", ipaddr, userAgent, token.AuthProviderEmail) } diff --git a/internal/app/twofa/service.go b/internal/app/twofa/service.go index 3b2098344..f7606db87 100644 --- a/internal/app/twofa/service.go +++ b/internal/app/twofa/service.go @@ -13,6 +13,7 @@ import ( "github.com/warmbly/warmbly/internal/errx" "github.com/warmbly/warmbly/internal/infrastructure/cache" "github.com/warmbly/warmbly/internal/models" + "github.com/warmbly/warmbly/internal/observability/errs" "github.com/warmbly/warmbly/internal/repository" ) @@ -36,6 +37,12 @@ type Service interface { EnrollStart(ctx context.Context, userID uuid.UUID) (*EnrollStart, *errx.Error) EnrollConfirm(ctx context.Context, userID uuid.UUID, code string) ([]string, *errx.Error) Disable(ctx context.Context, userID uuid.UUID, code string) *errx.Error + // VerifyCurrentCode checks a TOTP or recovery code for a user who is + // already signed in, without changing anything. Used by the re-auth + // endpoint so someone with 2FA on can confirm with their authenticator + // rather than retyping a password they may not have (passkey and SSO + // accounts often have none). + VerifyCurrentCode(ctx context.Context, userID uuid.UUID, code string) bool // CreatePendingChallenge mints a short-lived single-use pending token for a // 2FA login challenge (called from the login gate after the email code). CreatePendingChallenge(ctx context.Context, userID uuid.UUID) (string, int, *errx.Error) @@ -79,6 +86,18 @@ func (s *service) Disable(ctx context.Context, userID uuid.UUID, code string) *e return nil } +// VerifyCurrentCode reports whether the code is a valid TOTP or recovery code +// for this user right now. A recovery code is consumed, and a TOTP step is +// retired, exactly as they are at sign-in: a code that has confirmed something +// must not confirm a second thing. +func (s *service) VerifyCurrentCode(ctx context.Context, userID uuid.UUID, code string) bool { + row, err := s.repo.Get(ctx, userID) + if err != nil || row == nil || !row.Enabled { + return false + } + return s.validCode(ctx, userID, row, code) +} + // validCode checks a code against the user's TOTP secret OR consumes a matching // recovery code. Used by both Disable and VerifyLogin. func (s *service) validCode(ctx context.Context, userID uuid.UUID, row *models.UserTOTP, code string) bool { @@ -89,7 +108,19 @@ func (s *service) validCode(ctx context.Context, userID uuid.UUID, row *models.U if err != nil { return false } - return ValidateCode(secret, code) + step, ok := ValidateCodeStep(secret, code) + if !ok { + return false + } + // A correct code is only accepted once. Its step is retired here, so the + // same digits presented again inside their ±1-step validity window are + // refused rather than signing someone in a second time. + fresh, cerr := s.repo.ConsumeTOTPStep(ctx, userID, step) + if cerr != nil { + errs.CaptureException(cerr) + return false + } + return fresh } // --- pending-challenge cache (Redis, mirrors the auth login_sess pattern) --- diff --git a/internal/app/twofa/totp.go b/internal/app/twofa/totp.go index babc86d37..e645c83cb 100644 --- a/internal/app/twofa/totp.go +++ b/internal/app/twofa/totp.go @@ -59,21 +59,37 @@ func hotp(secret string, counter uint64) (string, error) { // ValidateCode checks a 6-digit code against the secret, allowing ±1 step of // clock skew. Constant-time compare on each candidate. func ValidateCode(secret, code string) bool { + _, ok := ValidateCodeStep(secret, code) + return ok +} + +// ValidateCodeStep is ValidateCode plus the time step the code matched. +// +// The caller needs the step to refuse a replay: a code stays valid across its +// own 30-second window and one step either side, so without recording which +// step was spent the same six digits work for up to 90 seconds. RFC 6238 +// section 5.2 requires exactly one acceptance per step. +// +// Candidates are tried oldest first so a code presented inside the overlap +// resolves to the earliest step it is valid for, which is the conservative +// choice: it retires that step and everything before it. +func ValidateCodeStep(secret, code string) (uint64, bool) { code = strings.TrimSpace(code) if len(code) != totpDigits { - return false + return 0, false } step := uint64(time.Now().Unix()) / totpPeriod for i := -totpSkew; i <= totpSkew; i++ { - expected, err := hotp(secret, uint64(int64(step)+int64(i))) + candidate := uint64(int64(step) + int64(i)) + expected, err := hotp(secret, candidate) if err != nil { - return false + return 0, false } if subtle.ConstantTimeCompare([]byte(expected), []byte(code)) == 1 { - return true + return candidate, true } } - return false + return 0, false } // OtpauthURI builds the otpauth://totp provisioning URI an authenticator scans. diff --git a/internal/app/user/cache.go b/internal/app/user/cache.go index 62807fc3c..5e0db17f6 100644 --- a/internal/app/user/cache.go +++ b/internal/app/user/cache.go @@ -16,55 +16,36 @@ func getUserKey(id uuid.UUID) string { return "user:" + id.String() } -// SaveUser refreshes the cached copy of a row that lives in Postgres, so a -// cache that will not take it is not a failed write: the authoritative row is -// already there and the read path falls back to it. -// -// A set that fails is followed by a delete, because the danger is not an -// absent copy but a stale one: the copy this call was replacing would -// otherwise be served until its TTL. Both failing means the cache is -// unreachable, which is also the state in which nothing can read the stale -// copy either. func (s *userService) SaveUser(ctx context.Context, user *models.User) *errx.Error { raw, err := json.Marshal(user) if err != nil { - // Not a cache fault: this row cannot be represented at all, and the - // caller is owed the failure. errs.CaptureException(err) return errx.InternalError() } key := getUserKey(user.ID) if err := s.cache.SetEx(ctx, key, raw, UserTTL).Err(); err != nil { - errs.CaptureException(err, errs.Tag("cache.key", "user"), errs.Tag("cache.op", "set")) - s.cache.Del(ctx, key) + errs.CaptureException(err) + return errx.InternalError() } return nil } -// getUser answers from the cached copy. A cache that cannot answer is a miss, -// not a failed request: the row is in Postgres and GetUser reads it from there. -// -// Treating an unreachable cache as a fault turned one cache outage into every -// signed-in request answering 500, because the user behind a request is read -// on nearly all of them. func (s *userService) getUser(ctx context.Context, userID uuid.UUID) (*models.User, *errx.Error) { data, err := s.cache.Get(ctx, getUserKey(userID)).Bytes() if err != nil { - if !errors.Is(err, redis.Nil) { - errs.CaptureException(err, errs.Tag("cache.key", "user"), errs.Tag("cache.op", "get")) + if errors.Is(err, redis.Nil) { + return nil, nil } - return nil, nil + errs.CaptureException(err) + return nil, errx.InternalError() } var user models.User if err := json.Unmarshal(data, &user); err != nil { - // Unreadable cached bytes are a miss for the same reason, and the - // copy is dropped so the next read does not repeat the work. - errs.CaptureException(err, errs.Tag("cache.key", "user")) - s.cache.Del(ctx, getUserKey(userID)) - return nil, nil + errs.CaptureException(err) + return nil, errx.InternalError() } return &user, nil diff --git a/internal/app/user/user.go b/internal/app/user/user.go index 23301ed6c..cbac4dc10 100644 --- a/internal/app/user/user.go +++ b/internal/app/user/user.go @@ -2,7 +2,6 @@ package user import ( "context" - "errors" "github.com/google/uuid" "github.com/warmbly/warmbly/internal/errx" @@ -20,14 +19,6 @@ func (s *userService) GetUser(ctx context.Context, userID uuid.UUID) (*models.Us u, xerr := s.userRepository.GetUser(ctx, userID) if xerr != nil { - // The repository already says "no such account" for a missing row. - // Flattening that into an internal fault answered a deleted or - // mistyped user with "Something went wrong", which reads as a broken - // server rather than as the account not being there. - var bizErr *errx.Error - if errors.As(xerr, &bizErr) { - return nil, bizErr - } return nil, errx.InternalError() } diff --git a/internal/config/config_auth.go b/internal/config/config_auth.go index 47ca2dfab..b9baa871f 100644 --- a/internal/config/config_auth.go +++ b/internal/config/config_auth.go @@ -2,6 +2,7 @@ package config import ( "context" + "fmt" "net/url" "os" "strings" @@ -55,6 +56,11 @@ type AuthConfig struct { WebAuthnRPOrigins []string } +// MinAuthSecretLength is the floor for AUTH_SECRET. HS256 keys shorter than +// the 256-bit hash output are brute-forceable offline from any token the +// service has ever issued. +const MinAuthSecretLength = 32 + func (c *Config) LoadAuthConfig(ctx context.Context) (*AuthConfig, error) { // Social sign-in (Google/Apple) and captcha (Turnstile) are optional: a // self-hosted install running only email+password / passkeys needs none of @@ -77,6 +83,17 @@ func (c *Config) LoadAuthConfig(ctx context.Context) (*AuthConfig, error) { if err != nil { return nil, err } + // HS256 signs every session, refresh, websocket, reset and challenge token + // with this one value, and RFC 7518 section 3.2 requires a key at least as + // long as the hash output. Presence was the only check, so a deployment + // could sign its whole auth system with a ten-character string. The + // realtime service applies the same floor to JWT_SECRET, which is this + // same value. + if len(authSecret) < MinAuthSecretLength { + return nil, fmt.Errorf( + "AUTH_SECRET must be at least %d characters (it signs every session token); generate one with: make gen-key", + MinAuthSecretLength) + } turnstileSecret := c.GetSecretOptional(ctx, "TURNSTILE_SECRET", "turnstile/secret", "") turnstileBypass := c.GetSecretOptional(ctx, "TURNSTILE_BYPASS_TOKEN", "turnstile/bypass_token", "") diff --git a/internal/config/inbox.go b/internal/config/inbox.go index c87f75ba0..333c6f1e7 100644 --- a/internal/config/inbox.go +++ b/internal/config/inbox.go @@ -30,13 +30,21 @@ func GoogleOauth2Inbox(baseURL string) *oauth2.Config { ClientID: os.Getenv("BOX_GOOGLE_CLIENT_ID"), ClientSecret: os.Getenv("BOX_GOOGLE_CLIENT_SECRET"), RedirectURL: baseURL + "/addresses/google/callback", + // The smallest set that does the job. Gmail's scopes nest: + // gmail.modify already confers readonly, send, compose and metadata, so + // asking for those as well widened the consent screen and the list of + // restricted scopes under review without granting anything extra. + // + // gmail.settings.basic is separate and is not implied: it is what reads + // the send-as identities, so a mailbox sending from an alias is set up + // correctly rather than rewritten to the primary address. + // + // Existing grants are unaffected. scopeSatisfiedBy in + // internal/app/email/onboarding.go resolves the nesting both ways, so a + // mailbox connected under the old six-scope consent still verifies. Scopes: []string{ - gmail.GmailComposeScope, - gmail.GmailMetadataScope, gmail.GmailModifyScope, - gmail.GmailSendScope, gmail.GmailSettingsBasicScope, - gmail.GmailReadonlyScope, }, Endpoint: google.Endpoint, } diff --git a/internal/errx/common.go b/internal/errx/common.go index bcabee36a..1e18c0a22 100644 --- a/internal/errx/common.go +++ b/internal/errx/common.go @@ -26,19 +26,27 @@ var ( ErrToken = New(Unauthorized, "Invalid or expired token.") ErrAuth = New(Unauthorized, "Missing or invalid Authorization header.") - ErrUser = New(BadRequest, "That account doesn't exist.") - ErrPassword = New(BadRequest, "Password must be at least 8 characters long.") - ErrEmail = New(BadRequest, "Invalid email address.") - ErrCredentials = New(BadRequest, "Invalid email or password.") - ErrSession = New(BadRequest, "Invalid or expired session.") - ErrCodeLimit = New(BadRequest, "Too many attempts. Start a new session and try again later.") - ErrCode = New(BadRequest, "Invalid or expired verification code.") - ErrAuthLimit = New(BadRequest, "Too many attempts, please try again later.") + ErrUser = New(BadRequest, "User doesn't exists.") + ErrPassword = New(BadRequest, "Password must be at least 8 characters long.") + // ErrPasswordTooLong and ErrPasswordBreached separate the two other ways a + // password is refused, so nobody is told to lengthen a 40-character + // passphrase that was rejected for appearing in a breach corpus. + ErrPasswordTooLong = New(BadRequest, "Password must be at most 128 characters long.") + ErrPasswordBreached = NewWithIdentifier(BadRequest, "password_breached", "This password appears in a public list of breached passwords. Choose one that does not.") + ErrEmail = New(BadRequest, "Invalid email address.") + ErrCredentials = New(BadRequest, "Invalid email or password.") + ErrSession = New(BadRequest, "Invalid or expired session.") + ErrCodeLimit = New(BadRequest, "Too many attempts. Start a new session and try again later.") + ErrCode = New(BadRequest, "Invalid or expired verification code.") + ErrAuthLimit = New(BadRequest, "Too many attempts, please try again later.") // ErrMailUndeliverable separates "we could not send you the email" from // every other internal fault. It used to be a bare 500, which on a // self-hosted install with no working relay is the single least helpful // thing to show someone who cannot log in. + // Public: this is the one internal fault whose message the person reading + // it can act on, and blanking it leaves a self-hoster with a broken relay + // no way to tell that is the problem. ErrMailUndeliverable = NewPublic(Internal, "We couldn't send the email. If you administer this server, check the mail transport configuration.") // Registration refusals. Each names the deployment policy rather than the @@ -82,12 +90,6 @@ var ( ErrPasskeyNotFound = New(NotFound, "Passkey not found.") ErrPasskeyExists = New(Conflict, "This passkey is already registered.") ErrPasskeyNone = New(BadRequest, "No passkey was found for this account.") - // A passkey ceremony holds its challenge outside the browser for the few - // minutes between starting and finishing, so a store that cannot keep it - // stops the ceremony. It is not the passkey's fault and not the person's, - // and "Something went wrong" sent them to re-register a key that works. - ErrPasskeyUnavailable = NewWithIdentifier(ServiceUnavailable, "passkey_unavailable", - "Passkey sign-in isn't available right now. Try again in a moment, or sign in with your password.") // Organization // @@ -108,18 +110,8 @@ var ( ErrGroupMax = New(BadRequest, "You reached the maximum amount.") // Email - ErrEmailCredentials = New(BadRequest, "Invalid email credentials.") - // The mail server did not answer inside the check's deadline. Named - // separately from bad credentials because the two have different fixes: - // this one is a host, a port or a firewall, not a password. - ErrEmailValidation = NewWithIdentifier(BadRequest, "mailbox_validation_timeout", - "The mail server didn't answer in time, so the credentials could not be checked. Confirm the host, port and security settings, then try again.") - // Raised when the check itself could not be run: the machine that tests - // credentials could not be reached, or the channel its answer comes back - // on was unavailable. Nothing about the mailbox is known either way, which - // is why it is not a credentials refusal. - ErrEmailValidationUnavailable = NewWithIdentifier(ServiceUnavailable, "mailbox_validation_unavailable", - "Warmbly couldn't check these credentials right now, so nothing was saved. Try again in a moment.") + ErrEmailCredentials = New(BadRequest, "Invalid email credentials.") + ErrEmailValidation = New(BadRequest, "Deadline exceed, try again later.") ErrEmailOnboardProvider = New(BadRequest, "Unsupported email provider. Use 'gmail', 'outlook', or 'smtp_imap'.") // Raised when the provider is supported but this deployment has no OAuth // client for it. Self-host only: the hosted product always has both set. The @@ -140,7 +132,7 @@ var ( ErrEmailOnboardExchange = New(BadRequest, "Could not exchange the authorization code with the provider.") ErrEmailOnboardUserInfo = New(BadRequest, "Could not read account details from the provider.") ErrEmailOnboardAlreadyExists = New(Conflict, "This email account is already connected.") - ErrEmailOnboardNoWorker = NewPublic(ServiceUnavailable, "No mailbox workers are available right now. Please try again shortly.") + ErrEmailOnboardNoWorker = New(ServiceUnavailable, "No mailbox workers are available right now. Please try again shortly.") ErrEmailReauthProvider = New(BadRequest, "This mailbox connects with SMTP/IMAP credentials. Update its credentials instead of re-authorizing.") ErrEmailReauthOAuthOnly = New(BadRequest, "This mailbox signs in with OAuth. Re-authorize it instead of entering credentials.") ErrEmailReauthWrongAccount = New(Conflict, "The account you signed in with is not this mailbox's address. Sign in with the mailbox's own account and try again.") diff --git a/internal/errx/errx.go b/internal/errx/errx.go index 8e795a172..b9fd77917 100644 --- a/internal/errx/errx.go +++ b/internal/errx/errx.go @@ -17,9 +17,12 @@ type Error struct { // to a client, so a caller that needs to branch on a specific condition has // nothing stable to match on. Empty means "derive it from Code". Identifier string `json:"-"` - // public marks a 5xx message as written for the person who will read it. - // See answer below: a 5xx message is kept server-side unless it is set. - public bool + // Public marks an Internal-class message that was written for the caller + // and is safe to show. Internal messages are otherwise replaced with a + // generic sentence, because they are usually built from the underlying + // error. The exceptions are the few that tell an operator something they + // can act on, like a mail transport that cannot deliver. + Public bool `json:"-"` } // Error implements error interface. @@ -32,25 +35,18 @@ func New(code Code, message string) *Error { return &Error{Code: code, Message: message} } -// NewPublic creates an error whose message is shown to the caller even when -// the code is a 5xx. Use it where the fault is genuinely the reader's to act -// on: a feature this deployment has not configured, a dependency that is down -// and will come back, an operation this instance does not offer. -// -// Everything else answers a 5xx with answer5xx and keeps its own words in the -// log. See the comment there for why. +// NewPublic creates an error whose message is shown to the caller even when it +// is server-class. Use it only for a message a person can act on, never for one +// derived from an underlying error. func NewPublic(code Code, message string) *Error { - return &Error{Code: code, Message: message, public: true} + return &Error{Code: code, Message: message, Public: true} } // NewWithIdentifier creates a business error carrying its own machine-readable // identifier, for conditions a client is expected to detect and handle // specifically rather than just display. -// -// An identifier is only worth minting for a condition somebody branches on, -// which is a condition somebody explains, so these are public at any status. func NewWithIdentifier(code Code, identifier, message string) *Error { - return &Error{Code: code, Message: message, Identifier: identifier, public: true} + return &Error{Code: code, Message: message, Identifier: identifier} } // identifier returns the response `code`: the error's own when set, otherwise @@ -79,21 +75,6 @@ func (e *Error) resolve() (int, string) { // callers that embed errors in a body of their own (per-row results). func (e *Error) ResponseCode() string { return e.identifier() } -// UserMessage is what this error says to the person who hit it: its own -// message, or the answer a server-side fault gives in place of one written for -// a stack trace. -// -// Use it wherever an error reaches a person outside the JSON envelope: a -// streamed agent event, a redirect carrying a reason, a rendered page. Those -// paths bypass JSON and Handle, so without this they are where the call site's -// own words still leak out. -func (e *Error) UserMessage() string { - if status, _ := e.resolve(); status >= 500 && !e.public { - return answer5xx(e.Code) - } - return e.Message -} - // --- Predefined errors (exported) --- var ( ErrUnauthorized = New(Unauthorized, "Token not found.") @@ -116,93 +97,59 @@ func InternalError() *Error { return New(Internal, "Something went wrong.") } -// answer5xx is what a server-side fault says to the person who hit it. -// -// A 5xx message written at the call site is written for whoever is reading the -// stack trace: "failed to get organization count", "failed to attach roles". -// Nearly four hundred of those reach the dashboard as the explanation under a -// failed action, where they tell the reader nothing they can act on and name -// internals they should not have to know. So the message on the wire says what -// is true and what to do, and the call site's own words go to the log next to -// the request id that identifies the very same failure. -// -// The id is not repeated in the text: it is its own field, and every surface -// that renders one of these already shows it (buildError in the dashboard, -// the CLI's api.Error, the response envelope itself). -// -// A 5xx that genuinely is the reader's to act on says so with NewPublic (or by -// carrying its own identifier) and is passed through untouched: a mail -// transport nobody configured and an AI provider with no key are both faults -// only the person reading can fix. -func answer5xx(code Code) string { - switch code { - case ServiceUnavailable: - return "This part of Warmbly is temporarily unavailable. Nothing was changed. Try again in a moment." - case NotImplemented: - return "This instance doesn't offer that." - default: - return "Something went wrong on our end. Try again in a moment. If it keeps happening, contact support with the request id." - } -} - -// answer is the body for one error: the status, the title, the message the -// caller is given, and the message the log keeps. -// -// detail is empty unless the two differ, so a log line only ever carries the -// call site's own words when they were not the ones sent. -func (e *Error) answer(requestID string) (int, response, string) { - httpCode, httpError := e.resolve() - message, detail := e.Message, "" - if httpCode >= 500 && !e.public { - message, detail = answer5xx(e.Code), e.Message - } - return httpCode, response{ - Error: httpError, - Message: message, - Code: e.identifier(), - RequestID: requestID, - }, detail -} - -// send writes the answer and, when the caller was given a different message -// than the call site wrote, logs the one it wrote. Nothing is lost by keeping -// a 5xx message server-side; it is only moved. -func send(c *gin.Context, e *Error) { - requestID := c.GetString("request_id") - httpCode, body, detail := e.answer(requestID) - if detail != "" { - entry := log.Error(). - Str("request_id", requestID). - Int("status", httpCode). - Str("code", body.Code) - // A context built without a request is a test's or an internal - // caller's; the detail is still worth logging without the route. - if c.Request != nil { - entry = entry.Str("method", c.Request.Method).Str("path", c.FullPath()) - } - entry.Msg(detail) - } - c.JSON(httpCode, body) -} - func Handle(c *gin.Context, err error) { var bizErr *Error if errors.As(err, &bizErr) { - send(c, bizErr) + JSON(c, bizErr) return } - // Unexpected error → treat as internal, keeping what it said for the log. - // A nil error reaching here is a caller bug rather than a request fault, - // and answering it with a panic helps nobody. - message := "no error given to errx.Handle" - if err != nil { - message = err.Error() - } - send(c, &Error{Code: Internal, Message: message}) + // Unexpected error → treat as internal + Handle(c, InternalError()) } -// JSON sends a business error as JSON response +// JSON sends a business error as JSON response. func JSON(c *gin.Context, err *Error) { - send(c, err) + httpCode, httpError := err.resolve() + c.JSON(httpCode, response{ + Error: httpError, + Message: clientMessage(c, err), + Code: err.identifier(), + RequestID: c.GetString("request_id"), + }) +} + +// genericServerMessage is the only thing a 5xx says to a caller. +const genericServerMessage = "Something went wrong." + +// clientMessage is what the caller is told. +// +// An Internal message describes something that went wrong inside the service, +// and handlers routinely built one from the underlying error: driver text with +// SQLSTATE codes and column names, provider responses, file paths. None of that +// helps the caller and all of it helps somebody mapping the system, which is +// what CASA 6.2.1 is about. +// +// So an Internal error answers with one fixed sentence and the request id. The +// real message is logged against that id, which is where an operator should be +// reading it from anyway. +// +// Only Internal. The other server-class codes carry messages a developer wrote +// for the caller and that the caller can act on ("no mailbox workers are +// available right now", "this provider is not configured on this instance"), +// and blanking those would replace working guidance with a shrug. +func clientMessage(c *gin.Context, err *Error) string { + status, _ := err.resolve() + if err.Code != Internal || err.Public { + return err.Message + } + if detail := err.Message; detail != "" && detail != genericServerMessage { + log.Error(). + Str("request_id", c.GetString("request_id")). + Str("path", c.FullPath()). + Int("status", status). + Str("detail", detail). + Msg("server error returned to client") + } + return genericServerMessage } diff --git a/internal/errx/errx_test.go b/internal/errx/errx_test.go index 02a59f96f..ea29e4f92 100644 --- a/internal/errx/errx_test.go +++ b/internal/errx/errx_test.go @@ -4,7 +4,6 @@ import ( "encoding/json" "net/http" "net/http/httptest" - "strings" "testing" "github.com/gin-gonic/gin" @@ -58,61 +57,3 @@ func TestJSONAnswersAnUnknownCodeAsAnError(t *testing.T) { t.Fatalf("code = %q", body.Code) } } - -// A 5xx written for a stack trace is not what the caller is told. The call -// site's own words used to be the explanation under a failed action in the -// dashboard: "failed to get organization count" is not something anybody can -// act on, and it names internals a caller should not have to know. -func TestJSONKeepsAnInternalMessageOffTheWire(t *testing.T) { - gin.SetMode(gin.TestMode) - rec := httptest.NewRecorder() - c, _ := gin.CreateTestContext(rec) - c.Set("request_id", "req_test_500") - - JSON(c, New(Internal, "failed to get organization count")) - - var body response - if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil { - t.Fatalf("decode response: %v", err) - } - if strings.Contains(body.Message, "organization count") { - t.Fatalf("internal message reached the caller: %q", body.Message) - } - if body.Message != answer5xx(Internal) { - t.Fatalf("message = %q", body.Message) - } - // The id is how the sentence above turns into something an operator can - // look up, so it has to survive the substitution. - if body.RequestID != "req_test_500" { - t.Fatalf("request_id = %q", body.RequestID) - } -} - -// A 5xx the reader can act on keeps its own words. A self-hoster with no mail -// transport configured learns nothing from a generic fault. -func TestJSONKeepsAPublicInternalMessage(t *testing.T) { - gin.SetMode(gin.TestMode) - rec := httptest.NewRecorder() - c, _ := gin.CreateTestContext(rec) - - JSON(c, ErrMailUndeliverable) - - var body response - if err := json.Unmarshal(rec.Body.Bytes(), &body); err != nil { - t.Fatalf("decode response: %v", err) - } - if body.Message != ErrMailUndeliverable.Message { - t.Fatalf("message = %q", body.Message) - } -} - -// A 4xx is written for the person reading it at every call site, so nothing -// replaces it. -func TestUserMessagePassesClientErrorsThrough(t *testing.T) { - if got := New(BadRequest, "Limit must be between 10 and 200.").UserMessage(); got != "Limit must be between 10 and 200." { - t.Fatalf("UserMessage() = %q", got) - } - if got := NewWithIdentifier(ServiceUnavailable, "mailbox_worker_unreachable", "Try again in a moment.").UserMessage(); got != "Try again in a moment." { - t.Fatalf("identified 5xx was replaced: %q", got) - } -} diff --git a/internal/errx/scrub_test.go b/internal/errx/scrub_test.go new file mode 100644 index 000000000..fbe616767 --- /dev/null +++ b/internal/errx/scrub_test.go @@ -0,0 +1,71 @@ +package errx + +import ( + "encoding/json" + "net/http" + "net/http/httptest" + "strings" + "testing" + + "github.com/gin-gonic/gin" +) + +func renderedBody(t *testing.T, err *Error) (int, response) { + t.Helper() + gin.SetMode(gin.TestMode) + w := httptest.NewRecorder() + c, _ := gin.CreateTestContext(w) + c.Request = httptest.NewRequest(http.MethodGet, "/x", nil) + c.Set("request_id", "req-123") + + JSON(c, err) + + var body response + if uerr := json.Unmarshal(w.Body.Bytes(), &body); uerr != nil { + t.Fatalf("decode body: %v", uerr) + } + return w.Code, body +} + +// A 500 must never carry the underlying error text: handlers built those from +// driver output, which names tables and columns. +func TestInternalErrorsAreScrubbed(t *testing.T) { + status, body := renderedBody(t, New(Internal, + `ERROR: null value in column "organization_id" of relation "warmup_routing_rules" (SQLSTATE 23502)`)) + + if status != http.StatusInternalServerError { + t.Fatalf("status = %d, want 500", status) + } + if strings.Contains(body.Message, "SQLSTATE") || strings.Contains(body.Message, "organization_id") { + t.Fatalf("internal detail reached the client: %q", body.Message) + } + if body.Message != genericServerMessage { + t.Fatalf("message = %q, want the generic one", body.Message) + } + if body.RequestID != "req-123" { + t.Fatalf("request id = %q, want it echoed so the detail can be found in the log", body.RequestID) + } +} + +// An Internal-class error explicitly marked public keeps its message: the mail +// transport one is the reason that escape hatch exists. +func TestPublicInternalMessagesSurvive(t *testing.T) { + _, body := renderedBody(t, ErrMailUndeliverable) + if body.Message != ErrMailUndeliverable.Message { + t.Fatalf("message = %q, want the authored one", body.Message) + } +} + +// A message the caller can act on is passed through untouched. +func TestClientErrorsKeepTheirMessage(t *testing.T) { + for _, err := range []*Error{ + New(BadRequest, "requested value must exceed current effective limit"), + New(Forbidden, "only the workspace owner can transfer ownership"), + New(ServiceUnavailable, "No mailbox workers are available right now. Please try again shortly."), + } { + _, body := renderedBody(t, err) + if body.Message != err.Message { + t.Errorf("message = %q, want %q", body.Message, err.Message) + } + } +} diff --git a/internal/events/publisher.go b/internal/events/publisher.go index 3fd9aab0d..5d88e19c3 100644 --- a/internal/events/publisher.go +++ b/internal/events/publisher.go @@ -97,8 +97,8 @@ type publisher struct { codec codec.Codec cipherService cipher.CipherService - // Last time a failure was reported for each topic and stage. See - // reportTopicFailure. + // Last time a publish failure on each topic was reported. See + // reportPublishFailure. failuresMu sync.Mutex lastFailure map[string]time.Time } @@ -372,35 +372,25 @@ func (p *publisher) PublishEmailValidation(ctx context.Context, workerID string, return p.publish(kafka.GetWorkerTopic(workerID), body.OrgID.String(), workerEvent) } -// publishFailureInterval is how often one topic's failure is reported. A topic -// the broker persistently refuses (a missing ACL, a name it will not +// publishFailureInterval is how often one topic's publish failure is reported. +// A topic the broker persistently refuses (a missing ACL, a name it will not // auto-create) fails on every message, and reporting each one buried every // other issue under hundreds of copies of the same sentence. const publishFailureInterval = 5 * time.Minute -// reportTopicFailure reports at most one failure per topic per stage per -// interval. The caller still gets the error, so nothing downstream changes. -// -// Serialization is throttled on the same terms as the publish it precedes, -// because it fails on the same terms: a schema the registry will not accept -// under a topic's subject is refused for every event on that topic, for as -// long as the two disagree. One afternoon of that filed 19,190 copies of one -// sentence naming two worker topics. -func (p *publisher) reportTopicFailure(stage, topic string, err error) { +// reportPublishFailure reports at most one failure per topic per interval. The +// caller still gets the error, so nothing downstream changes. +func (p *publisher) reportPublishFailure(topic string, err error) { now := time.Now() - key := stage + "\x00" + topic p.failuresMu.Lock() - last, seen := p.lastFailure[key] + last, seen := p.lastFailure[topic] if seen && now.Sub(last) < publishFailureInterval { p.failuresMu.Unlock() return } - p.lastFailure[key] = now + p.lastFailure[topic] = now p.failuresMu.Unlock() - errs.CaptureException(fmt.Errorf("failed to %s event for topic %s: %w", stage, topic, err), - errs.Tag("bus.topic", topic), - errs.Tag("bus.stage", stage), - ) + errs.CaptureException(fmt.Errorf("failed to publish event: %w", err)) } // publish serializes (via codec) and publishes (via bus) an event. @@ -418,13 +408,13 @@ func (p *publisher) publish(topic, key string, event interface{}) error { ctx := context.Background() data, err := p.codec.Serialize(ctx, topic, event) if err != nil { - p.reportTopicFailure("serialize", topic, err) + errs.CaptureException(fmt.Errorf("failed to serialize event: %w", err)) return err } if err := p.bus.Publish(ctx, topic, key, data); err != nil { // A bus closed under us is shutdown, not a fault worth an issue. if !errors.Is(err, eventbus.ErrBusClosed) { - p.reportTopicFailure("publish", topic, err) + p.reportPublishFailure(topic, err) } return err } diff --git a/internal/formserver/pages.go b/internal/formserver/pages.go index 747774091..729f12d8f 100644 --- a/internal/formserver/pages.go +++ b/internal/formserver/pages.go @@ -46,9 +46,23 @@ func notFoundPage(c *gin.Context) { // This is why the shell must come from this process and not a dumb file // server: the header is per-form. func setFormFrameHeaders(c *gin.Context, allowedDomains []string) { + // An empty allowlist means "any site may embed this", which is the + // documented contract and what every embed installed without configuring + // the list depends on. Narrowing it to 'self' would take those forms off + // their owners' websites with no error anywhere, so the default stays. + // + // What changed is that the policy is now stated rather than absent. A + // missing header and a permissive one behave the same in a browser, but + // only one of them says which it meant, and a scanner cannot tell an + // intentional default from an oversight. + // + // An owner who wants framing restricted lists their domains, which is the + // control the product actually offers. if len(allowedDomains) == 0 { + c.Header("Content-Security-Policy", "frame-ancestors *") return } + sources := make([]string, 0, len(allowedDomains)*2+1) sources = append(sources, "'self'") for _, d := range allowedDomains { diff --git a/internal/formserver/server.go b/internal/formserver/server.go index 5f8954a76..2a0445fb2 100644 --- a/internal/formserver/server.go +++ b/internal/formserver/server.go @@ -22,6 +22,7 @@ import ( "time" "github.com/gin-gonic/gin" + "github.com/warmbly/warmbly/internal/api/middleware" "github.com/warmbly/warmbly/internal/formwire" ) @@ -121,7 +122,20 @@ func New(cfg Config) (*Server, error) { } func (s *Server) Router(trustedProxies []string) (*gin.Engine, error) { - r := gin.Default() + // Not gin.Default(): its logger prints the full request URI, and the form + // page carries the per-contact prefill ticket as ?t=. That ticket + // discloses the contact's name, address, company and phone to whoever + // holds it, so it must not be written to an access log. + // + // Release mode too, unless the operator asked for otherwise: this is an + // internet-facing service, and debug mode prints the route table and a + // warning banner on every start. + if env := strings.ToLower(strings.TrimSpace(os.Getenv("APP_ENV"))); os.Getenv("GIN_MODE") == "" && + env != "" && env != "dev" && env != "development" && env != "local" { + gin.SetMode(gin.ReleaseMode) + } + r := gin.New() + r.Use(middleware.RequestLogger(), gin.Recovery()) // Same posture as the backend: trust no proxy unless the operator names // it, so a forged X-Forwarded-For cannot dodge the submit limiter. if len(trustedProxies) > 0 { diff --git a/internal/infrastructure/codec/avro.go b/internal/infrastructure/codec/avro.go index 371516b21..b2f77bf7b 100644 --- a/internal/infrastructure/codec/avro.go +++ b/internal/infrastructure/codec/avro.go @@ -11,7 +11,6 @@ import ( "encoding/binary" "errors" "fmt" - "strings" "sync" "github.com/confluentinc/confluent-kafka-go/v2/schemaregistry" @@ -134,7 +133,7 @@ func (c *AvroCodec) register(subject string, schema avro.Schema) (int, error) { } id, err = c.client.Register(subject, schemaregistry.SchemaInfo{Schema: string(doc)}, true) if err != nil { - return 0, fmt.Errorf("codec: register %s: %w%s", subject, err, registryHint(err)) + return 0, fmt.Errorf("codec: register %s: %w", subject, err) } c.mu.Lock() c.ids[key] = id @@ -165,29 +164,3 @@ func (c *AvroCodec) schemaByID(subject string, id int) (avro.Schema, error) { // subjectFor is Confluent's TopicNameStrategy, the default everywhere else. func subjectFor(topic string) string { return topic + "-value" } - -// registryHint names what a registry refusal means and what resolves it. -// -// The bare answer is a number: "error code: 40901: Schema being registered is -// incompatible with an earlier schema for subject w.-value". Every send -// on that worker's topic fails for as long as the two disagree, and the number -// alone does not say that the subject is per topic, that the envelope is -// derived from the registry in internal/models/event_variants.go, or that the -// fix is a compatibility decision rather than a retry. -func registryHint(err error) string { - text := err.Error() - switch { - case strings.Contains(text, "40901"): - return " (the subject already holds a schema this one cannot evolve from," + - " so nothing can be published on this topic until they agree:" + - " check the envelope derived in internal/models/event_schema.go against" + - " the subject's registered versions, and the subject's compatibility level)" - case strings.Contains(text, "40401") || strings.Contains(text, "40403"): - return " (the registry has no such subject or version; a registry that" + - " does not auto-register needs the subject created before a publish)" - case strings.Contains(text, "401") && strings.Contains(strings.ToLower(text), "unauthorized"): - return " (the registry refused the credentials in SCHEMA_REGISTRY_URL;" + - " check the key and secret this instance was given)" - } - return "" -} diff --git a/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.down.sql b/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.down.sql new file mode 100644 index 000000000..06adcfb79 --- /dev/null +++ b/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.down.sql @@ -0,0 +1,15 @@ +-- Restoring the instance-wide constraint can fail where two organizations +-- legitimately hold the same key, which is the state the up migration allows. +-- Duplicates are collapsed to the oldest row first so the rollback applies. + +ALTER TABLE public.deliverability_events + DROP CONSTRAINT IF EXISTS deliverability_events_idempotency_unique; + +DELETE FROM public.deliverability_events a + USING public.deliverability_events b + WHERE a.idempotency_key = b.idempotency_key + AND a.ctid > b.ctid; + +ALTER TABLE public.deliverability_events + ADD CONSTRAINT deliverability_events_idempotency_unique + UNIQUE (idempotency_key); diff --git a/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.up.sql b/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.up.sql new file mode 100644 index 000000000..4f7155dde --- /dev/null +++ b/internal/infrastructure/db/migrations/000181_deliverability_idempotency_per_org.up.sql @@ -0,0 +1,25 @@ +-- Scope the deliverability idempotency key to the organization. +-- +-- The key was unique instance-wide, and the keys the platform itself mints are +-- derived from ids the recipient of a campaign email can read ("reject:", +-- "ndr:", "fbl:"). One workspace could therefore insert a +-- row carrying another workspace's future key and, because the writer is +-- ON CONFLICT DO NOTHING, silently discard that workspace's real bounce or +-- complaint for good. +-- +-- Rows are deduplicated before the new index is built: an existing collision +-- across two organizations is exactly the case the old constraint could not +-- represent, and the oldest row is the one that was recorded first. + +ALTER TABLE public.deliverability_events + DROP CONSTRAINT IF EXISTS deliverability_events_idempotency_unique; + +DELETE FROM public.deliverability_events a + USING public.deliverability_events b + WHERE a.organization_id = b.organization_id + AND a.idempotency_key = b.idempotency_key + AND a.ctid > b.ctid; + +ALTER TABLE public.deliverability_events + ADD CONSTRAINT deliverability_events_idempotency_unique + UNIQUE (organization_id, idempotency_key); diff --git a/internal/infrastructure/db/migrations/000181_task_status_org_suspended.down.sql b/internal/infrastructure/db/migrations/000181_task_status_org_suspended.down.sql deleted file mode 100644 index 87e78c9bc..000000000 --- a/internal/infrastructure/db/migrations/000181_task_status_org_suspended.down.sql +++ /dev/null @@ -1,2 +0,0 @@ --- task_status keeps 'skipped_org_suspended': Postgres cannot drop an enum value. -SELECT 1; diff --git a/internal/infrastructure/db/migrations/000181_task_status_org_suspended.up.sql b/internal/infrastructure/db/migrations/000181_task_status_org_suspended.up.sql deleted file mode 100644 index 5cc24b11f..000000000 --- a/internal/infrastructure/db/migrations/000181_task_status_org_suspended.up.sql +++ /dev/null @@ -1,4 +0,0 @@ --- A warmup send held for a suspended workspace has written this status since --- the org risk posture shipped, but nothing added it, so every write failed and --- left the task pending for the dispatcher to fire again. -ALTER TYPE public.task_status ADD VALUE IF NOT EXISTS 'skipped_org_suspended'; diff --git a/internal/infrastructure/db/migrations/000182_session_mfa_verified.down.sql b/internal/infrastructure/db/migrations/000182_session_mfa_verified.down.sql new file mode 100644 index 000000000..64d6e9bba --- /dev/null +++ b/internal/infrastructure/db/migrations/000182_session_mfa_verified.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE public.sessions + DROP COLUMN IF EXISTS mfa_verified; diff --git a/internal/infrastructure/db/migrations/000182_session_mfa_verified.up.sql b/internal/infrastructure/db/migrations/000182_session_mfa_verified.up.sql new file mode 100644 index 000000000..88dd537f2 --- /dev/null +++ b/internal/infrastructure/db/migrations/000182_session_mfa_verified.up.sql @@ -0,0 +1,17 @@ +-- Record whether a session proved a second factor. +-- +-- Multi-factor authentication existed but nothing could tell afterwards whether +-- a given session had used it: auth_provider says "email" whether the sign-in +-- was password-only or password plus a TOTP code. Without that distinction the +-- admin panel could not require MFA, which CASA 3.3.1 asks for on any +-- internet-reachable administrative interface. +-- +-- Existing sessions default to false, so an admin signed in right now is asked +-- to sign in again with their second factor. That is the intended direction: +-- the safe default for "we do not know" is "not verified". + +ALTER TABLE public.sessions + ADD COLUMN IF NOT EXISTS mfa_verified boolean NOT NULL DEFAULT false; + +COMMENT ON COLUMN public.sessions.mfa_verified IS + 'True when this session was established with a second factor: a TOTP code, a recovery code, or a passkey (which is itself multi-factor).'; diff --git a/internal/infrastructure/db/migrations/000183_totp_last_used_step.down.sql b/internal/infrastructure/db/migrations/000183_totp_last_used_step.down.sql new file mode 100644 index 000000000..dba24e059 --- /dev/null +++ b/internal/infrastructure/db/migrations/000183_totp_last_used_step.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE public.user_totp_settings + DROP COLUMN IF EXISTS last_used_step; diff --git a/internal/infrastructure/db/migrations/000183_totp_last_used_step.up.sql b/internal/infrastructure/db/migrations/000183_totp_last_used_step.up.sql new file mode 100644 index 000000000..c6f7f2887 --- /dev/null +++ b/internal/infrastructure/db/migrations/000183_totp_last_used_step.up.sql @@ -0,0 +1,13 @@ +-- Remember the last TOTP step a user spent, so a code cannot be used twice. +-- +-- A TOTP code is valid for its own 30-second step plus one on each side, so the +-- same six digits were accepted for up to 90 seconds. Anyone who saw the code in +-- that window (over someone's shoulder, in a phishing relay, in a screen +-- recording) could replay it. RFC 6238 section 5.2 says the verifier must +-- refuse a second use of the same step, and this column is what lets it. + +ALTER TABLE public.user_totp_settings + ADD COLUMN IF NOT EXISTS last_used_step bigint NOT NULL DEFAULT 0; + +COMMENT ON COLUMN public.user_totp_settings.last_used_step IS + 'Highest TOTP time step already accepted for this user. A code at or below it is a replay and is refused.'; diff --git a/internal/infrastructure/db/migrations/000184_session_reauth_at.down.sql b/internal/infrastructure/db/migrations/000184_session_reauth_at.down.sql new file mode 100644 index 000000000..88b557895 --- /dev/null +++ b/internal/infrastructure/db/migrations/000184_session_reauth_at.down.sql @@ -0,0 +1,2 @@ +ALTER TABLE public.sessions + DROP COLUMN IF EXISTS reauth_at; diff --git a/internal/infrastructure/db/migrations/000184_session_reauth_at.up.sql b/internal/infrastructure/db/migrations/000184_session_reauth_at.up.sql new file mode 100644 index 000000000..d708c00b6 --- /dev/null +++ b/internal/infrastructure/db/migrations/000184_session_reauth_at.up.sql @@ -0,0 +1,17 @@ +-- Record when a session last re-proved the person behind it. +-- +-- CASA 2.4.1 wants a sensitive account change to sit behind a full session plus +-- re-authentication or a secondary check. Changing a password and disabling 2FA +-- already ask for a current credential; adding a passkey, minting an API key, +-- transferring a workspace and scheduling a deletion asked for nothing beyond a +-- live token. A stolen token is enough for all of those, and the first two hand +-- the attacker a durable credential of their own. +-- +-- NULL means "never re-authenticated in this session", which is the state every +-- existing session starts in. + +ALTER TABLE public.sessions + ADD COLUMN IF NOT EXISTS reauth_at timestamptz; + +COMMENT ON COLUMN public.sessions.reauth_at IS + 'When this session last re-proved the account holder (password, TOTP, recovery code or passkey). Read by RequireFreshAuth.'; diff --git a/internal/infrastructure/storage/filesystem.go b/internal/infrastructure/storage/filesystem.go index 74bfcaeb0..e7d350985 100644 --- a/internal/infrastructure/storage/filesystem.go +++ b/internal/infrastructure/storage/filesystem.go @@ -75,6 +75,16 @@ func (s *FilesystemStore) Get(_ context.Context, key string) (io.ReadCloser, err } return nil, err } + // A key naming a directory ("avatars/") opens cleanly and then reads as an + // empty object, so the public route answered 200 with no body instead of + // 404. Treat it as absent, which is what it is. + if info, serr := f.Stat(); serr != nil || info.IsDir() { + _ = f.Close() + if serr != nil { + return nil, serr + } + return nil, ErrNotFound + } return f, nil } diff --git a/internal/jobs/mailbox_erasure_live_test.go b/internal/jobs/mailbox_erasure_live_test.go index 02b00a174..74c18e517 100644 --- a/internal/jobs/mailbox_erasure_live_test.go +++ b/internal/jobs/mailbox_erasure_live_test.go @@ -103,7 +103,7 @@ func TestLiveErasureRemovesTheStoredMailAndTheQueueRow(t *testing.T) { // The delete itself, through the repository the API uses. emails := repository.NewEmailRepostory(handle, nil) - if xerr := emails.Delete(ctx, mailbox.String(), 1); xerr != nil { + if xerr := emails.Delete(ctx, user.String(), mailbox.String(), 1); xerr != nil { t.Fatalf("delete mailbox: %v", xerr) } diff --git a/internal/models/email.go b/internal/models/email.go index 6fdecdeef..98d7ab9d0 100644 --- a/internal/models/email.go +++ b/internal/models/email.go @@ -481,6 +481,13 @@ type EmailOnboardingState struct { // EmailAccountID marks a re-authorization round trip: the finish leg // renews this mailbox's tokens instead of connecting a new one. EmailAccountID *uuid.UUID `json:"email_account_id,omitempty"` + // CodeVerifier is the PKCE verifier for this round trip. It stays here, + // server-side, and is never sent to the browser: the point of PKCE is that + // only the party that started the flow can finish it, so an authorization + // code intercepted anywhere between the provider and this backend is not + // redeemable. Empty for a state written before PKCE was added, which the + // exchange tolerates so an in-flight consent still lands. + CodeVerifier string `json:"code_verifier,omitempty"` } // EmailOnboardingStartResponse is returned from POST /emails/onboarding/oauth/start. diff --git a/internal/models/token.go b/internal/models/token.go index 342d2484e..7114447ae 100644 --- a/internal/models/token.go +++ b/internal/models/token.go @@ -52,6 +52,18 @@ type Session struct { // How this session authenticated: email, google, apple, webauthn. AuthProvider string `json:"auth_provider"` + // MFAVerified is true when a second factor was presented to establish this + // session: a TOTP code, a recovery code, or a passkey (which proves + // possession of the device and, through the platform, the person). It is + // separate from AuthProvider because a password sign-in that then passed + // TOTP and one that did not both record "email". + MFAVerified bool `json:"mfa_verified"` + + // ReauthAt is when this session last re-proved the account holder. Nil + // means never. Sensitive account changes require it to be recent; see + // RequireFreshAuth. + ReauthAt *time.Time `json:"reauth_at,omitempty"` + CreatedAt time.Time `json:"created_at"` RevokedAt *time.Time `json:"revoked_at"` ExpiresAt *time.Time `json:"expires_at"` diff --git a/internal/models/user.go b/internal/models/user.go index c8a69d12d..af68e6c82 100644 --- a/internal/models/user.go +++ b/internal/models/user.go @@ -32,6 +32,12 @@ type User struct { AdminPermissions AdminPermission `json:"admin_permissions"` IsAdmin bool `json:"is_admin"` + // SessionMFAVerified reports whether the session making this request + // presented a second factor. The admin panel needs it to explain why an + // admin account is being refused, rather than showing a bare 403 on the + // first data call. + SessionMFAVerified bool `json:"session_mfa_verified"` + // Set when the user has scheduled their own account for deletion. // While these are populated the account is "pending deletion" and // gets hard-deleted at DeletionScheduledFor unless cancelled. diff --git a/internal/notify/email.go b/internal/notify/email.go index 542d25d38..e415f0590 100644 --- a/internal/notify/email.go +++ b/internal/notify/email.go @@ -67,10 +67,11 @@ func (s *emailNotificationService) Send(ctx context.Context, to, cc, bcc []strin _, err := s.Client.SendEmail(ctx, input) if err != nil { - return reportSendFailure(err, "send") + errs.CaptureException(err) + return err } - return nil + return err } // SendOutreach is Send with an explicit Reply-To. SES exposes @@ -99,7 +100,8 @@ func (s *emailNotificationService) SendOutreach(ctx context.Context, to []string _, err := s.Client.SendEmail(ctx, input) if err != nil { - return reportSendFailure(err, "outreach") + errs.CaptureException(err) + return err } return nil } diff --git a/internal/notify/sesfault.go b/internal/notify/sesfault.go deleted file mode 100644 index 7ff4402fa..000000000 --- a/internal/notify/sesfault.go +++ /dev/null @@ -1,65 +0,0 @@ -package notify - -import ( - "errors" - "fmt" - "strings" - - "github.com/aws/aws-sdk-go-v2/service/sesv2/types" - "github.com/warmbly/warmbly/internal/observability/errs" -) - -// SES refuses a send for reasons that are not interchangeable, and the raw -// operation error says which only if you already know what to look for: -// -// operation error SESv2: SendEmail, https response error StatusCode: 400, -// MessageRejected: Email address is not verified. The following identities -// failed the check in region US-EAST-1: someone@example.com -// -// That is not a bad address and not an outage. It is this deployment's SES -// account still being in the sandbox, where every recipient has to be verified -// first, and it means no account on this instance can be signed up for or -// recover a password until someone requests production access. Nothing in the -// message says that, and the person who can act on it is the operator reading -// the log rather than the person who just typed their email in. -// -// So every SES refusal is reported with the one sentence that names the fix. - -// sesHint is the operator-facing explanation for a refusal, empty when there -// is nothing specific to add. -func sesHint(err error) string { - var rejected *types.MessageRejected - if errors.As(err, &rejected) && strings.Contains(strings.ToLower(err.Error()), "not verified") { - return "this SES account is still in the sandbox, where only verified addresses can be mailed; request production access in the SES console, or verify the recipient" - } - var paused *types.AccountSuspendedException - if errors.As(err, &paused) { - return "SES has suspended sending for this account; check the account's reputation dashboard" - } - var sendingPaused *types.SendingPausedException - if errors.As(err, &sendingPaused) { - return "SES has paused sending for this account; re-enable it in the SES console once the cause is resolved" - } - var throttled *types.TooManyRequestsException - if errors.As(err, &throttled) { - return "SES is throttling this account; the send can be retried" - } - var notFound *types.NotFoundException - if errors.As(err, ¬Found) { - return "the configured sending identity does not exist in this region; check MAIL_FROM and the SES region" - } - return "" -} - -// reportSendFailure reports one SES refusal with the sentence naming its fix. -// The caller still gets the error. -func reportSendFailure(err error, operation string) error { - hint := sesHint(err) - opts := []errs.Option{errs.Tag("notify.operation", operation)} - if hint != "" { - opts = append(opts, errs.Extra("notify.fix", hint)) - err = fmt.Errorf("%w (%s)", err, hint) - } - errs.CaptureException(err, opts...) - return err -} diff --git a/internal/observability/errs/errs.go b/internal/observability/errs/errs.go index 28e1768de..97af6b383 100644 --- a/internal/observability/errs/errs.go +++ b/internal/observability/errs/errs.go @@ -102,9 +102,6 @@ type Option func(*scope) type scope struct { tags map[string]string extra map[string]any - // always sends the event even when the same fault has just been reported. - // See repeat.go. - always bool } // Tag adds an indexed key/value pair, searchable and groupable. @@ -128,13 +125,6 @@ func Extra(key string, value any) Option { } } -// Always exempts one event from the repeat suppression in repeat.go. Use it -// where every occurrence is its own fact rather than another sighting of one -// fault: the last error before a process exits, and nothing else so far. -func Always() Option { - return func(s *scope) { s.always = true } -} - // event is one report on its way to every enabled backend. type event struct { ctx context.Context @@ -150,11 +140,7 @@ func CaptureException(err error, opts ...Option) { if err == nil || abandoned(err) { return } - sc := build(opts) - if !admit(&sc, fingerprintError(err)) { - return - } - report(event{err: err, scope: sc}) + report(event{err: err, scope: build(opts)}) } // CaptureExceptionContext reports err on the reporting state carried by ctx @@ -163,11 +149,7 @@ func CaptureExceptionContext(ctx context.Context, err error, opts ...Option) { if err == nil || abandoned(err) { return } - sc := build(opts) - if !admit(&sc, fingerprintError(err)) { - return - } - report(event{ctx: ctx, err: err, scope: sc}) + report(event{ctx: ctx, err: err, scope: build(opts)}) } // abandoned reports whether err says the caller stopped waiting, rather than @@ -190,11 +172,7 @@ func CaptureMessage(message string, opts ...Option) { if message == "" { return } - sc := build(opts) - if !admit(&sc, shapeOf(message)) { - return - } - report(event{message: message, scope: sc}) + report(event{message: message, scope: build(opts)}) } // CaptureMessageContext is CaptureMessage on ctx's reporting state. @@ -202,11 +180,7 @@ func CaptureMessageContext(ctx context.Context, message string, opts ...Option) if message == "" { return } - sc := build(opts) - if !admit(&sc, shapeOf(message)) { - return - } - report(event{ctx: ctx, message: message, scope: sc}) + report(event{ctx: ctx, message: message, scope: build(opts)}) } // fatalFlushTimeout is how long a process about to exit waits for its last @@ -218,10 +192,7 @@ const fatalFlushTimeout = 2 * time.Second // in the background and os.Exit does not wait for them, so a boot failure, the // error most worth having, was the one that never arrived. func CaptureFatal(err error, opts ...Option) { - // Always: the process is about to exit, so this is the last thing it will - // say. A crash loop restarting every few seconds would otherwise report - // its first boot failure and stay silent through every one after it. - CaptureException(err, append(opts, Always())...) + CaptureException(err, opts...) Flush(fatalFlushTimeout) } diff --git a/internal/observability/errs/errs_test.go b/internal/observability/errs/errs_test.go index 046fd28a3..fdaed4ef6 100644 --- a/internal/observability/errs/errs_test.go +++ b/internal/observability/errs/errs_test.go @@ -15,21 +15,10 @@ import ( "time" ) -// Repeat suppression (repeat.go) is process-wide, so one test reporting the -// same error as another would be silenced by it. Every test below starts from -// an empty table. -func freshReports(t *testing.T) { - t.Helper() - repeatMu.Lock() - repeats = map[string]*repeatState{} - repeatMu.Unlock() -} - // A deployment that configured no backend is the self-host default, so that // path has to keep working on its own: the event reaches the process log and // nothing leaves the machine. func TestNoBackendReportsToTheLog(t *testing.T) { - freshReports(t) var buf bytes.Buffer log.SetOutput(&buf) t.Cleanup(func() { log.SetOutput(os.Stderr) }) @@ -64,7 +53,6 @@ func TestNoBackendReportsToTheLog(t *testing.T) { // so an event that carries the error anywhere else is an event that never // becomes an issue. func TestPostHogPostsAnException(t *testing.T) { - freshReports(t) bodies := make(chan string, 4) srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { body, _ := io.ReadAll(r.Body) @@ -120,7 +108,6 @@ func TestPostHogPostsAnException(t *testing.T) { // told about, so a cancelled context must not reach a backend at all. A // deadline this process set still must. func TestCancelledWorkIsNotReported(t *testing.T) { - freshReports(t) var buf bytes.Buffer log.SetOutput(&buf) t.Cleanup(func() { log.SetOutput(os.Stderr) }) @@ -146,93 +133,3 @@ func TestCancelledWorkIsNotReported(t *testing.T) { t.Error("a deadline this process set and blew through was dropped as if the caller had gone away") } } - -// One fault that recurs is one thing to fix. A schema the registry refused -// filed 19,190 events in three hours and a cache provider over its request -// quota filed 2,815 in five, and in both cases every other issue in the -// project was pushed off the first page while nothing was learned after the -// first copy. So the second sighting is counted rather than sent, and the -// report that ends the silence says how many it stands for. -func TestARecurringFaultReportsOnce(t *testing.T) { - freshReports(t) - var buf bytes.Buffer - log.SetOutput(&buf) - t.Cleanup(func() { log.SetOutput(os.Stderr) }) - - if err := Init(Config{Service: "backend", Environment: "dev"}); err != nil { - t.Fatalf("Init: %v", err) - } - - for i := 0; i < 50; i++ { - CaptureException(fmt.Errorf("register w.%d-value: schema registry refused", i)) - } - if got := strings.Count(buf.String(), "[issue-local]"); got != 1 { - t.Fatalf("reported %d times, want 1", got) - } - - // A different fault is a different thing to fix and is never held back by - // one that happens to be recurring. - CaptureException(errors.New("the mail server closed the connection")) - if got := strings.Count(buf.String(), "[issue-local]"); got != 2 { - t.Fatalf("a distinct fault was suppressed: %d reports", got) - } -} - -// The window is what makes the suppression temporary rather than permanent: a -// fault still recurring after it reports again, carrying what it stood for. -func TestSuppressionEndsWithTheWindow(t *testing.T) { - freshReports(t) - var buf bytes.Buffer - log.SetOutput(&buf) - t.Cleanup(func() { log.SetOutput(os.Stderr) }) - - if err := Init(Config{Service: "backend", Environment: "dev"}); err != nil { - t.Fatalf("Init: %v", err) - } - - err := errors.New("redis: max requests limit exceeded") - CaptureException(err) - CaptureException(err) - CaptureException(err) - - // Age the streak past the window rather than waiting it out. - repeatMu.Lock() - for _, state := range repeats { - state.reportedAt = state.reportedAt.Add(-repeatWindow - time.Second) - } - repeatMu.Unlock() - - var sc scope - if !admit(&sc, fingerprintError(err)) { - t.Fatal("a fault still recurring after the window stayed suppressed") - } - if sc.extra["repeat.suppressed"] != 2 { - t.Fatalf("suppressed count = %v, want 2", sc.extra["repeat.suppressed"]) - } -} - -// The last thing a process says before it exits is exempt: a crash loop -// restarting every few seconds would otherwise report its first boot failure -// and go quiet through every one after it. -func TestAFatalIsNeverSuppressed(t *testing.T) { - freshReports(t) - var sc scope - Always()(&sc) - key := fingerprintError(errors.New("boot failed")) - if !admit(&sc, key) || !admit(&sc, key) { - t.Fatal("an always-report event was suppressed") - } -} - -// The key collapses the ids and addresses that differ between sightings of one -// fault, and keeps apart two faults that differ in anything else. -func TestFingerprintGroupsOneFaultAndSeparatesTwo(t *testing.T) { - a := fingerprintError(fmt.Errorf("mailbox 7c2f1f0e-1111-4a1b-8f01-000000000001 could not be reached")) - b := fingerprintError(fmt.Errorf("mailbox 9d3a2b1c-2222-4c2d-9e02-000000000002 could not be reached")) - if a != b { - t.Fatalf("one fault split by its ids:\n%s\n%s", a, b) - } - if a == fingerprintError(fmt.Errorf("mailbox 7c2f1f0e-1111-4a1b-8f01-000000000001 refused the password")) { - t.Fatal("two faults collapsed into one key") - } -} diff --git a/internal/observability/errs/repeat.go b/internal/observability/errs/repeat.go deleted file mode 100644 index af32d4229..000000000 --- a/internal/observability/errs/repeat.go +++ /dev/null @@ -1,110 +0,0 @@ -package errs - -import ( - "fmt" - "regexp" - "strings" - "sync" - "time" -) - -// One fault that recurs is one thing to fix, and reporting every occurrence of -// it buries everything else. A schema the registry refused filed 19,190 events -// in three hours; a Redis provider over its request quota filed 2,815 in five; -// both times every other issue in the project was pushed off the first page -// while nothing was learned after the first copy. -// -// So a recurring fault reports once, then again no more often than -// repeatWindow, and the report that breaks the silence says how many it stands -// for. Nothing is thrown away silently: the count is on the event. -// -// This is deliberately in errs rather than at the call sites that flooded. -// Every one of those had a reason to report, and the next flood will come from -// a call site nobody has throttled yet. -const repeatWindow = 5 * time.Minute - -// repeatKeyLimit bounds the table. A process that produces more distinct faults -// than this has a bigger problem than its reporting, and an unbounded map on -// the error path is a way to turn a bad hour into an OOM. Reaching the limit -// drops the table rather than evicting one entry, which costs at most one -// duplicate report per fault and cannot leave a stale half. -const repeatKeyLimit = 4096 - -type repeatState struct { - reportedAt time.Time - suppressed int -} - -var ( - repeatMu sync.Mutex - repeats = map[string]*repeatState{} -) - -// admit decides whether this event is sent, and annotates it with the number -// its silence covered. Called from the public entry points before report, so -// the number of frames between a caller and a sink is unchanged (see -// stackSkip). -func admit(sc *scope, key string) bool { - if sc.always || key == "" { - return true - } - now := time.Now() - - repeatMu.Lock() - if len(repeats) >= repeatKeyLimit { - repeats = map[string]*repeatState{} - } - state, seen := repeats[key] - if !seen { - repeats[key] = &repeatState{reportedAt: now} - repeatMu.Unlock() - return true - } - if now.Sub(state.reportedAt) < repeatWindow { - state.suppressed++ - repeatMu.Unlock() - return false - } - suppressed := state.suppressed - state.reportedAt = now - state.suppressed = 0 - repeatMu.Unlock() - - if suppressed > 0 { - Extra("repeat.suppressed", suppressed)(sc) - Extra("repeat.window", repeatWindow.String())(sc) - } - return true -} - -// variable matches the parts of a message that differ between occurrences of -// the same fault: the ids, addresses and counters. Collapsing them is what lets -// "mailbox could not be reached" be recognised as one recurring fault -// rather than one per mailbox. -// -// Deliberately blunt. A key that merges two faults costs one delayed report; a -// key that separates every occurrence of one fault is the flood this exists to -// stop. -var variable = regexp.MustCompile( - `[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}` + // uuid - `|0x[0-9a-fA-F]+` + // hex literal - `|\b\d[\d.:]*\b`, // numbers, addresses, ports, durations -) - -// fingerprintLimit keeps one pathological message (a query, a stack, a body) -// from being the key it is hashed into. -const fingerprintLimit = 256 - -// fingerprintError keys an error by its Go type and the shape of its message. -// The type alone is far too coarse: every wrapped error in the codebase is -// *fmt.wrapError. -func fingerprintError(err error) string { - return fmt.Sprintf("%T", err) + "\x00" + shapeOf(err.Error()) -} - -func shapeOf(text string) string { - if len(text) > fingerprintLimit { - text = text[:fingerprintLimit] - } - return variable.ReplaceAllString(strings.TrimSpace(text), "#") -} diff --git a/internal/observability/errs/sentry.go b/internal/observability/errs/sentry.go index 384be8708..cf8955944 100644 --- a/internal/observability/errs/sentry.go +++ b/internal/observability/errs/sentry.go @@ -15,8 +15,12 @@ type sentrySink struct{} func newSentrySink(cfg Config) (sink, error) { err := sentry.Init(sentry.ClientOptions{ - Dsn: cfg.SentryDSN, - SendDefaultPII: true, + Dsn: cfg.SentryDSN, + // Off deliberately: the services attach the ids an event needs + // themselves. SendDefaultPII would add request headers and bodies, + // which on this backend means Authorization headers, mailbox + // credentials on the connect path, and message content. + SendDefaultPII: false, Environment: cfg.Environment, Release: cfg.Release, ServerName: cfg.Service, diff --git a/internal/pkg/crypt/password_error.go b/internal/pkg/crypt/password_error.go new file mode 100644 index 000000000..c821967e0 --- /dev/null +++ b/internal/pkg/crypt/password_error.go @@ -0,0 +1,18 @@ +package crypt + +import "github.com/warmbly/warmbly/internal/errx" + +// PasswordError maps a password rejection onto the error the API returns. +// Callers use this rather than testing the boolean so the person setting the +// password is told which rule they hit. +func PasswordError(password string) *errx.Error { + switch CheckPassword(password) { + case PasswordTooShort: + return errx.ErrPassword + case PasswordTooLong: + return errx.ErrPasswordTooLong + case PasswordBreached: + return errx.ErrPasswordBreached + } + return nil +} diff --git a/internal/pkg/crypt/passwords/README.md b/internal/pkg/crypt/passwords/README.md new file mode 100644 index 000000000..245888f4f --- /dev/null +++ b/internal/pkg/crypt/passwords/README.md @@ -0,0 +1,16 @@ +# Breached-password denylist + +`breached.txt` is the UK National Cyber Security Centre's list of the 100,000 +most commonly breached passwords (published from the Have I Been Pwned corpus), +reduced to the 46,528 entries that are 8 to 128 characters long. Anything +shorter is already refused by the length rule, so carrying it here would only +make the file bigger. + +Entries are lowercased, deduplicated and sorted. The comparison in +`crypt.CheckPassword` lowercases the candidate, so the casing here is not a +weakening: `Password123` and `password123` are both refused. + +Source: https://github.com/danielmiessler/SecLists (Passwords/Common-Credentials/100k-most-used-passwords-NCSC.txt) + +Refreshing it is a matter of re-running that filter and committing the result. +Nothing else needs to change. diff --git a/internal/pkg/crypt/passwords/breached.txt b/internal/pkg/crypt/passwords/breached.txt new file mode 100644 index 000000000..29b43f819 --- /dev/null +++ b/internal/pkg/crypt/passwords/breached.txt @@ -0,0 +1,46528 @@ +!@#$%^&* +!@#$%^&*( +!@#$%^&*() +!qaz1qaz +!qaz2wsx +!qazxsw2 +!qazzaq1 +#1babygirl +#1baller +#1hottie +#1player +#1princess +#1stunna +#1stunner +$hex[687474703a2f2f616473] +$hex[687474703a2f2f777777] +�: +� +&hearts: +******** +********* +********** +++++++@mail.ru +-deleted- +........ +.......... +.adgjmpt +.adgjmptw +/.,mnbvcxz +0.00000000 +0.123456 +00000000 +000000000 +0000000000 +00000000000 +000000000000 +000000000000000 +00000000000000000000 +00000000001 +0000000000o +0000000001 +00000000a +00000001 +00000007 +00000008 +0000000a +000000aa +0000011111 +00001111 +00001234 +00009999 +0000aaaa +0000oooo +000111222 +00070007 +000999888 +000webhost +000webhost.com +001002003 +00110011 +00112233 +0011223344 +00114477 +00123456 +00123456789 +001579238 +007007007 +007008009 +007james +008hotboy +00990099 +00998877 +0099887766 +009d9cc2 +01010101 +0101010101 +01011900 +01011910 +01011959 +01011960 +01011961 +01011962 +01011963 +01011964 +01011965 +01011966 +01011967 +01011968 +01011969 +01011970 +01011971 +01011972 +01011973 +01011974 +01011975 +01011976 +01011977 +01011978 +01011979 +01011980 +01011981 +01011982 +01011983 +01011984 +01011985 +01011986 +01011987 +01011988 +01011989 +01011990 +01011991 +01011992 +01011993 +01011994 +01011995 +01011996 +01011997 +01011998 +01011999 +01012000 +01012001 +01012005 +01012006 +01012007 +01012008 +01012009 +01012010 +01012011 +01020102 +010203010203 +01020304 +0102030405 +010203040506 +010203040506070809 +01021973 +01021974 +01021975 +01021976 +01021977 +01021978 +01021979 +01021980 +01021981 +01021982 +01021983 +01021984 +01021985 +01021986 +01021987 +01021988 +01021989 +01021990 +01021991 +01021992 +01021993 +01021994 +01021995 +01021996 +01021997 +01031972 +01031975 +01031976 +01031977 +01031978 +01031979 +01031980 +01031981 +01031982 +01031983 +01031984 +01031985 +01031986 +01031987 +01031988 +01031989 +01031990 +01031991 +01031992 +01031993 +01031994 +01031995 +01031996 +01041975 +01041976 +01041977 +01041978 +01041979 +01041980 +01041981 +01041982 +01041983 +01041984 +01041985 +01041986 +01041987 +01041988 +01041989 +01041990 +01041991 +01041992 +01041993 +01041994 +01041995 +01041996 +01051976 +01051977 +01051978 +01051979 +01051980 +01051981 +01051982 +01051983 +01051984 +01051985 +01051986 +01051987 +01051988 +01051989 +01051990 +01051991 +01051992 +01051993 +01051994 +01051995 +01051996 +01061975 +01061976 +01061977 +01061978 +01061979 +01061980 +01061981 +01061982 +01061983 +01061984 +01061985 +01061986 +01061987 +01061988 +01061989 +01061990 +01061991 +01061992 +01061993 +01061994 +01061995 +01061996 +01071975 +01071976 +01071977 +01071978 +01071979 +01071980 +01071981 +01071982 +01071983 +01071984 +01071985 +01071986 +01071987 +01071988 +01071989 +01071990 +01071991 +01071992 +01071993 +01071994 +01071995 +01081977 +01081978 +01081979 +01081980 +01081981 +01081982 +01081983 +01081984 +01081985 +01081986 +01081987 +01081988 +01081989 +01081990 +01081991 +01081992 +01081993 +01081994 +01081995 +01081996 +01091976 +01091977 +01091978 +01091979 +01091980 +01091981 +01091982 +01091983 +01091984 +01091985 +01091986 +01091987 +01091988 +01091989 +01091990 +01091991 +01091992 +01091993 +01091994 +01091995 +01091996 +01092000 +01092006 +01092007 +01092008 +01092009 +01100110 +01101977 +01101978 +01101979 +01101980 +01101981 +01101982 +01101983 +01101984 +01101985 +01101986 +01101987 +01101988 +01101989 +01101990 +01101991 +01101992 +01101993 +01101994 +01101995 +01111980 +01111981 +01111982 +01111983 +01111984 +01111985 +01111986 +01111987 +01111988 +01111989 +01111990 +01111991 +01111992 +011151zangetsu +01121978 +01121979 +01121980 +01121981 +01121982 +01121983 +01121984 +01121985 +01121986 +01121987 +01121988 +01121989 +01121990 +01121991 +01121992 +01121993 +01121994 +01121995 +011235813 +01200120 +012012012 +01230123 +01233210 +01234560 +01234561 +01234567 +012345678 +0123456789 +01234567890 +01234567891 +012345678910 +0123456789a +0123456a +0123654789 +0123698745 +01470147 +01470258 +014702580369 +0147258369 +01477410 +01478520 +0147852369 +01478963 +0147896325 +0192837465 +02011975 +02011977 +02011978 +02011979 +02011980 +02011981 +02011982 +02011983 +02011984 +02011985 +02011986 +02011987 +02011988 +02011989 +02011990 +02011991 +02011992 +02011993 +02011995 +02020202 +02021970 +02021972 +02021973 +02021974 +02021975 +02021976 +02021977 +02021978 +02021979 +02021980 +02021981 +02021982 +02021983 +02021984 +02021985 +02021986 +02021987 +02021988 +02021989 +02021990 +02021991 +02021992 +02021993 +02021994 +02021995 +02021996 +02022002 +02030203 +02031974 +02031975 +02031976 +02031977 +02031978 +02031979 +02031980 +02031981 +02031982 +02031983 +02031984 +02031985 +02031986 +02031987 +02031988 +02031989 +02031990 +02031991 +02031992 +02031993 +02031994 +02031995 +02031996 +02040204 +02041971 +02041973 +02041974 +02041975 +02041976 +02041977 +02041978 +02041979 +02041980 +02041981 +02041982 +02041983 +02041984 +02041985 +02041986 +02041987 +02041988 +02041989 +02041990 +02041991 +02041992 +02041993 +02041994 +02041995 +02041996 +02051972 +02051974 +02051975 +02051976 +02051977 +02051978 +02051979 +02051980 +02051981 +02051982 +02051983 +02051984 +02051985 +02051986 +02051987 +02051988 +02051989 +02051990 +02051991 +02051992 +02051993 +02051994 +02051995 +02051996 +02061972 +02061974 +02061975 +02061976 +02061977 +02061978 +02061979 +02061980 +02061981 +02061982 +02061983 +02061984 +02061985 +02061986 +02061987 +02061988 +02061989 +02061990 +02061991 +02061992 +02061993 +02061994 +02061995 +02061996 +02071975 +02071976 +02071977 +02071978 +02071979 +02071980 +02071981 +02071982 +02071983 +02071984 +02071985 +02071986 +02071987 +02071988 +02071989 +02071990 +02071991 +02071992 +02071993 +02071994 +02071995 +02071996 +02081973 +02081974 +02081975 +02081976 +02081977 +02081978 +02081979 +02081980 +02081981 +02081982 +02081983 +02081984 +02081985 +02081986 +02081987 +02081988 +02081989 +02081990 +02081991 +02081992 +02081993 +02081994 +02081995 +02081996 +02091974 +02091975 +02091976 +02091977 +02091978 +02091979 +02091980 +02091981 +02091982 +02091983 +02091984 +02091985 +02091986 +02091987 +02091988 +02091989 +02091990 +02091991 +02091992 +02091993 +02091994 +02091995 +0210-605 +02101976 +02101977 +02101978 +02101979 +02101980 +02101981 +02101982 +02101983 +02101984 +02101985 +02101986 +02101987 +02101988 +02101989 +02101990 +02101991 +02101992 +02101993 +02101994 +02101995 +02101996 +02111980 +02111981 +02111982 +02111983 +02111984 +02111985 +02111986 +02111987 +02111988 +02111989 +02111990 +02111991 +02111992 +02111993 +02120212 +02121977 +02121978 +02121979 +02121980 +02121981 +02121982 +02121983 +02121984 +02121985 +02121986 +02121987 +02121988 +02121989 +02121990 +02121991 +02121992 +02121993 +02121994 +0246813579 +02580258 +02588520 +0277127298 +03011980 +03011981 +03011982 +03011983 +03011984 +03011985 +03011986 +03011987 +03011988 +03011989 +03011990 +03011991 +03011992 +03011993 +03011994 +03011995 +03021977 +03021980 +03021981 +03021982 +03021983 +03021984 +03021985 +03021986 +03021987 +03021988 +03021989 +03021990 +03021991 +03021992 +03021993 +03021994 +03021995 +03030303 +03031976 +03031977 +03031978 +03031979 +03031980 +03031981 +03031982 +03031983 +03031984 +03031985 +03031986 +03031987 +03031988 +03031989 +03031990 +03031991 +03031992 +03031993 +03031994 +03031995 +03031996 +03031997 +03031998 +03041975 +03041976 +03041977 +03041978 +03041979 +03041980 +03041981 +03041982 +03041983 +03041984 +03041985 +03041986 +03041987 +03041988 +03041989 +03041990 +03041991 +03041992 +03041993 +03041994 +03041995 +03041996 +03051979 +03051980 +03051981 +03051982 +03051983 +03051984 +03051985 +03051986 +03051987 +03051988 +03051989 +03051990 +03051991 +03051992 +03051993 +03051994 +03051995 +03051996 +03061978 +03061979 +03061980 +03061981 +03061982 +03061983 +03061984 +03061985 +03061986 +03061987 +03061988 +03061989 +03061990 +03061991 +03061992 +03061993 +03061994 +03061995 +03061996 +03071977 +03071978 +03071979 +03071980 +03071981 +03071982 +03071983 +03071984 +03071985 +03071986 +03071987 +03071988 +03071989 +03071990 +03071991 +03071992 +03071993 +03071994 +03071995 +03071996 +03081977 +03081978 +03081979 +03081980 +03081981 +03081982 +03081983 +03081984 +03081985 +03081986 +03081987 +03081988 +03081989 +03081990 +03081991 +03081992 +03081993 +03081994 +03081995 +03082006 +03091977 +03091979 +03091980 +03091981 +03091982 +03091983 +03091984 +03091985 +03091986 +03091987 +03091988 +03091989 +03091990 +03091991 +03091992 +03091993 +03091994 +03101978 +03101979 +03101980 +03101981 +03101982 +03101983 +03101984 +03101985 +03101986 +03101987 +03101988 +03101989 +03101990 +03101991 +03101992 +03101993 +03101994 +03101995 +03101996 +03110311 +03111976 +03111980 +03111981 +03111982 +03111983 +03111984 +03111985 +03111986 +03111987 +03111988 +03111989 +03111990 +03111991 +03111992 +03111993 +03120312 +03121976 +03121979 +03121980 +03121981 +03121982 +03121983 +03121984 +03121985 +03121986 +03121987 +03121988 +03121989 +03121990 +03121991 +03121992 +03121993 +03121994 +03121995 +03121996 +03210321 +0321654987 +04011980 +04011981 +04011982 +04011983 +04011984 +04011985 +04011986 +04011987 +04011988 +04011989 +04011990 +04011991 +04011992 +04011993 +04011994 +04021980 +04021981 +04021982 +04021983 +04021984 +04021985 +04021986 +04021987 +04021988 +04021989 +04021990 +04021991 +04021992 +04021993 +04021994 +04022000 +04031980 +04031981 +04031982 +04031983 +04031984 +04031985 +04031986 +04031987 +04031988 +04031989 +04031990 +04031991 +04031992 +04031993 +04031994 +04040404 +04041974 +04041975 +04041977 +04041978 +04041979 +04041980 +04041981 +04041982 +04041983 +04041984 +04041985 +04041986 +04041987 +04041988 +04041989 +04041990 +04041991 +04041992 +04041993 +04041994 +04041995 +04041996 +04041997 +04051977 +04051978 +04051979 +04051980 +04051981 +04051982 +04051983 +04051984 +04051985 +04051986 +04051987 +04051988 +04051989 +04051990 +04051991 +04051992 +04051993 +04051994 +04051995 +04051996 +04061977 +04061978 +04061980 +04061981 +04061982 +04061983 +04061984 +04061985 +04061986 +04061987 +04061988 +04061989 +04061990 +04061991 +04061992 +04061993 +04061994 +04061995 +04061996 +04071979 +04071980 +04071981 +04071982 +04071983 +04071984 +04071985 +04071986 +04071987 +04071988 +04071989 +04071990 +04071991 +04071992 +04071993 +04071994 +04071995 +04071996 +04081978 +04081979 +04081980 +04081981 +04081982 +04081983 +04081984 +04081985 +04081986 +04081987 +04081988 +04081989 +04081990 +04081991 +04081992 +04081993 +04081994 +04081995 +04091979 +04091980 +04091981 +04091982 +04091983 +04091984 +04091985 +04091986 +04091987 +04091988 +04091989 +04091990 +04091991 +04091992 +04091993 +04091994 +04101980 +04101981 +04101982 +04101983 +04101984 +04101985 +04101986 +04101987 +04101988 +04101989 +04101990 +04101991 +04101992 +04101993 +04101994 +04111980 +04111982 +04111983 +04111984 +04111985 +04111986 +04111987 +04111988 +04111989 +04111990 +04111991 +04111992 +04111993 +04120412 +04121977 +04121980 +04121981 +04121982 +04121983 +04121984 +04121985 +04121986 +04121987 +04121988 +04121989 +04121990 +04121991 +04121992 +04121993 +04121994 +04200420 +05011980 +05011981 +05011982 +05011983 +05011984 +05011985 +05011986 +05011987 +05011988 +05011989 +05011990 +05011991 +05011992 +05011993 +05011994 +05021978 +05021979 +05021980 +05021981 +05021982 +05021983 +05021984 +05021985 +05021986 +05021987 +05021988 +05021989 +05021990 +05021991 +05021992 +05021993 +05021994 +05021995 +05021996 +05031980 +05031981 +05031982 +05031983 +05031984 +05031985 +05031986 +05031987 +05031988 +05031989 +05031990 +05031991 +05031992 +05031993 +05031994 +05031996 +05041977 +05041979 +05041980 +05041981 +05041982 +05041983 +05041984 +05041985 +05041986 +05041987 +05041988 +05041989 +05041990 +05041991 +05041992 +05041993 +05041994 +05041995 +05050505 +05051971 +05051975 +05051976 +05051977 +05051978 +05051979 +05051980 +05051981 +05051982 +05051983 +05051984 +05051985 +05051986 +05051987 +05051988 +05051989 +05051990 +05051991 +05051992 +05051993 +05051994 +05051995 +05051996 +05051997 +05052005 +05061978 +05061979 +05061980 +05061981 +05061982 +05061983 +05061984 +05061985 +05061986 +05061987 +05061988 +05061989 +05061990 +05061991 +05061992 +05061993 +05061994 +05061995 +05061996 +05071977 +05071978 +05071979 +05071980 +05071981 +05071982 +05071983 +05071984 +05071985 +05071986 +05071987 +05071988 +05071989 +05071990 +05071991 +05071992 +05071993 +05071994 +05071995 +05071996 +05081979 +05081980 +05081980bija +05081981 +05081982 +05081983 +05081984 +05081985 +05081986 +05081987 +05081988 +05081989 +05081990 +05081991 +05081992 +05081993 +05081994 +05081995 +05091978 +05091979 +05091980 +05091981 +05091982 +05091983 +05091984 +05091985 +05091986 +05091987 +05091988 +05091989 +05091990 +05091991 +05091992 +05091993 +05091994 +05091995 +05101978 +05101979 +05101980 +05101981 +05101982 +05101983 +05101984 +05101985 +05101986 +05101987 +05101988 +05101989 +05101990 +05101991 +05101992 +05101993 +05101994 +05101995 +05111980 +05111981 +05111982 +05111983 +05111984 +05111985 +05111986 +05111987 +05111988 +05111989 +05111990 +05111991 +05111992 +05111993 +05121978 +05121980 +05121981 +05121982 +05121983 +05121984 +05121985 +05121986 +05121987 +05121988 +05121989 +05121990 +05121991 +05121992 +05121993 +05121994 +05121995 +05200520 +0523213511 +055001984 +05mustang +06011980 +06011981 +06011982 +06011983 +06011984 +06011985 +06011986 +06011987 +06011988 +06011989 +06011990 +06011991 +06011992 +06011993 +06011994 +06011995 +06021979 +06021980 +06021981 +06021982 +06021983 +06021984 +06021985 +06021986 +06021987 +06021988 +06021989 +06021990 +06021991 +06021992 +06021993 +06021994 +06021996 +06031978 +06031981 +06031982 +06031983 +06031984 +06031985 +06031986 +06031987 +06031988 +06031989 +06031990 +06031991 +06031992 +06031993 +06031994 +06031996 +06041979 +06041980 +06041981 +06041982 +06041983 +06041984 +06041985 +06041986 +06041987 +06041988 +06041989 +06041990 +06041991 +06041992 +06041993 +06041994 +06041995 +06051980 +06051981 +06051982 +06051983 +06051984 +06051985 +06051986 +06051987 +06051988 +06051989 +06051990 +06051991 +06051992 +06051993 +06051994 +06051995 +06060606 +06061975 +06061976 +06061977 +06061978 +06061979 +06061980 +06061981 +06061982 +06061983 +06061984 +06061985 +06061986 +06061987 +06061988 +06061989 +06061990 +06061991 +06061992 +06061993 +06061994 +06061995 +06061996 +06062006 +06071978 +06071979 +06071980 +06071981 +06071982 +06071983 +06071984 +06071985 +06071986 +06071987 +06071988 +06071989 +06071990 +06071991 +06071992 +06071993 +06071994 +06071995 +06071996 +06081977 +06081979 +06081980 +06081981 +06081982 +06081983 +06081984 +06081985 +06081986 +06081987 +06081988 +06081989 +06081990 +06081991 +06081992 +06081993 +06081994 +06091979 +06091980 +06091981 +06091982 +06091983 +06091984 +06091985 +06091986 +06091987 +06091988 +06091989 +06091990 +06091991 +06091992 +06091993 +06091994 +06091995 +06101978 +06101979 +06101980 +06101981 +06101982 +06101983 +06101984 +06101985 +06101986 +06101987 +06101988 +06101989 +06101990 +06101991 +06101992 +06101993 +06101994 +06111980 +06111981 +06111982 +06111983 +06111984 +06111985 +06111986 +06111987 +06111988 +06111989 +06111990 +06111991 +06111992 +06121978 +06121979 +06121980 +06121981 +06121982 +06121983 +06121984 +06121985 +06121986 +06121987 +06121988 +06121989 +06121990 +06121991 +06121992 +06121993 +06121994 +06121995 +0676135313 +07011980 +07011981 +07011982 +07011983 +07011984 +07011985 +07011986 +07011987 +07011988 +07011989 +07011990 +07011991 +07011992 +07011993 +07011994 +07021980 +07021981 +07021982 +07021983 +07021984 +07021985 +07021986 +07021987 +07021988 +07021989 +07021990 +07021991 +07021992 +07021993 +07021994 +07021995 +07031980 +07031981 +07031982 +07031983 +07031984 +07031985 +07031986 +07031987 +07031988 +07031989 +07031990 +07031991 +07031992 +07031993 +07031995 +07041978 +07041979 +07041980 +07041981 +07041982 +07041983 +07041984 +07041985 +07041986 +07041987 +07041988 +07041989 +07041990 +07041991 +07041992 +07041993 +07041994 +07041995 +07051979 +07051980 +07051981 +07051982 +07051983 +07051984 +07051985 +07051986 +07051987 +07051988 +07051989 +07051990 +07051991 +07051992 +07051993 +07051994 +07051995 +07061978 +07061980 +07061981 +07061982 +07061983 +07061984 +07061985 +07061985nina +07061986 +07061987 +07061988 +07061989 +07061990 +07061991 +07061992 +07061993 +07061994 +07061995 +07070707 +07071976 +07071977 +07071978 +07071979 +07071980 +07071981 +07071982 +07071983 +07071984 +07071985 +07071986 +07071987 +07071988 +07071989 +07071990 +07071991 +07071992 +07071993 +07071994 +07071995 +07071997 +07071998 +07072007 +07081978 +07081979 +07081980 +07081981 +07081982 +07081983 +07081984 +07081985 +07081986 +07081987 +07081988 +07081989 +07081990 +07081991 +07081992 +07081993 +07081994 +07091980 +07091981 +07091982 +07091983 +07091984 +07091985 +07091986 +07091987 +07091988 +07091989 +07091990 +07091991 +07091992 +07091993 +07091994 +07091995 +07101962 +07101980 +07101981 +07101982 +07101983 +07101984 +07101985 +07101986 +07101987 +07101988 +07101989 +07101990 +07101991 +07101992 +07101993 +07101994 +07101995 +07111980 +07111981 +07111982 +07111983 +07111984 +07111985 +07111986 +07111987 +07111988 +07111989 +07111990 +07111991 +07111992 +07111993 +07121979 +07121980 +07121981 +07121982 +07121983 +07121984 +07121985 +07121986 +07121987 +07121988 +07121989 +07121990 +07121991 +07121992 +07121993 +07121994 +07831505 +07860786 +08011981 +08011982 +08011983 +08011984 +08011985 +08011986 +08011987 +08011988 +08011989 +08011990 +08011991 +08011992 +08011993 +08011994 +08021980 +08021981 +08021982 +08021983 +08021984 +08021985 +08021986 +08021987 +08021988 +08021989 +08021990 +08021991 +08021992 +08021993 +08021994 +08021995 +08031977 +08031978 +08031979 +08031980 +08031981 +08031982 +08031983 +08031984 +08031985 +08031986 +08031987 +08031988 +08031989 +08031990 +08031991 +08031992 +08031993 +08031994 +08031996 +08041978 +08041980 +08041981 +08041982 +08041983 +08041984 +08041985 +08041986 +08041987 +08041988 +08041989 +08041990 +08041991 +08041992 +08041993 +08041994 +08051980 +08051981 +08051982 +08051983 +08051984 +08051985 +08051986 +08051987 +08051988 +08051989 +08051990 +08051991 +08051992 +08051993 +08051994 +08061977 +08061979 +08061980 +08061981 +08061982 +08061983 +08061984 +08061985 +08061986 +08061987 +08061988 +08061989 +08061990 +08061991 +08061992 +08061993 +08061994 +08061995 +08071980 +08071981 +08071982 +08071983 +08071984 +08071985 +08071986 +08071987 +08071988 +08071989 +08071990 +08071991 +08071992 +08071993 +08071994 +08080808 +08081973 +08081974 +08081976 +08081977 +08081978 +08081979 +08081980 +08081981 +08081982 +08081983 +08081984 +08081985 +08081986 +08081987 +08081988 +08081989 +08081990 +08081991 +08081992 +08081993 +08081994 +08081995 +08081996 +08081998 +08082008 +08090809 +08091977 +08091979 +08091980 +08091981 +08091982 +08091983 +08091984 +08091985 +08091986 +08091987 +08091988 +08091989 +08091990 +08091991 +08091992 +08091993 +08091994 +08091995 +08101980 +08101981 +08101982 +08101983 +08101984 +08101985 +08101986 +08101987 +08101988 +08101989 +08101990 +08101991 +08101992 +08101993 +08111982 +08111983 +08111984 +08111985 +08111986 +08111987 +08111988 +08111989 +08111990 +08111991 +08111992 +08111993 +08121979 +08121980 +08121981 +08121982 +08121983 +08121984 +08121985 +08121986 +08121987 +08121988 +08121989 +08121990 +08121991 +08121992 +08121993 +08121994 +08121995 +08150815 +08154711 +08520852 +08522580 +090078601 +09011982 +09011983 +09011984 +09011985 +09011986 +09011987 +09011988 +09011989 +09011990 +09011991 +09011992 +09011993 +09021977 +09021978 +09021980 +09021981 +09021982 +09021983 +09021984 +09021985 +09021986 +09021987 +09021988 +09021989 +09021990 +09021991 +09021992 +09021993 +09021994 +09021995 +09031980 +09031981 +09031982 +09031983 +09031984 +09031985 +09031986 +09031987 +09031988 +09031989 +09031990 +09031991 +09031992 +09031993 +09031994 +09031995 +09041977 +09041979 +09041980 +09041981 +09041982 +09041983 +09041984 +09041985 +09041986 +09041987 +09041988 +09041989 +09041990 +09041991 +09041992 +09041993 +09041994 +09051945 +09051978 +09051979 +09051980 +09051981 +09051982 +09051983 +09051984 +09051985 +09051986 +09051987 +09051988 +09051989 +09051990 +09051991 +09051992 +09051993 +09051994 +09051995 +09061976 +09061980 +09061981 +09061982 +09061983 +09061984 +09061985 +09061986 +09061987 +09061988 +09061989 +09061990 +09061991 +09061992 +09061993 +09061994 +09061995 +09071980 +09071981 +09071982 +09071983 +09071984 +09071985 +09071986 +09071987 +09071988 +09071989 +09071990 +09071991 +09071992 +09071993 +09071994 +09080706 +0908070605 +09081980 +09081981 +09081982 +09081983 +09081984 +09081985 +09081986 +09081987 +09081988 +09081989 +09081990 +09081991 +09081992 +09081993 +09081994 +09090909 +0909090909 +09091088 +09091977 +09091978 +09091979 +09091980 +09091981 +09091982 +09091983 +09091984 +09091985 +09091986 +09091987 +09091988 +09091989 +09091990 +09091991 +09091992 +09091993 +09091994 +09091995 +09091999 +09092009 +09101980 +09101981 +09101982 +09101983 +09101984 +09101985 +09101986 +09101987 +09101988 +09101989 +09101990 +09101991 +09101992 +09101993 +09110911 +09111980 +09111981 +09111982 +09111983 +09111984 +09111985 +09111986 +09111987 +09111988 +09111989 +09111990 +09111991 +09111992 +09111993 +09120912 +09121980 +09121981 +09121982 +09121983 +09121984 +09121985 +09121986 +09121987 +09121988 +09121989 +09121990 +09121991 +09121992 +09121993 +09121994 +09123456 +0912345678 +09123456789 +0931541082 +098098098 +09870987 +0987612345 +09876543 +098765432 +0987654321 +09876543210 +09876543211 +0987654321a +0987654321q +0987654321z +09877890 +0987poiu +0blivion +0cdh0v99ue +0icotpd785 +0lhhnw3v +0o0o0o0o +0o9i8u7y +0o9i8u7y6t +0okm9ijn +0okmnji9 +0p9o8i7u +0p9o8i7u6y +0password +0r968ji9ufj6 +1,00001e+14 +1,00002e+14 +1.23457e +1.23457e+11 +10000000 +1000000000 +10001000 +10002000 +100100100 +10011001 +10011975 +10011976 +10011977 +10011978 +10011979 +10011980 +10011981 +10011982 +10011983 +10011984 +10011985 +10011986 +10011987 +10011988 +10011989 +10011990 +10011991 +10011992 +10011993 +10011994 +10011995 +10011996 +10011997 +1001wdst +100200300 +10021002 +10021976 +10021977 +10021978 +10021979 +10021980 +10021981 +10021982 +10021983 +10021984 +10021985 +10021986 +10021987 +10021988 +10021989 +10021990 +10021991 +10021992 +10021993 +10021994 +10021995 +10021996 +10021997 +10031003 +10031977 +10031978 +10031979 +10031980 +10031981 +10031982 +10031983 +10031984 +10031985 +10031986 +10031987 +10031988 +10031989 +10031990 +10031991 +10031992 +10031993 +10031994 +10031995 +10041004 +10041974 +10041977 +10041978 +10041979 +10041980 +10041981 +10041982 +10041983 +10041984 +10041985 +10041986 +10041987 +10041988 +10041989 +10041990 +10041991 +10041992 +10041993 +10041994 +10041995 +10041996 +10041997 +10051005 +10051976 +10051977 +10051978 +10051979 +10051980 +10051981 +10051982 +10051983 +10051984 +10051985 +10051986 +10051987 +10051988 +10051989 +10051990 +10051991 +10051992 +10051993 +10051994 +10051995 +10051996 +10061006 +10061976 +10061977 +10061978 +10061979 +10061980 +10061981 +10061982 +10061983 +10061984 +10061985 +10061986 +10061987 +10061988 +10061989 +10061990 +10061991 +10061992 +10061993 +10061994 +10061995 +10061996 +10071007 +10071977 +10071978 +10071979 +10071980 +10071981 +10071982 +10071983 +10071984 +10071985 +10071986 +10071987 +10071988 +10071989 +10071990 +10071991 +10071992 +10071993 +10071994 +10071995 +10071996 +10081008 +10081975 +10081976 +10081977 +10081978 +10081979 +10081980 +10081981 +10081982 +10081983 +10081984 +10081985 +10081986 +10081987 +10081988 +10081989 +10081990 +10081991 +10081992 +10081993 +10081994 +10081995 +100827092 +10091009 +10091977 +10091978 +10091979 +10091980 +10091981 +10091982 +10091983 +10091984 +10091985 +10091986 +10091987 +10091988 +10091989 +10091990 +10091991 +10091992 +10091993 +10091994 +10091995 +100dollars +100grand +100million +100percent +100proof +100years +10101010 +1010101010 +10101968 +10101970 +10101972 +10101973 +10101974 +10101975 +10101976 +10101977 +10101978 +10101979 +10101980 +10101981 +10101982 +10101983 +10101984 +10101985 +10101986 +10101987 +10101988 +10101989 +10101990 +10101991 +10101992 +10101993 +10101994 +10101995 +10101996 +10101997 +10101998 +10102000 +10102008 +10102010 +10102020 +10111011 +10111213 +10111975 +10111976 +10111977 +10111978 +10111979 +10111980 +10111981 +10111982 +10111983 +10111984 +10111985 +10111986 +10111987 +10111988 +10111989 +10111990 +10111991 +10111992 +10111993 +10111994 +10111995 +10121012 +10121972 +10121974 +10121975 +10121976 +10121977 +10121978 +10121979 +10121980 +10121981 +10121982 +10121983 +10121984 +10121985 +10121986 +10121987 +10121988 +10121989 +10121990 +10121991 +10121992 +10121993 +10121994 +10121995 +10121996 +10121997 +10131013 +10141014 +10151015 +10161016 +10171017 +10181018 +10191019 +10200718 +10201020 +102030102030 +10203040 +1020304050 +102030405060 +102030405060708090 +102102102 +10211021 +10221022 +10231023 +10241024 +10251025 +10261026 +10271027 +10281028 +10291029 +10293847 +1029384756 +1029384756a +1029384756q +10301030 +10311031 +10401040 +10661066 +10711071 +10971199 +1098765432 +10987654321 +10fingers +10inches +10million +10qpalzm +11-05-1992 +11001001 +11001100 +110110110 +110110jp +11011101 +110119120 +11011977 +11011978 +11011979 +11011980 +11011981 +11011982 +11011983 +11011984 +11011985 +11011986 +11011987 +11011988 +11011989 +11011990 +11011991 +11011992 +11011993 +11011994 +11011995 +11011996 +110120119 +110120130 +11021102 +11021977 +11021978 +11021979 +11021980 +11021981 +11021982 +11021983 +11021984 +11021985 +11021986 +11021987 +11021988 +11021989 +11021990 +11021991 +11021992 +11021993 +11021994 +11021995 +11021996 +11021997 +11021998 +11031103 +11031975 +11031977 +11031978 +11031979 +11031980 +11031981 +11031982 +11031983 +11031984 +11031985 +11031986 +11031987 +11031988 +11031989 +11031990 +11031991 +11031992 +11031993 +11031994 +11031995 +11031996 +11031997 +110331rahili +11041104 +11041976 +11041978 +11041979 +11041980 +11041981 +11041982 +11041983 +11041984 +11041985 +11041986 +11041987 +11041988 +11041989 +11041990 +11041991 +11041992 +11041993 +11041994 +11041995 +11041996 +11041997 +11051105 +11051976 +11051977 +11051978 +11051979 +11051980 +11051981 +11051982 +11051983 +11051984 +11051985 +11051986 +11051987 +11051988 +11051989 +11051990 +11051991 +11051992 +11051993 +11051994 +11051995 +11051996 +11061106 +11061976 +11061978 +11061979 +11061980 +11061981 +11061982 +11061983 +11061984 +11061985 +11061986 +11061987 +11061988 +11061989 +11061990 +11061991 +11061992 +11061993 +11061994 +11061995 +11061996 +11071107 +11071977 +11071978 +11071979 +11071980 +11071981 +11071982 +11071983 +11071984 +11071985 +11071986 +11071987 +11071988 +11071989 +11071990 +11071991 +11071992 +11071993 +11071994 +11071995 +11071996 +11081108 +11081976 +11081977 +11081978 +11081979 +11081980 +11081981 +11081982 +11081983 +11081984 +11081985 +11081986 +11081987 +11081988 +11081989 +11081990 +11081991 +11081992 +11081993 +11081994 +11081995 +11091109 +11091978 +11091979 +11091980 +11091981 +11091982 +11091983 +11091984 +11091985 +11091986 +11091987 +11091988 +11091989 +11091990 +11091991 +11091992 +11091993 +11091994 +11091995 +11091996 +11092001 +11101976 +11101978 +11101979 +11101980 +11101981 +11101982 +11101983 +11101984 +11101985 +11101986 +11101987 +11101988 +11101989 +11101990 +11101991 +11101992 +11101993 +11101994 +11101995 +11110000 +11111111 +111111111 +1111111111 +11111111111 +111111111111 +1111111111111 +11111111111111 +111111111111111 +11111111111111111111 +1111111111a +1111111111q +111111111a +111111111q +11111111a +11111111q +11111112 +11111118 +1111111a +1111111q +111111aa +111111aaa +111111prof_root2.sql.txt:, +111111prof_root3.sql.txt:, +111111qq +1111122222 +11111974 +11111975 +11111976 +11111977 +11111978 +11111979 +11111980 +11111981 +11111982 +11111983 +11111984 +11111985 +11111986 +11111987 +11111988 +11111989 +11111990 +11111991 +11111992 +11111993 +11111994 +11111995 +11111aaaaa +11111qqqqq +11112011 +11112222 +111122223333 +11113333 +11114444 +11119999 +1111aaaa +1111qqqq +11121112 +11121314 +1112131415 +11121974 +11121975 +11121976 +11121977 +11121978 +11121979 +11121980 +11121981 +11121982 +11121983 +11121984 +11121985 +11121986 +11121987 +11121988 +11121989 +11121990 +11121991 +11121992 +11121993 +11121994 +11121995 +11121996 +11121997 +11122233 +111222333 +111222333444 +111222333444555 +111222333a +111222333q +111222tianya +11131113 +111555999 +111qqq111 +111zabavina +11201120 +11211121 +112112112 +11221122 +11223300 +11223311 +112233112233 +112233123 +11223343 +11223344 +112233445 +1122334455 +112233445566 +11223344556677 +1122334455667788 +112233445566778899 +11223344556677889900 +11223344a +11223344q +11223345 +11223355 +11223366 +112233aa +112233qq +11223456 +1122qqww +11231123 +1123456789 +11235813 +1123581321 +112358132134 +11241124 +11251125 +11261126 +11271127 +11281128 +11291129 +11301130 +11331133 +11335577 +1133557799 +11341134 +11441144 +11551155 +11794591 +11921192 +11922960 +119872653 +11991199 +11aa22bb +11eleven +11november +11qq11qq +11qq22ww +11qqaazz +12001200 +1200nerds +12011201 +12011976 +12011977 +12011978 +12011979 +12011980 +12011981 +12011982 +12011983 +12011984 +12011985 +12011986 +12011987 +12011988 +12011989 +12011990 +12011991 +12011992 +12011993 +12011994 +12011995 +12011996 +120120120 +12021202 +12021974 +12021975 +12021976 +12021977 +12021978 +12021979 +12021980 +12021981 +12021982 +12021983 +12021984 +12021985 +12021986 +12021987 +12021988 +12021989 +12021990 +12021991 +12021992 +12021993 +12021994 +12021995 +12021996 +12021997 +12031203 +12031976 +12031977 +12031978 +12031979 +12031980 +12031981 +12031982 +12031983 +12031984 +12031985 +12031986 +12031987 +12031988 +12031989 +12031990 +12031991 +12031992 +12031993 +12031994 +12031995 +12031996 +12031997 +12041204 +12041961 +12041976 +12041977 +12041978 +12041979 +12041980 +12041981 +12041982 +12041983 +12041984 +12041985 +12041986 +12041987 +12041988 +12041989 +12041990 +12041991 +12041992 +12041993 +12041994 +12041995 +12041996 +12051205 +12051976 +12051977 +12051978 +12051979 +12051980 +12051981 +12051982 +12051983 +12051984 +12051985 +12051986 +12051987 +12051988 +12051989 +12051990 +12051991 +12051992 +12051993 +12051994 +12051995 +12051996 +12051997 +12061206 +12061976 +12061977 +12061978 +12061979 +12061980 +12061981 +12061982 +12061983 +12061984 +12061985 +12061986 +12061987 +12061988 +12061989 +12061990 +12061991 +12061992 +12061993 +12061994 +12061995 +12061996 +12061997 +12071207 +12071976 +12071977 +12071978 +12071979 +12071980 +12071981 +12071982 +12071983 +12071984 +12071985 +12071986 +12071987 +12071988 +12071989 +12071990 +12071991 +12071992 +12071993 +12071994 +12071995 +12071996 +12081208 +12081975 +12081976 +12081977 +12081978 +12081979 +12081980 +12081981 +12081982 +12081983 +12081984 +12081985 +12081986 +12081987 +12081988 +12081989 +12081990 +12081991 +12081992 +12081993 +12081994 +12081995 +12081996 +12091209 +12091976 +12091977 +12091978 +12091979 +12091980 +12091981 +12091982 +12091983 +12091984 +12091985 +12091986 +12091987 +12091988 +12091989 +12091990 +12091991 +12091992 +12091993 +12091994 +12091995 +12091996 +12101210 +12101961 +12101974 +12101975 +12101976 +12101977 +12101978 +12101979 +12101980 +12101981 +12101982 +12101983 +12101984 +12101985 +12101986 +12101987 +12101988 +12101989 +12101990 +12101991 +12101992 +12101993 +12101994 +12101995 +12101996 +1211109032 +12111211 +1211123a +12111977 +12111978 +12111979 +12111980 +12111981 +12111982 +12111983 +12111984 +12111985 +12111986 +12111987 +12111988 +12111989 +12111990 +12111991 +12111992 +12111993 +12111994 +12111995 +12121212 +1212121212 +121212121212 +12121212a +121212qw +12121313 +12121970 +12121972 +12121973 +12121974 +12121975 +12121976 +12121977 +12121978 +12121979 +12121980 +12121981 +12121982 +12121983 +12121984 +12121985 +12121986 +12121987 +12121988 +12121989 +12121990 +12121991 +12121992 +12121993 +12121994 +12121995 +12121996 +12121997 +12122000 +12122008 +12122012 +1212312121 +12123434 +12123456 +1212qwqw +12131213 +12131415 +1213141516 +1213141516171819 +12141214 +12151215 +12152325 +12161216 +12171217 +12181218 +12191219 +12201220 +12211221 +12213443 +12231223 +1223334444 +122333444455555 +12233445 +12241224 +12251225 +12261226 +12271227 +12280202 +12281228 +12291229 +12300123 +12301230 +123012301230 +12304560 +12311231 +12312300 +12312312 +123123123 +1231231230 +1231231231 +123123123123 +123123123123123 +1231231234 +123123123a +123123123q +123123123z +123123321 +12312345 +123123456 +123123456456 +123123aa +123123aaa +123123abc +123123as +123123asd +123123qq +123123qw +123123qwe +123123qweqwe +123123zz +12321232 +123212321 +1232323q +123234345 +123258789 +12331233 +12332100 +12332112 +123321123 +123321123321 +1233211234567 +12332145 +123321456 +123321456654 +123321aa +123321abc +123321as +123321asd +123321fvfv +123321qaz +123321qq +123321qw +123321qwe +123321qweewq +123321zxc +1234!@#$ +12340000 +12340987 +12341234 +123412341234 +123412345 +12341234a +12341234q +12342234 +1234321a +1234321q +12343412 +12344321 +123443211 +12344321a +12344321q +1234509876 +12345123 +123451234 +1234512345 +123451234512345 +123454321 +123454321a +123454321q +1234554321 +1234554321a +1234554321q +123456** +123456.. +12345600 +123456000 +12345610 +12345611 +12345612 +123456123 +1234561234 +123456123456 +123456286 +123456321 +123456456 +12345654 +12345654321 +12345656 +12345665 +123456654 +1234566543 +123456654321 +12345666 +12345670 +12345671 +1234567123 +12345671234567 +12345676 +1234567654321 +12345677 +12345677654321 +123456777 +12345678 +123456780 +1234567809 +123456781 +1234567812345678 +123456787 +123456788 +1234567887654321 +1234567889 +123456789 +123456789! +123456789* +123456789+ +123456789- +123456789. +1234567890 +1234567890- +1234567890-= +1234567890. +12345678900 +123456789000 +12345678900987654321 +12345678901 +123456789012 +1234567890123 +123456789012345 +1234567890123456 +12345678901234567890 +12345678909 +1234567890987654321 +1234567890a +1234567890abc +1234567890d +1234567890f +1234567890k +1234567890l +1234567890m +1234567890o +1234567890p +1234567890q +1234567890qaz +1234567890qw +1234567890qwe +1234567890qwer +1234567890qwert +1234567890qwerty +1234567890qwertyuiop +1234567890r +1234567890s +1234567890v +1234567890w +1234567890z +1234567891 +12345678910 +123456789101 +1234567891011 +123456789101112 +12345678910a +12345678911 +12345678912 +123456789123 +1234567891234 +12345678912345 +123456789123456 +1234567891234567 +123456789123456789 +1234567892 +1234567895 +1234567896 +12345678963 +1234567897 +123456789789 +1234567898 +12345678987654321 +1234567899 +123456789987 +123456789987654 +1234567899876543 +123456789987654321 +12345678999 +123456789@ +123456789_ +123456789a +123456789aa +123456789aaa +123456789ab +123456789abc +123456789abcd +123456789abcde +123456789as +123456789asd +123456789asdf +123456789az +123456789b +123456789c +123456789d +123456789e +123456789f +123456789g +123456789h +123456789i +123456789j +123456789k +123456789l +123456789lol +123456789love +123456789m +123456789ma +123456789n +123456789o +123456789ok +123456789p +123456789q +123456789qaz +123456789qq +123456789qqq +123456789qw +123456789qwe +123456789qwer +123456789qwert +123456789qwerty +123456789qwertyuio +123456789qwertyuiop +123456789r +123456789s +123456789t +123456789u +123456789v +123456789w +123456789x +123456789y +123456789z +123456789zx +123456789zxc +123456789zxcvbnm +123456789zz +123456789zzz +12345678a +12345678aa +12345678ab +12345678abc +12345678as +12345678b +12345678bj +12345678c +12345678d +12345678e +12345678f +12345678g +12345678h +12345678i +12345678j +12345678k +12345678l +12345678m +12345678n +12345678o +12345678p +12345678q +12345678qw +12345678qwe +12345678qwertyui +12345678r +12345678s +12345678t +12345678u +12345678v +12345678w +12345678x +12345678y +12345678z +12345679 +123456798 +1234567a +1234567aa +1234567ab +1234567abc +1234567as +1234567asd +1234567b +1234567c +1234567d +1234567e +1234567f +1234567g +1234567h +1234567i +1234567j +1234567k +1234567l +1234567m +1234567n +1234567o +1234567p +1234567q +1234567qq +1234567qw +1234567qwe +1234567qwerty +1234567qwertyu +1234567r +1234567s +1234567t +1234567u +1234567v +1234567w +1234567x +1234567y +1234567z +123456852 +12345687 +12345688 +12345689 +12345698 +123456987 +12345699 +123456aa +123456aaa +123456ab +123456abc +123456abcd +123456abcdef +123456ad +123456al +123456am +123456as +123456asd +123456asdf +123456asdfgh +123456ass +123456az +123456bb +123456cc +123456da +123456dd +123456dj +123456dm +123456er +123456ff +123456gg +123456gh +123456go +123456hh +123456hi +123456jb +123456jc +123456jj +123456jk +123456jr +123456kk +123456kl +123456ll +123456lol +123456love +123456ma +123456mama +123456me +123456mm +123456mn +123456ms +123456ok +123456pa +123456po +123456pp +123456prof_root2.sql.txt:, +123456prof_root3.sql.txt:, +123456qa +123456qaz +123456qq +123456qqq +123456qw +123456qwe +123456qwer +123456qwert +123456qwerty +123456rr +123456ru +123456sa +123456sd +123456ss +123456tt +123456ty +123456ww +123456www +123456xx +123456xxx +123456yu +123456yy +123456zx +123456zxc +123456zxcv +123456zxcvbn +123456zz +123456zzz +123456й +12345789 +123459876 +12345aaa +12345abc +12345abcd +12345abcde +12345asd +12345asdf +12345asdfg +12345lol +12345love +12345qaz +12345qqq +12345qwe +12345qwer +12345qwert +12345qwertasdfg +12345qwerty +12345rewq +12345sex +12345six +12345tgb +12345trewq +12345zxc +12345zxcvb +12345zzz +12346789 +12347890 +12348765 +12348878 +12349876 +123498765 +1234aaaa +1234abcd +1234anna +1234asdf +1234five +1234kids +1234love +1234pass +1234qwer +1234qwerasdf +1234qwerasdfzxcv +1234qwert +1234qwerty +1234rewq +1234wert +1234zxcv +12351235 +12356789 +12356790 +123578951 +123581321 +12361236 +123654123 +12365478 +123654789 +1236547890 +123654789a +123654789q +123654987 +123698547 +12369874 +123698741 +123698745 +1236987450 +1236987456 +123698745a +123789456 +123789654 +123789852 +123789abc +12381238 +123987456 +123a123a +123a456b +123aaa123 +123abc123 +123abc123abc +123abc456 +123abcde +123admin +123admin32 +123admin321 +123admin321a +123angel +123apple +123as123 +123asd123 +123asd123asd +123asd456 +123asd88 +123asdfg +123asdqwe +123asdzxc +123bitch +123chris +123david +123e123e +123ewqasd +123ewqasdcxz +123fuckyou +123green +123happy +123hello +123hfjdk147 +123iloveme +123iloveu +123india +123itsme +123jesus +123killer +123lol123 +123masha +123money +123monkey +123mudar +123music +123myspace +123odidol +123passwor +123password +123pormi +123q123q +123qaz123 +123qazwsx +123qq123 +123qw123 +123qwaszx +123qwe,./ +123qwe123 +123qwe123qwe +123qwe321 +123qwe456 +123qwe456asd +123qwe456rty +123qwe4r +123qweas +123qweasd +123qweasdz +123qweasdzxc +123qweqwe +123qwert +123qwerty +123qwerty123 +123qwezxc +123smile +123soleil +123spill +123stella +123zxc123 +123zxcvbnm +123йцу +12401240 +12421242 +12431243 +12435687 +12451245 +12456789 +124578369 +12457896 +124578963 +12481248 +12481632 +12501250 +125125125 +12521252 +12541254 +125478963 +12561256 +12581258 +12781278 +12891289 +12901290 +12991299 +12ab34cd +12d8a377 +12e3e456 +12fuckyou +12inches +12monkey +12monkeys +12password +12q12q12q +12qazwsx +12qw12qw +12qw23we +12qw34as +12qw34er +12qw34er56ty +12qwasyx +12qwaszx +12qwerty +12s3t4p55 +12stones +12string +12wq12wq +12wqasxz +13011301 +13011977 +13011979 +13011980 +13011981 +13011982 +13011983 +13011984 +13011985 +13011986 +13011987 +13011988 +13011989 +13011990 +13011991 +13011992 +13011993 +13011994 +13011995 +13021302 +13021977 +13021978 +13021979 +13021980 +13021981 +13021982 +13021983 +13021984 +13021985 +13021986 +13021987 +13021988 +13021989 +13021990 +13021991 +13021992 +13021993 +13021994 +13021995 +13021996 +13021997 +13031303 +13031977 +13031978 +13031979 +13031980 +13031981 +13031982 +13031983 +13031984 +13031985 +13031986 +13031987 +13031988 +13031989 +13031990 +13031991 +13031992 +13031993 +13031994 +13031995 +13031996 +13041304 +13041978 +13041979 +13041980 +13041981 +13041982 +13041983 +13041984 +13041985 +13041986 +13041987 +13041988 +13041989 +13041990 +13041991 +13041992 +13041993 +13041994 +13041995 +13041996 +13051305 +13051976 +13051977 +13051978 +13051979 +13051980 +13051981 +13051982 +13051983 +13051984 +13051985 +13051986 +13051987 +13051988 +13051989 +13051990 +13051991 +13051992 +13051993 +13051994 +13051995 +13051996 +13061306 +13061978 +13061979 +13061980 +13061981 +13061982 +13061983 +13061984 +13061985 +13061986 +13061987 +13061988 +13061989 +13061990 +13061991 +13061992 +13061993 +13061994 +13061995 +13061996 +13071307 +13071977 +13071978 +13071979 +13071980 +13071981 +13071982 +13071983 +13071984 +13071985 +13071986 +13071987 +13071988 +13071989 +13071990 +13071991 +13071992 +13071993 +13071994 +13071995 +13081308 +13081977 +13081979 +13081980 +13081981 +13081982 +13081983 +13081984 +13081985 +13081986 +13081987 +13081988 +13081989 +13081990 +13081991 +13081992 +13081993 +13081994 +13081996 +13091309 +13091979 +13091980 +13091981 +13091982 +13091983 +13091984 +13091985 +13091986 +13091987 +13091988 +13091989 +13091990 +13091991 +13091992 +13091993 +13091994 +13091995 +13091996 +13101310 +13101976 +13101977 +13101978 +13101979 +13101980 +13101981 +13101982 +13101983 +13101984 +13101985 +13101986 +13101987 +13101988 +13101989 +13101990 +13101991 +13101992 +13101993 +13101994 +13101995 +13111311 +13111978 +13111979 +13111980 +13111981 +13111982 +13111983 +13111984 +13111985 +13111986 +13111987 +13111988 +13111989 +13111990 +13111991 +13111992 +13111993 +13111994 +13111995 +13121312 +13121975 +13121976 +13121977 +13121978 +13121979 +13121980 +13121981 +13121982 +13121983 +13121984 +13121985 +13121986 +13121987 +13121988 +13121989 +13121990 +13121991 +13121992 +13121993 +13121994 +13121995 +13121996 +13131313 +1313131313 +13141314 +13141516 +13145200 +13151315 +13171317 +13201320 +13211321 +132132132 +13221322 +13231323 +1323456789 +13241324 +13243546 +1324354657 +1324354657687980 +132456789 +13245768 +132465798 +13251325 +13261326 +13271327 +13281328 +13301827475 +13311331 +13324124 +13371337 +1337ness +13421342 +13451345 +13456789 +13461346 +134679258 +13467982 +134679852 +1346798520 +13489277 +13501350 +13511351 +13521352 +13531353 +13541354 +13551355 +13561356 +13571357 +13572468 +13577531 +13579000 +1357902468 +1357908642 +135791113 +1357911q +13579135 +1357913579 +13579246 +135792468 +1357924680 +13579246810 +135797531 +135798642 +1357997531 +1357reti99 +13581358 +13587930210 +13591359 +13601360 +13611361 +13621362 +13631363 +13641364 +13651365 +13661366 +13671367 +13681368 +13691369 +13701370 +13751375 +13771377 +13791379 +13801380 +139381512 +13971397 +13marino +13pass13 +13qeadzc +13thirteen +14001400 +14011401 +14011980 +14011981 +14011982 +14011983 +14011984 +14011985 +14011986 +14011987 +14011988 +14011989 +14011990 +14011991 +14011992 +14011993 +14011994 +14011995 +14021402 +14021975 +14021976 +14021977 +14021978 +14021979 +14021980 +14021981 +14021982 +14021983 +14021984 +14021985 +14021986 +14021987 +14021988 +14021989 +14021990 +14021991 +14021992 +14021993 +14021994 +14021995 +14021996 +14021997 +14022008 +14022009 +14031403 +14031972 +14031977 +14031978 +14031979 +14031980 +14031981 +14031982 +14031983 +14031984 +14031985 +14031986 +14031987 +14031988 +14031989 +14031990 +14031991 +14031992 +14031993 +14031994 +14031995 +14031996 +14041404 +14041976 +14041977 +14041978 +14041979 +14041980 +14041981 +14041982 +14041983 +14041984 +14041985 +14041986 +14041987 +14041988 +14041989 +14041990 +14041991 +14041992 +14041993 +14041994 +14041995 +14041997 +14051405 +14051977 +14051979 +14051980 +14051981 +14051982 +14051983 +14051984 +14051985 +14051986 +14051987 +14051988 +14051989 +14051990 +14051991 +14051992 +14051993 +14051994 +14051995 +14051996 +14051997 +14061406 +14061976 +14061977 +14061979 +14061980 +14061981 +14061982 +14061983 +14061984 +14061985 +14061986 +14061987 +14061988 +14061989 +14061990 +14061991 +14061992 +14061993 +14061994 +14061995 +14061996 +14071407 +14071977 +14071979 +14071980 +14071981 +14071982 +14071983 +14071984 +14071985 +14071986 +14071987 +14071988 +14071989 +14071990 +14071991 +14071992 +14071993 +14071994 +14071995 +14071997 +14081408 +14081979 +14081980 +14081981 +14081982 +14081983 +14081984 +14081985 +14081986 +14081987 +14081988 +14081989 +14081990 +14081991 +14081992 +14081993 +14081994 +14081995 +14081996 +14091980 +14091981 +14091982 +14091983 +14091984 +14091985 +14091986 +14091987 +14091988 +14091989 +14091990 +14091991 +14091992 +14091993 +14091994 +14091995 +14101410 +14101976 +14101978 +14101979 +14101980 +14101981 +14101982 +14101983 +14101984 +14101985 +14101986 +14101987 +14101988 +14101989 +14101990 +14101991 +14101992 +14101993 +14101994 +14101995 +14101996 +14111411 +14111978 +14111979 +14111980 +14111981 +14111982 +14111983 +14111984 +14111985 +14111986 +14111987 +14111988 +14111989 +14111990 +14111991 +14111992 +14111993 +14111994 +14111995 +14121412 +14121976 +14121977 +14121978 +14121979 +14121980 +14121981 +14121982 +14121983 +14121984 +14121985 +14121986 +14121987 +14121988 +14121989 +14121990 +14121991 +14121992 +14121993 +14121994 +14121995 +14121996 +14131413 +14141414 +14151415 +14151617 +14181418 +14201420 +1420839army +14211421 +14221422 +14231423 +14241424 +14251425 +142536789 +142753869 +14301430 +143143143 +14321432 +143445254 +14371437 +143iloveyo +143jesus +14411441 +14521452 +145236987 +14531453 +14561456 +14629227 +14701470 +147147147 +1472580369 +14725836 +147258369 +1472583690 +1472583691 +147258369a +147258369q +147258963 +147369258 +14781478 +14785236 +147852369 +1478523690 +147852369a +147852369q +147852963 +147852zes +14789632 +147896321 +147896325 +1478963250 +1478963258 +147896325a +1478963a +147963258 +14881488 +14921492 +14themoney +14theroad +15001500 +15011977 +15011978 +15011979 +15011980 +15011981 +15011982 +15011983 +15011984 +15011985 +15011986 +15011987 +15011988 +15011989 +15011990 +15011991 +15011992 +15011993 +15011994 +15011995 +15011996 +150150as +15021502 +15021976 +15021977 +15021978 +15021979 +15021980 +15021981 +15021982 +15021983 +15021984 +15021985 +15021986 +15021987 +15021988 +15021989 +15021990 +15021991 +15021992 +15021993 +15021994 +15021995 +15021996 +15031503 +15031975 +15031977 +15031978 +15031979 +15031980 +15031981 +15031982 +15031983 +15031984 +15031985 +15031986 +15031987 +15031988 +15031989 +15031990 +15031991 +15031992 +15031993 +15031994 +15031995 +15031996 +15041977 +15041978 +15041979 +15041980 +15041981 +15041982 +15041983 +15041984 +15041985 +15041986 +15041987 +15041988 +15041989 +15041990 +15041991 +15041992 +15041993 +15041994 +15041995 +15041996 +15051505 +15051975 +15051976 +15051977 +15051978 +15051979 +15051980 +15051981 +15051982 +15051983 +15051984 +15051985 +15051986 +15051987 +15051988 +15051989 +15051990 +15051991 +15051992 +15051993 +15051994 +15051995 +15051996 +15061977 +15061978 +15061979 +15061980 +15061981 +15061982 +15061983 +15061984 +15061985 +15061986 +15061987 +15061988 +15061989 +15061990 +15061991 +15061992 +15061993 +15061994 +15061995 +15061996 +15071977 +15071979 +15071980 +15071981 +15071982 +15071983 +15071984 +15071985 +15071986 +15071987 +15071988 +15071989 +15071990 +15071991 +15071992 +15071993 +15071994 +15071996 +15081508 +15081976 +15081977 +15081978 +15081979 +15081980 +15081981 +15081982 +15081983 +15081984 +15081985 +15081986 +15081987 +15081988 +15081989 +15081990 +15081991 +15081992 +15081993 +15081994 +15081995 +15081996 +15091977 +15091978 +15091979 +15091980 +15091981 +15091982 +15091983 +15091984 +15091985 +15091986 +15091987 +15091988 +15091989 +15091990 +15091991 +15091992 +15091993 +15091994 +15091995 +15092007 +15101510 +15101975 +15101976 +15101977 +15101978 +15101979 +15101980 +15101981 +15101982 +15101983 +15101984 +15101985 +15101986 +15101987 +15101988 +15101989 +15101990 +15101991 +15101992 +15101993 +15101994 +15101995 +15101996 +15111978 +15111979 +15111980 +15111981 +15111982 +15111983 +15111984 +15111985 +15111986 +15111987 +15111988 +15111989 +15111990 +15111991 +15111992 +15111993 +15111994 +15111995 +15121512 +15121975 +15121977 +15121978 +15121979 +15121980 +15121981 +15121982 +15121983 +15121984 +15121985 +15121986 +15121987 +15121988 +15121989 +15121990 +15121991 +15121992 +15121993 +15121994 +15121995 +15151515 +1515151515 +15161516 +15161718 +15201520 +15231523 +15241524 +15251525 +15253545 +15261526 +15301530 +15321532 +15421542 +15426378 +154322358 +15511551 +15516210 +15727666 +15731573 +1580@welca +1580@welcamino +1580welcamino +15901590 +1590736tany +159159159 +159258357 +159263487 +15935700 +159357000 +159357123 +159357159357 +1593572468 +1593572486 +159357258 +159357258456 +15935728 +159357456 +15935746 +159357852 +15935789 +159487263 +159632478 +159635741 +15975300 +159753123 +159753159 +159753159753 +15975321 +1597532468 +1597532486 +159753258 +159753258456 +1597532684 +159753456 +159753456852 +15975346 +1597534682 +159753654 +159753852 +159753852456 +159874123 +15987532 +159875321 +1598753a +159951159 +15995123 +16011978 +16011980 +16011981 +16011982 +16011983 +16011984 +16011985 +16011986 +16011987 +16011988 +16011989 +16011990 +16011991 +16011992 +16011993 +16011994 +16011995 +16011996 +16021977 +16021978 +16021979 +16021980 +16021981 +16021982 +16021983 +16021984 +16021985 +16021986 +16021987 +16021988 +16021989 +16021990 +16021991 +16021992 +16021993 +16021994 +16021995 +16021996 +16031977 +16031978 +16031980 +16031981 +16031982 +16031983 +16031984 +16031985 +16031986 +16031987 +16031988 +16031989 +16031990 +16031991 +16031992 +16031993 +16031994 +16031995 +16041976 +16041977 +16041978 +16041979 +16041980 +16041981 +16041982 +16041983 +16041984 +16041985 +16041986 +16041987 +16041988 +16041989 +16041990 +16041991 +16041992 +16041993 +16041994 +16041995 +16041997 +16051977 +16051978 +16051979 +16051980 +16051981 +16051982 +16051983 +16051984 +16051985 +16051986 +16051987 +16051988 +16051989 +16051990 +16051991 +16051992 +16051993 +16051994 +16051995 +16051996 +16051997 +16061977 +16061978 +16061980 +16061981 +16061982 +16061983 +16061984 +16061985 +16061986 +16061987 +16061988 +16061989 +16061990 +16061991 +16061992 +16061993 +16061994 +16061995 +16071978 +16071979 +16071980 +16071981 +16071982 +16071983 +16071984 +16071985 +16071986 +16071987 +16071988 +16071989 +16071990 +16071991 +16071992 +16071993 +16071994 +16081977 +16081978 +16081979 +16081980 +16081981 +16081982 +16081983 +16081984 +16081985 +16081986 +16081987 +16081988 +16081989 +16081990 +16081991 +16081992 +16081993 +16081994 +16081995 +16081996 +16091980 +16091981 +16091982 +16091983 +16091984 +16091985 +16091986 +16091987 +16091988 +16091989 +16091990 +16091991 +16091992 +16091993 +16091994 +16091995 +16101610 +16101976 +16101977 +16101978 +16101979 +16101980 +16101981 +16101982 +16101983 +16101984 +16101985 +16101986 +16101987 +16101988 +16101989 +16101990 +16101991 +16101992 +16101993 +16101994 +16101995 +16111978 +16111979 +16111980 +16111981 +16111982 +16111983 +16111984 +16111985 +16111986 +16111987 +16111988 +16111989 +16111990 +16111991 +16111992 +16111993 +16111994 +16111995 +16121612 +16121976 +16121977 +16121978 +16121979 +16121980 +16121981 +16121982 +16121983 +16121984 +16121985 +16121986 +16121987 +16121988 +16121989 +16121990 +16121991 +16121992 +16121993 +16121994 +16121995 +16121996 +16161616 +16181618 +16246149 +16641664 +168168168 +16881688 +16897168 +16899168 +168asd168 +16candles +17011701 +17011977 +17011980 +17011981 +17011982 +17011983 +17011984 +17011985 +17011986 +17011987 +17011988 +17011989 +17011990 +17011991 +17011992 +17011993 +17011994 +17011995 +17011996 +17012003 +17021977 +17021978 +17021979 +17021980 +17021981 +17021982 +17021983 +17021984 +17021985 +17021986 +17021987 +17021988 +17021989 +17021990 +17021991 +17021992 +17021993 +17021994 +17021995 +17021996 +17021997 +17031978 +17031980 +17031981 +17031982 +17031983 +17031984 +17031985 +17031986 +17031987 +17031988 +17031989 +17031990 +17031991 +17031992 +17031993 +17031994 +17031995 +17041977 +17041978 +17041979 +17041980 +17041981 +17041982 +17041983 +17041984 +17041985 +17041986 +17041987 +17041988 +17041989 +17041990 +17041991 +17041992 +17041993 +17041994 +17041995 +17051978 +17051979 +17051980 +17051981 +17051982 +17051983 +17051984 +17051985 +17051986 +17051987 +17051988 +17051989 +17051990 +17051991 +17051992 +17051993 +17051994 +17051995 +17051996 +17061978 +17061980 +17061981 +17061982 +17061983 +17061984 +17061985 +17061986 +17061987 +17061988 +17061989 +17061990 +17061991 +17061992 +17061993 +17061994 +17061995 +17071977 +17071978 +17071979 +17071980 +17071981 +17071982 +17071983 +17071984 +17071985 +17071986 +17071987 +17071988 +17071989 +17071990 +17071991 +17071992 +17071993 +17071994 +17071995 +17071996 +17071997 +17081945 +17081977 +17081978 +17081980 +17081981 +17081982 +17081983 +17081984 +17081985 +17081986 +17081987 +17081988 +17081989 +17081990 +17081991 +17081992 +17081993 +17081994 +17081995 +17091976 +17091979 +17091980 +17091981 +17091982 +17091983 +17091984 +17091985 +17091986 +17091987 +17091988 +17091989 +17091990 +17091991 +17091992 +17091993 +17091994 +17091995 +17101710 +17101975 +17101978 +17101979 +17101980 +17101981 +17101982 +17101983 +17101984 +17101985 +17101986 +17101987 +17101988 +17101989 +17101990 +17101991 +17101992 +17101993 +17101994 +17101995 +17101996 +17111979 +17111980 +17111981 +17111982 +17111983 +17111984 +17111985 +17111986 +17111987 +17111988 +17111989 +17111990 +17111991 +17111992 +17111993 +17111994 +17111995 +171204jg +17121977 +17121978 +17121979 +17121980 +17121981 +17121982 +17121983 +17121984 +17121985 +17121986 +17121987 +17121988 +17121989 +17121990 +17121991 +17121992 +17121993 +17121994 +17121995 +17121996 +17151715 +17171717 +1721k1721 +172839456 +17711771 +17746052 +17891789 +17931793 +179324865 +17ciao72 +18001800 +18011979 +18011980 +18011981 +18011982 +18011983 +18011984 +18011985 +18011986 +18011987 +18011988 +18011989 +18011990 +18011991 +18011992 +18011993 +18011994 +18011995 +18021977 +18021978 +18021979 +18021980 +18021981 +18021982 +18021983 +18021984 +18021985 +18021986 +18021987 +18021988 +18021989 +18021990 +18021991 +18021992 +18021993 +18021994 +18021995 +18021996 +18031977 +18031978 +18031979 +18031980 +18031981 +18031982 +18031983 +18031984 +18031985 +18031986 +18031987 +18031988 +18031989 +18031990 +18031991 +18031992 +18031993 +18031994 +18031995 +18031996 +18031997 +18041977 +18041978 +18041979 +18041980 +18041981 +18041982 +18041983 +18041984 +18041985 +18041986 +18041987 +18041988 +18041989 +18041990 +18041991 +18041992 +18041993 +18041994 +18041995 +18041996 +18051959 +18051978 +18051979 +18051980 +18051981 +18051982 +18051983 +18051984 +18051985 +18051986 +18051987 +18051988 +18051989 +18051990 +18051991 +18051992 +18051993 +18051994 +18051995 +18061978 +18061979 +18061980 +18061981 +18061982 +18061983 +18061984 +18061985 +18061986 +18061987 +18061988 +18061989 +18061990 +18061991 +18061992 +18061993 +18061994 +18061996 +18071979 +18071980 +18071981 +18071982 +18071983 +18071984 +18071985 +18071986 +18071987 +18071988 +18071989 +18071990 +18071991 +18071992 +18071993 +18071994 +18071995 +18081977 +18081978 +18081979 +18081980 +18081981 +18081982 +18081983 +18081984 +18081985 +18081986 +18081987 +18081988 +18081989 +18081990 +18081991 +18081992 +18081993 +18081994 +18081995 +18091978 +18091979 +18091980 +18091981 +18091982 +18091983 +18091984 +18091985 +18091986 +18091987 +18091988 +18091989 +18091990 +18091991 +18091992 +18091993 +18091994 +18101810 +18101977 +18101978 +18101979 +18101980 +18101981 +18101982 +18101983 +18101984 +18101985 +18101986 +18101987 +18101988 +18101989 +18101990 +18101991 +18101992 +18101993 +18101994 +18101995 +18101996 +18111976 +18111978 +18111980 +18111981 +18111982 +18111983 +18111984 +18111985 +18111986 +18111987 +18111988 +18111989 +18111990 +18111991 +18111992 +18111993 +18111994 +18111995 +18121812 +18121977 +18121978 +18121979 +18121980 +18121981 +18121982 +18121983 +18121984 +18121985 +18121986 +18121987 +18121988 +18121989 +18121990 +18121991 +18121992 +18121993 +18121994 +18121995 +18121996 +18181818 +18191819 +18211821 +18273645 +18297649 +182blink +18436572 +18811881 +18811938 +18atcskd2w +18n28n24a5 +18street +18wheeler +19001560 +19001570 +19001900 +19011977 +19011980 +19011981 +19011982 +19011983 +19011984 +19011985 +19011986 +19011987 +19011988 +19011989 +19011990 +19011991 +19011992 +19011993 +19011994 +19011995 +19011996 +19021902 +19021975 +19021977 +19021978 +19021979 +19021980 +19021981 +19021982 +19021983 +19021984 +19021985 +19021986 +19021987 +19021988 +19021989 +19021990 +19021991 +19021992 +19021993 +19021994 +19021995 +19021996 +19031903 +19031979 +19031980 +19031981 +19031982 +19031983 +19031984 +19031985 +19031986 +19031987 +19031988 +19031989 +19031990 +19031991 +19031992 +19031993 +19031994 +19031995 +19031996 +19031997 +19032003 +19041977 +19041978 +19041979 +19041980 +19041981 +19041982 +19041983 +19041984 +19041985 +19041986 +19041987 +19041988 +19041989 +19041990 +19041991 +19041992 +19041993 +19041994 +19041995 +19051905 +19051977 +19051978 +19051979 +19051980 +19051981 +19051982 +19051983 +19051984 +19051985 +19051986 +19051987 +19051988 +19051989 +19051990 +19051991 +19051992 +19051993 +19051994 +19051995 +19051996 +19051997 +19052005 +19061978 +19061979 +19061980 +19061981 +19061982 +19061983 +19061984 +19061985 +19061986 +19061987 +19061988 +19061989 +19061990 +19061991 +19061992 +19061993 +19061994 +19061995 +19061996 +19071907 +19071978 +19071979 +19071980 +19071981 +19071982 +19071983 +19071984 +19071985 +19071986 +19071987 +19071988 +19071989 +19071990 +19071991 +19071992 +19071993 +19071994 +19071995 +19071996 +19072007 +1907fener +19081908 +19081977 +19081978 +19081980 +19081981 +19081982 +19081983 +19081984 +19081985 +19081986 +19081987 +19081988 +19081989 +19081990 +19081991 +19081992 +19081993 +19081994 +19081995 +19091977 +19091978 +19091979 +19091980 +19091981 +19091982 +19091983 +19091984 +19091985 +19091986 +19091987 +19091988 +19091989 +19091990 +19091991 +19091992 +19091993 +19091994 +19091995 +19101910 +19101977 +19101978 +19101979 +19101980 +19101981 +19101982 +19101983 +19101984 +19101985 +19101986 +19101987 +19101988 +19101989 +19101990 +19101991 +19101992 +19101993 +19101994 +19101995 +19111911 +19111979 +19111980 +19111981 +19111982 +19111983 +19111984 +19111985 +19111986 +19111987 +19111988 +19111989 +19111990 +19111991 +19111992 +19111993 +19111994 +19111996 +19121912 +19121977 +19121978 +19121979 +19121980 +19121981 +19121982 +19121983 +19121984 +19121985 +19121986 +19121987 +19121988 +19121989 +19121990 +19121991 +19121992 +19121993 +19121994 +19121995 +19121996 +19141914 +19171917 +19191919 +19201920 +19216801 +19221922 +19231923 +19251925 +19271927 +19281928 +19283746 +192837465 +1928374655 +192837465a +19371937 +19372846 +19381938 +19391939 +19391945 +19401940 +1941-1945 +19411941 +19411945 +19421942 +19431943 +19441944 +19451945 +19461946 +19471947 +19481948 +19491001 +19491949 +19501950 +19511951 +19521952 +19531953 +19541954 +19551955 +1955chevy +19561956 +19571957 +1957chevy +19581958 +19591959 +19601960 +19611961 +19621962 +19631963 +19641964 +19651965 +19661966 +19671967 +19681968 +19691969 +1969camaro +19701970 +19711971 +19721972 +19731973 +19733791 +19734682 +197346825 +19741974 +19751975 +19761968serg +19761976 +19771977 +19781978 +19791979 +19791980 +1979pool +19801980 +19801981 +19801982 +19810301 +19811981 +19811982 +19821010 +19821012 +19821020 +19821023 +19821028 +19821108 +19821209 +19821212 +19821982 +19821983 +19821984 +19822891 +1982gonzo +19831010 +19831015 +19831020 +19831022 +19831120 +19831212 +19831983 +19831984 +19831985 +19833891 +19841001 +19841002 +19841007 +19841010 +19841011 +19841012 +19841013 +19841014 +19841015 +19841016 +19841017 +19841018 +19841019 +19841020 +19841021 +19841022 +19841023 +19841024 +19841025 +19841026 +19841027 +19841028 +19841029 +19841120 +19841121 +19841123 +19841124 +19841125 +19841212 +19841224 +19841225 +19841984 +19841985 +19841986 +19844891 +19850101 +19851001 +19851010 +19851011 +19851012 +19851015 +19851016 +19851018 +19851020 +19851022 +19851023 +19851024 +19851025 +19851028 +19851030 +19851111 +19851120 +19851121 +19851122 +19851123 +19851125 +19851126 +19851127 +19851203 +19851210 +19851211 +19851212 +19851213 +19851215 +19851216 +19851217 +19851218 +19851220 +19851223 +19851224 +19851225 +19851228 +19851230 +19851985 +19851986 +19851987 +19855891 +19860101 +19860214 +19861001 +19861002 +19861010 +19861011 +19861012 +19861013 +19861015 +19861016 +19861017 +19861018 +19861020 +19861021 +19861022 +19861023 +19861024 +19861025 +19861026 +19861028 +19861030 +19861103 +19861106 +19861110 +19861111 +19861115 +19861119 +19861120 +19861121 +19861122 +19861123 +19861124 +19861125 +19861126 +19861210 +19861211 +19861212 +19861213 +19861214 +19861215 +19861216 +19861218 +19861220 +19861223 +19861224 +19861225 +19861226 +19861986 +19861987 +19861988 +19866891 +19870101 +19870111 +19870212 +19871010 +19871012 +19871015 +19871016 +19871020 +19871021 +19871023 +19871024 +19871025 +19871026 +19871028 +19871029 +19871111 +19871120 +19871212 +19871225 +19871987 +198719871987 +19871988 +19871989 +19877891 +19881010 +19881212 +19881988 +19881989 +19888891 +1988comeer +19891229 +19891989 +19899891 +19900991 +19901990 +19901991 +19902000ttt +19911991 +19911992 +19912009 +19921992 +19921993 +19922991 +19931993 +19931994 +19932008 +19932009 +19933991 +1993ga4mi +19941028 +19941994 +19941995 +19942009 +19944991 +19951995 +19951996 +19952009 +19955991 +19960122 +19960309 +19961996 +19961997 +19966991 +19971997 +19971998 +19977991 +19980621 +19981998 +19991999 +19992000 +1a1a1a1a +1a1a1a1a1a +1a2a3a4a +1a2a3a4a5a +1a2a3a4a5a6a +1a2b3c4d +1a2b3c4d5e +1a2b3c4d5e6f +1a2s3d4f +1a2s3d4f5g +1a2s3d4f5g6h +1aaliyah +1abcdefg +1abcdefgh +1adgjmptw +1alabama +1alejandro +1alexander +1america +1american +1andonly +1anthony +1antonio +1arsenal +1asdfghj +1asdfghjkl +1asshole +1atlanta +1babyboy +1babydoll +1babygirl +1babygurl +1babylove +1badbitch +1badgirl +1barbara +1baseball +1basketbal +1bastard +1beautiful +1benjamin +1bigcock +1bigdaddy +1bigdick +1bigfish +1bighead +1bigpimp +1billion +1bitches +1blessed +1blessing +1blondie +1boricua +1bradley +1brandon +1brianna +1brittany +1brooklyn +1brother +1bubbles +1budlight +1bulldog +1bullshit +1business +1buttercup +1butterfly +1butthead +1californi +1cameron +1carolina +1cecream +1champion +1charles +1charlie +1cheater +1chelsea +1chester +1cheyenne +1chicago +1chicken +1chocolate +1chopper +1chrisbrow +1christian +1christina +1christine +1christmas +1christoph +1ck75iflga +1cocacola +1computer +1cookies +1cooldude +1coolguy +1corazon +1corvette +1country +1courtney +1cowboys +1cowgirl +1cracker +1cricket +1crystal +1cupcake +1cutiepie +1danielle +1daughter +1december +1derrick +1destiny +1diamond +1dickhead +1dolphin +1dontknow +1dreamer +1drowssap +1drpepper +1drummer +1dumbass +1eastside +1element +1elephant +1elizabeth +1estrella +1f3q8aunke +1fineday +1fireman +1fish2fish +1fishing +1florida +1flowers +1football +1forever +1fptjtl919 +1fr2rfq7xl +1frankie +1freedom +1freeman +1friends +1fuckoff +1fuckyou +1g2w3e4r +1gabriel +1gangsta +1gangster +1gateway +1georgia +1getmoney +1goddess +1godisgood +1goodgirl +1grandma +1grandpa +1greenday +1hateyou +1heather +1hollywood +1hotbitch +1hotchick +1hotgirl +1hotmail +1hotmama +1hotmomma +1hotstuff +1houston +1hundred +1husband +1hustler +1hxboqg2s +1icecream +1iffqb66tw +1iloveme +1iloveyou +1internet +1inuyasha +1isabella +1jackass +1jackson +1jamaica +1jasmine +1jehovah +1jellybean +1jennifer +1jessica +1johncena +1johnson +1jonathan +1juggalo +1justice +1kenneth +1kimberly +1kingdom +1kittycat +1l0v3y0u +1ladybug +1lesbian +1letmein +1life1love +1life2live +1lilmama +1lilwayne +1linkedin +1liverpool +1lollipop +1love1life +1love4ever +1love4life +1love4me +1lovebaby +1lovebug +1lovechris +1lovegod +1loveher +1lovehim +1lovejesus +1lovelife +1lovelove +1lovemom +1lovemusic +1loverboy +1loveyou +1luckydog +1madison +1malaysia +1manarmy +1maryjane +1matthew +1maxwell +1melissa +1mercedes +1metallica +1mexican +1michael +1michelle +1midnight +1million +1mnbvcxz +1monique +1monster +1montana +1moretime +1mountain +1mustang +1myspace +1myspace1 +1natalie +1natasha +1newlife +1newport +1newyork +1nicholas +1nirvana +1nothing +1november +1nternet +1ofakind +1olmetec1 +1onelove +1orlando +1panther +1passion +1password +1password1 +1password2 +1patches +1patricia +1patrick +1peaches +1pebbles +1penguin +1phoenix +1pioneer +1pitbull +1playboy +1pokemon +1poohbear +1popcorn +1pothead +1precious +1princess +1promise +1pumpkin +1q1q1q1q +1q1q1q1q1q +1q2q3q4q +1q2q3q4q5q +1q2w1q2w +1q2w3e1q2w3e +1q2w3e4r +1q2w3e4r5 +1q2w3e4r5t +1q2w3e4r5t6 +1q2w3e4r5t6y +1q2w3e4r5t6y7 +1q2w3e4r5t6y7u +1q2w3e4r5t6y7u8 +1q2w3e4r5t6y7u8i +1q2w3e4r5t6y7u8i9o +1q2w3e4r5t6y7u8i9o0p +1q2w3e4r5t6z +1q2w3easd +1q3e2w4r +1q3e5t7u +1q3e5t7u9o +1qa2ws3ed +1qa2ws3ed4rf +1qa2ws3ed4rf5tg +1qasw23ed +1qay2wsx +1qayxsw2 +1qaz!qaz +1qaz0okm +1qaz1qaz +1qaz2wsx +1qaz2wsx3 +1qaz2wsx3e +1qaz2wsx3edc +1qaz2wsx3edc4rfv +1qaz2wsx3edc4rfv5tgb +1qaz3edc +1qaz@wsx +1qazwsxedc +1qazxcvb +1qazxcvbnm +1qazxdr5 +1qazxsw2 +1qazxsw23 +1qazxsw23e +1qazxsw23edc +1qazxsw23edcvfr4 +1qazxsw@ +1qazzaq! +1qazzaq1 +1qw21qw2 +1qw23er4 +1qw23er45t +1qweasdzxc +1qwerty1 +1qwerty2 +1qwerty7 +1qwertyu +1qwertyui +1qwertyuio +1qwertyuiop +1raiders +1rainbow +1raymond +1realnigga +1rebecca +1redhead +1redneck +1redrose +1remember +1richard +1rockstar +1rooster +1rosebud +1sabella +1sabrina +1samantha +1samsung +1savannah +1scarface +1scooter +1scorpio +1sebastian +1september +1sexybitch +1sexyboy +1sexygirl +1sexygurl +1sexylady +1sexymama +1sexyman +1shannon +1shithead +1shot1kill +1slipknot +1snickers +1snowball +1snowman +1softball +1soldier +1southside +1spencer +1spiderman +1spongebob +1starwars +1stclass +1steelers +1stephanie +1stephen +1stplace +1strawberr +1stunner +1success +1sunflower +1sunshine +1superman +1superstar +1sweetie +1sweetpea +1teacher +1teddybear +1thuglife +1thunder +1thursday +1tiffany +1timothy +1tinkerbel +1toomany +1treehill +1trinity +1trouble +1truelove +1two3four +1twothree +1ty2an3ja +1unicorn +1urkilbth674 +1v7upjw3nt +1vampire +1vanessa +1veronica +1victoria +1vincent +1w2e3r4t +1w2q3r4e +1w2w3w4w +1warrior +1welcome +1westside +1wetpussy +1whatever +1wildcat +1william +1williams +1winston +1wordpass +1yankees +1z2x3c4v +1z2x3c4v5b +1z2x3c4v5b6n +1zachary +1zg1h9suza +1zn6fpn01n +1zn6fpn01x +1zxcvbnm +1zyybyt82a +1й2ц3у +1й2ц3у4к +1й2ц3у4к5е +20000000 +20002000 +2000comeer +20011975 +20011977 +20011978 +20011979 +20011980 +20011981 +20011982 +20011983 +20011984 +20011985 +20011986 +20011987 +20011988 +20011989 +20011990 +20011991 +20011992 +20011993 +20011994 +20011995 +20011996 +20012001 +20012002 +20012003 +20012005 +20012007 +20021967 +20021975 +20021976 +20021977 +20021978 +20021979 +20021980 +20021981 +20021982 +20021983 +20021984 +20021985 +20021986 +20021987 +20021988 +20021989 +20021990 +20021991 +20021992 +20021993 +20021994 +20021995 +20021996 +20021997 +20022002 +20022003 +20022004 +20022006 +20022007 +20031975 +20031976 +20031977 +20031978 +20031979 +20031980 +20031981 +20031982 +20031983 +20031984 +20031985 +20031986 +20031987 +20031988 +20031989 +20031990 +20031991 +20031992 +20031993 +20031994 +20031995 +20031996 +20031997 +20032003 +20032004 +20032005 +20032006 +20032007 +20032008 +20041889 +20041976 +20041977 +20041978 +20041979 +20041980 +20041981 +20041982 +20041983 +20041984 +20041985 +20041986 +20041987 +20041988 +20041989 +20041990 +20041991 +20041992 +20041993 +20041994 +20041995 +20041996 +20042004 +20042005 +20042006 +20042007 +20042008 +20051975 +20051976 +20051977 +20051978 +20051979 +20051980 +20051981 +20051982 +20051983 +20051984 +20051985 +20051986 +20051987 +20051988 +20051989 +20051990 +20051991 +20051992 +20051993 +20051994 +20051995 +20051996 +20051997 +20052005 +20052006 +20052007 +20052008 +20052009 +20061977 +20061978 +20061979 +20061980 +20061981 +20061982 +20061983 +20061984 +20061985 +20061986 +20061987 +20061988 +20061989 +20061990 +20061991 +20061992 +20061993 +20061994 +20061995 +20061996 +20061997 +20062006 +20062007 +20062008 +20062009 +20070509031 +20071977 +20071979 +20071980 +20071981 +20071982 +20071983 +20071984 +20071985 +20071986 +20071987 +20071988 +20071989 +20071990 +20071991 +20071992 +20071993 +20071994 +20071995 +20071996 +20072007 +20072008 +20080808 +20081975 +20081977 +20081978 +20081979 +20081980 +20081981 +20081982 +20081983 +20081984 +20081985 +20081986 +20081987 +20081988 +20081989 +20081990 +20081991 +20081992 +20081993 +20081994 +20081995 +20081996 +20082008 +200820082 +20082009 +20091975 +20091977 +20091978 +20091979 +20091980 +20091981 +20091982 +20091983 +20091984 +20091985 +20091986 +20091987 +20091988 +20091989 +20091990 +20091991 +20091992 +20091993 +20091994 +20091995 +20091996 +20092008 +20092009 +20092010 +20100728 +20101975 +20101976 +20101977 +20101978 +20101979 +20101980 +20101981 +20101982 +20101983 +20101984 +20101985 +20101986 +20101987 +20101988 +20101989 +20101990 +20101991 +20101992 +20101993 +20101994 +20101995 +20101996 +20101997 +20102000 +20102007 +20102010 +20102011 +2010comer +20111976 +20111977 +20111978 +20111979 +20111980 +20111981 +20111982 +20111983 +20111984 +20111985 +20111986 +20111987 +20111988 +20111989 +20111990 +20111991 +20111992 +20111993 +20111994 +20111995 +20111996 +20112011 +20112012 +20121204 +20121207 +20121975 +20121976 +20121977 +20121978 +20121979 +20121980 +20121981 +20121982 +20121983 +20121984 +20121985 +20121986 +20121987 +20121988 +20121989 +20121990 +20121991 +20121992 +20121993 +20121994 +20121995 +20121996 +20122012 +2012comeer +20132013 +20142014 +20152015 +20202020 +2020202020 +20212021 +20252025 +20302030 +20304050 +20462046 +21002100 +21011974 +21011977 +21011978 +21011979 +21011980 +21011981 +21011982 +21011983 +21011984 +21011985 +21011986 +21011987 +21011988 +21011989 +21011990 +21011991 +21011992 +21011993 +21011994 +21011995 +21011996 +21011997 +21012101 +21021978 +21021979 +21021980 +21021981 +21021982 +21021983 +21021984 +21021985 +21021986 +21021987 +21021988 +21021989 +21021990 +21021991 +21021992 +21021993 +21021994 +21021995 +21021996 +21031977 +21031978 +21031979 +21031980 +21031981 +21031982 +21031983 +21031984 +21031985 +21031986 +21031987 +21031988 +21031989 +21031990 +21031991 +21031992 +21031993 +21031994 +21031995 +21031996 +21031997 +21032103 +21041977 +21041978 +21041979 +21041980 +21041981 +21041982 +21041983 +21041984 +21041985 +21041986 +21041987 +21041988 +21041989 +21041990 +21041991 +21041992 +21041993 +21041994 +21041995 +21041996 +21042104 +21051976 +21051977 +21051978 +21051979 +21051980 +21051981 +21051982 +21051983 +21051984 +21051985 +21051986 +21051987 +21051988 +21051989 +21051990 +21051991 +21051992 +21051993 +21051994 +21051995 +21051996 +21051997 +21052003 +21052105 +21061978 +21061979 +21061980 +21061981 +21061982 +21061983 +21061984 +21061985 +21061986 +21061987 +21061988 +21061989 +21061990 +21061991 +21061992 +21061993 +21061994 +21061995 +21061996 +21062106 +21071977 +21071978 +21071979 +21071980 +21071981 +21071982 +21071983 +21071984 +21071985 +21071986 +21071987 +21071988 +21071989 +21071990 +21071991 +21071992 +21071993 +21071994 +21071995 +21072107 +21081978 +21081979 +21081980 +21081981 +21081982 +21081983 +21081984 +21081985 +21081986 +21081987 +21081988 +21081989 +21081990 +21081991 +21081992 +21081993 +21081994 +21081995 +21081996 +21082108 +21091977 +21091979 +21091980 +21091981 +21091982 +21091983 +21091984 +21091985 +21091986 +21091987 +21091988 +21091989 +21091990 +21091991 +21091992 +21091993 +21091994 +21091995 +21092109 +21101976 +21101977 +21101978 +21101979 +21101980 +21101981 +21101982 +21101983 +21101984 +21101985 +21101986 +21101987 +21101988 +21101989 +21101990 +21101991 +21101992 +21101993 +21101994 +21101995 +21102110 +21111977 +21111978 +21111979 +21111980 +21111981 +21111982 +21111983 +21111984 +21111985 +21111986 +21111987 +21111988 +21111989 +21111990 +21111991 +21111992 +21111993 +21111994 +21111995 +21121976 +21121977 +21121978 +21121979 +21121980 +21121981 +21121982 +21121983 +21121984 +21121985 +21121986 +21121987 +21121988 +21121989 +21121990 +21121991 +21121992 +21121993 +21121994 +21121995 +21121996 +21122012 +21122112 +2112rush +21152117 +21212121 +2121212121 +2121321e +2121321q +21222122 +21222324 +212224236 +21232123 +21252125 +21312131 +21314151 +21342134 +213546879 +21436587 +2143658709 +214dallas +21864812 +2199127551 +21ainiyan +22002200 +22011979 +22011980 +22011981 +22011982 +22011983 +22011984 +22011985 +22011986 +22011987 +22011988 +22011989 +22011990 +22011991 +22011992 +22011993 +22011994 +22011995 +22011996 +22011997 +22012201 +22021977 +22021978 +22021979 +22021980 +22021981 +22021982 +22021983 +22021984 +22021985 +22021986 +22021987 +22021988 +22021989 +22021990 +22021991 +22021992 +22021993 +22021994 +22021995 +22021996 +22021997 +22022002 +22022202 +22031975 +22031976 +22031977 +22031978 +22031979 +22031980 +22031981 +22031982 +22031983 +22031984 +22031985 +22031986 +22031987 +22031988 +22031989 +22031990 +22031991 +22031992 +22031993 +22031994 +22031995 +22031996 +22032203 +22041976 +22041977 +22041978 +22041979 +22041980 +22041981 +22041982 +22041983 +22041984 +22041985 +22041986 +22041987 +22041988 +22041989 +22041990 +22041991 +22041992 +22041993 +22041994 +22041995 +22041996 +22041997 +22051977 +22051978 +22051979 +22051980 +22051981 +22051982 +22051983 +22051984 +22051985 +22051986 +22051987 +22051988 +22051989 +22051990 +22051991 +22051992 +22051993 +22051994 +22051995 +22051996 +22051997 +22052205 +22061941 +22061976 +22061977 +22061978 +22061979 +22061980 +22061981 +22061982 +22061983 +22061984 +22061985 +22061986 +22061987 +22061988 +22061989 +22061990 +22061991 +22061992 +22061993 +22061994 +22061995 +22061996 +22071972 +22071977 +22071979 +22071980 +22071981 +22071982 +22071983 +22071984 +22071985 +22071986 +22071987 +22071988 +22071989 +22071990 +22071991 +22071992 +22071993 +22071994 +22071995 +22081977 +22081978 +22081979 +22081980 +22081981 +22081982 +22081983 +22081984 +22081985 +22081986 +22081987 +22081988 +22081989 +22081990 +22081991 +22081992 +22081993 +22081994 +22081995 +22081996 +22091978 +22091979 +22091980 +22091981 +22091982 +22091983 +22091984 +22091985 +22091986 +22091987 +22091988 +22091989 +22091990 +22091991 +22091992 +22091993 +22091994 +22091995 +22091996 +220a220a +22101976 +22101977 +22101978 +22101979 +22101980 +22101981 +22101982 +22101983 +22101984 +22101985 +22101986 +22101987 +22101988 +22101989 +22101990 +22101991 +22101992 +22101993 +22101994 +22101995 +22101996 +22101997 +22102210 +22111976 +22111978 +22111979 +22111980 +22111981 +22111982 +22111983 +22111984 +22111985 +22111986 +22111987 +22111988 +22111989 +22111990 +22111991 +22111992 +22111993 +22111994 +22111995 +22112211 +22121977 +22121978 +22121979 +22121980 +22121981 +22121982 +22121983 +22121984 +22121985 +22121986 +22121987 +22121988 +22121989 +22121990 +22121991 +22121992 +22121993 +22121994 +22121995 +22121996 +22122212 +22132213 +22152182 +22221111 +22222222 +222222222 +2222222222 +222222222222 +22223333 +22224444 +222333444 +22312231 +22332233 +22334455 +2233445566 +223456789 +22362236 +2238qwer +22442244 +22446688 +2244668800 +22552255 +22558800 +22772277 +228228228 +22882288 +22janv67 +23011978 +23011980 +23011981 +23011982 +23011983 +23011984 +23011985 +23011986 +23011987 +23011988 +23011989 +23011990 +23011991 +23011992 +23011993 +23011994 +23011995 +23011996 +23011997 +23012301 +23021977 +23021978 +23021979 +23021980 +23021981 +23021982 +23021983 +23021984 +23021985 +23021986 +23021987 +23021988 +23021989 +23021990 +23021991 +23021992 +23021993 +23021994 +23021995 +23021996 +23022302 +23031977 +23031978 +23031979 +23031980 +23031981 +23031982 +23031983 +23031984 +23031985 +23031986 +23031987 +23031988 +23031989 +23031990 +23031991 +23031992 +23031993 +23031994 +23031995 +23031996 +23032303 +23041977 +23041978 +23041979 +23041980 +23041981 +23041982 +23041983 +23041984 +23041985 +23041986 +23041987 +23041988 +23041989 +23041990 +23041991 +23041992 +23041993 +23041994 +23041995 +23041996 +23041997 +23042304 +23051978 +23051979 +23051980 +23051981 +23051982 +23051983 +23051984 +23051985 +23051986 +23051987 +23051988 +23051989 +23051990 +23051991 +23051992 +23051993 +23051994 +23051995 +23051996 +23051997 +23052305 +23061976 +23061978 +23061979 +23061980 +23061981 +23061982 +23061983 +23061984 +23061985 +23061986 +23061987 +23061988 +23061989 +23061990 +23061991 +23061992 +23061993 +23061994 +23061995 +23061996 +23071977 +23071978 +23071979 +23071980 +23071981 +23071982 +23071983 +23071984 +23071985 +23071986 +23071987 +23071988 +23071989 +23071990 +23071991 +23071992 +23071993 +23071994 +23071995 +23071996 +23081977 +23081978 +23081979 +23081980 +23081981 +23081982 +23081983 +23081984 +23081985 +23081986 +23081987 +23081988 +23081989 +23081990 +23081991 +23081992 +23081993 +23081994 +23081995 +23081996 +23082308 +23091977 +23091978 +23091979 +23091980 +23091981 +23091982 +23091983 +23091984 +23091985 +23091986 +23091987 +23091988 +23091989 +23091990 +23091991 +23091992 +23091993 +23091994 +23091995 +23101977 +23101978 +23101979 +23101980 +23101981 +23101982 +23101983 +23101984 +23101985 +23101986 +23101987 +23101988 +23101989 +23101990 +23101991 +23101992 +23101993 +23101994 +23101995 +23101996 +23102310 +23111977 +23111978 +23111979 +23111980 +23111981 +23111982 +23111983 +23111984 +23111985 +23111986 +23111987 +23111988 +23111989 +23111990 +23111991 +23111992 +23111993 +23111994 +23111995 +23112311 +23121977 +23121978 +23121979 +23121980 +23121981 +23121982 +23121983 +23121984 +23121985 +23121986 +23121987 +23121988 +23121989 +23121990 +23121991 +23121992 +23121993 +23121994 +23121995 +23121996 +23121997 +23122312 +23132313 +23142314 +23212321 +23232323 +2323232323 +23242324 +23242526 +23252325 +23262326 +23322332 +234234234 +23452345 +23456789 +234567890 +2345678z +23562356 +23628221 +23692369 +23isback +23jordan +23skidoo +23wesdxc +24011980 +24011981 +24011982 +24011983 +24011984 +24011985 +24011986 +24011987 +24011988 +24011989 +24011990 +24011991 +24011992 +24011993 +24011994 +24011995 +24011996 +24021976 +24021978 +24021980 +24021981 +24021982 +24021983 +24021984 +24021985 +24021986 +24021987 +24021988 +24021989 +24021990 +24021991 +24021992 +24021993 +24021994 +24021995 +24021996 +24031977 +24031979 +24031980 +24031981 +24031982 +24031983 +24031984 +24031985 +24031986 +24031987 +24031988 +24031989 +24031990 +24031991 +24031992 +24031993 +24031994 +24031995 +24041978 +24041979 +24041980 +24041981 +24041982 +24041983 +24041984 +24041985 +24041986 +24041987 +24041988 +24041989 +24041990 +24041991 +24041992 +24041993 +24041994 +24041995 +24041996 +24051978 +24051980 +24051981 +24051982 +24051983 +24051984 +24051985 +24051986 +24051987 +24051988 +24051989 +24051990 +24051991 +24051992 +24051993 +24051994 +24051995 +24051996 +24061978 +24061979 +24061980 +24061981 +24061982 +24061983 +24061984 +24061985 +24061986 +24061987 +24061988 +24061989 +24061990 +24061991 +24061992 +24061993 +24061994 +24061995 +24071980 +24071981 +24071982 +24071983 +24071984 +24071985 +24071986 +24071987 +24071988 +24071989 +24071990 +24071991 +24071992 +24071993 +24071994 +24071995 +24081977 +24081978 +24081979 +24081980 +24081981 +24081982 +24081983 +24081984 +24081985 +24081986 +24081987 +24081988 +24081989 +24081990 +24081991 +24081992 +24081993 +24081994 +24081995 +24081996 +24091979 +24091980 +24091981 +24091982 +24091983 +24091984 +24091985 +24091986 +24091987 +24091988 +24091989 +24091990 +24091991 +24091992 +24091993 +24091994 +24101977 +24101978 +24101979 +24101980 +24101981 +24101982 +24101983 +24101984 +24101985 +24101986 +24101987 +24101988 +24101989 +24101990 +24101991 +24101992 +24101993 +24101994 +24101995 +24101996 +24102410 +24111978 +24111979 +24111980 +24111981 +24111982 +24111983 +24111984 +24111985 +24111986 +24111987 +24111988 +24111989 +24111990 +24111991 +24111992 +24111993 +24111994 +24111995 +24112411 +24121976 +24121977 +24121978 +24121979 +24121980 +24121981 +24121982 +24121983 +24121984 +24121985 +24121986 +24121987 +24121988 +24121989 +24121990 +24121991 +24121992 +24121993 +24121994 +24121995 +24121996 +24122412 +2416101113 +24242424 +24252425 +24262426 +24422442 +2468013579 +24681012 +2468101214 +24681357 +246813579 +24682468 +24688642 +24692469 +24862486 +24gordon +25002500 +25011978 +25011979 +25011980 +25011981 +25011982 +25011983 +25011984 +25011985 +25011986 +25011987 +25011988 +25011989 +25011990 +25011991 +25011992 +25011993 +25011994 +25011995 +25011996 +25012501 +25021977 +25021978 +25021979 +25021980 +25021981 +25021982 +25021983 +25021984 +25021985 +25021986 +25021987 +25021988 +25021989 +25021990 +25021991 +25021992 +25021993 +25021994 +25021995 +25031978 +25031980 +25031981 +25031982 +25031983 +25031984 +25031985 +25031986 +25031987 +25031988 +25031989 +25031990 +25031991 +25031992 +25031993 +25031994 +25031995 +25031996 +25032503 +25041977 +25041978 +25041979 +25041980 +25041981 +25041982 +25041983 +25041984 +25041985 +25041986 +25041987 +25041988 +25041989 +25041990 +25041991 +25041992 +25041993 +25041994 +25041995 +25041996 +25041997 +25051975 +25051976 +25051977 +25051978 +25051979 +25051980 +25051981 +25051982 +25051983 +25051984 +25051985 +25051986 +25051987 +25051988 +25051989 +25051990 +25051991 +25051992 +25051993 +25051994 +25051995 +25051996 +25052005 +25052505 +25061977 +25061978 +25061979 +25061980 +25061981 +25061982 +25061983 +25061984 +25061985 +25061986 +25061987 +25061988 +25061989 +25061990 +25061991 +25061992 +25061993 +25061994 +25061996 +25071977 +25071978 +25071979 +25071980 +25071981 +25071982 +25071983 +25071984 +25071985 +25071986 +25071987 +25071988 +25071989 +25071990 +25071991 +25071992 +25071993 +25071994 +25071995 +25081978 +25081979 +25081980 +25081981 +25081982 +25081983 +25081984 +25081985 +25081986 +25081987 +25081988 +25081989 +25081990 +25081991 +25081992 +25081993 +25081994 +25081995 +25082508 +25091978 +25091979 +25091980 +25091981 +25091982 +25091983 +25091984 +25091985 +25091986 +25091987 +25091988 +25091989 +25091990 +25091991 +25091992 +25091993 +25091994 +25091995 +25091996 +25101977 +25101978 +25101979 +25101980 +25101981 +25101982 +25101983 +25101984 +25101985 +25101986 +25101987 +25101988 +25101989 +25101990 +25101991 +25101992 +25101993 +25101994 +25101995 +25102510 +25111978 +25111979 +25111980 +25111981 +25111982 +25111983 +25111984 +25111985 +25111986 +25111987 +25111988 +25111989 +25111990 +25111991 +25111992 +25111993 +25111994 +25111995 +25112511 +25121975 +25121976 +25121977 +25121978 +25121979 +25121980 +25121981 +25121982 +25121983 +25121984 +25121985 +25121986 +25121987 +25121988 +25121989 +25121990 +25121991 +25121992 +25121993 +25121994 +25121995 +25121996 +25122512 +25132513 +25142514 +25172517 +25202520 +25212521 +25222522 +25232523 +25242524 +25251325 +25252525 +2525252525 +25257758 +25262526 +25272527 +25282528 +25292529 +25302530 +25312531 +25352535 +25362536 +25393275 +25412541 +25452545 +25522552 +25632563 +256buowriz +25800852 +25802580 +258147369 +258258258 +258369147 +25892589 +258963147 +25962596 +25nuvaha +25tolife +26.09.67 +26011979 +26011980 +26011981 +26011982 +26011983 +26011984 +26011985 +26011986 +26011987 +26011988 +26011989 +26011990 +26011991 +26011992 +26011993 +26011994 +26011995 +26011996 +26021979 +26021980 +26021981 +26021982 +26021983 +26021984 +26021985 +26021986 +26021987 +26021988 +26021989 +26021990 +26021991 +26021992 +26021993 +26021994 +26021995 +26021996 +26031979 +26031980 +26031981 +26031982 +26031983 +26031984 +26031985 +26031986 +26031987 +26031988 +26031989 +26031990 +26031991 +26031992 +26031993 +26031994 +26031995 +26031996 +26031998m +26041978 +26041979 +26041980 +26041981 +26041982 +26041983 +26041984 +26041985 +26041986 +26041987 +26041988 +26041989 +26041990 +26041991 +26041992 +26041993 +26041994 +26041995 +26051980 +26051981 +26051982 +26051983 +26051984 +26051985 +26051986 +26051987 +26051988 +26051989 +26051990 +26051991 +26051992 +26051993 +26051994 +26051995 +26061977 +26061978 +26061979 +26061980 +26061981 +26061982 +26061983 +26061984 +26061985 +26061986 +26061987 +26061988 +26061989 +26061990 +26061991 +26061992 +26061993 +26061994 +26061995 +26061996 +26061997 +26071979 +26071980 +26071981 +26071982 +26071983 +26071984 +26071985 +26071986 +26071987 +26071988 +26071989 +26071990 +26071991 +26071992 +26071993 +26071994 +26071995 +26081980 +26081981 +26081982 +26081983 +26081984 +26081985 +26081986 +26081987 +26081988 +26081989 +26081990 +26081991 +26081992 +26081993 +26081994 +26081995 +26091979 +26091980 +26091981 +26091982 +26091983 +26091984 +26091985 +26091986 +26091987 +26091988 +26091989 +26091990 +26091991 +26091992 +26091993 +26091994 +26091995 +26101978 +26101979 +26101980 +26101981 +26101982 +26101983 +26101984 +26101985 +26101986 +26101987 +26101988 +26101989 +26101990 +26101991 +26101992 +26101993 +26101994 +26101995 +26101996 +26102610 +26111978 +26111979 +26111980 +26111981 +26111982 +26111983 +26111984 +26111985 +26111986 +26111987 +26111988 +26111989 +26111990 +26111991 +26111992 +26111993 +26111994 +26121977 +26121978 +26121979 +26121980 +26121981 +26121982 +26121983 +26121984 +26121985 +26121986 +26121987 +26121988 +26121989 +26121990 +26121991 +26121992 +26121993 +26121994 +26121995 +26121996 +26262626 +26665806 +26842684 +27011978 +27011979 +27011980 +27011981 +27011982 +27011983 +27011984 +27011985 +27011986 +27011987 +27011988 +27011989 +27011990 +27011991 +27011992 +27011993 +27011994 +27011995 +27021978 +27021979 +27021980 +27021981 +27021982 +27021983 +27021984 +27021985 +27021986 +27021987 +27021988 +27021989 +27021990 +27021991 +27021992 +27021993 +27021994 +27021995 +27021996 +27031978 +27031980 +27031981 +27031982 +27031983 +27031984 +27031985 +27031986 +27031987 +27031988 +27031989 +27031990 +27031991 +27031992 +27031993 +27031994 +27031995 +27041977 +27041978 +27041979 +27041980 +27041981 +27041982 +27041983 +27041984 +27041985 +27041986 +27041987 +27041988 +27041989 +27041990 +27041991 +27041992 +27041993 +27041994 +27041995 +27051977 +27051978 +27051980 +27051981 +27051982 +27051983 +27051984 +27051985 +27051986 +27051987 +27051988 +27051989 +27051990 +27051991 +27051992 +27051993 +27051994 +27051995 +27061979 +27061980 +27061981 +27061982 +27061983 +27061984 +27061985 +27061986 +27061987 +27061988 +27061989 +27061990 +27061991 +27061992 +27061993 +27061994 +27061995 +27071977 +27071978 +27071980 +27071981 +27071982 +27071983 +27071984 +27071985 +27071986 +27071987 +27071988 +27071989 +27071990 +27071991 +27071992 +27071993 +27071994 +27071995 +27072007 +27081980 +27081981 +27081982 +27081983 +27081984 +27081985 +27081986 +27081987 +27081988 +27081989 +27081990 +27081991 +27081992 +27081993 +27081994 +27091979 +27091980 +27091981 +27091982 +27091983 +27091984 +27091985 +27091986 +27091987 +27091988 +27091989 +27091990 +27091991 +27091992 +27091993 +27091994 +27091995 +27101977 +27101979 +27101980 +27101981 +27101982 +27101983 +27101984 +27101985 +27101986 +27101987 +27101988 +27101989 +27101990 +27101991 +27101992 +27101993 +27101994 +27101995 +27111978 +27111979 +27111980 +27111981 +27111982 +27111983 +27111984 +27111985 +27111986 +27111987 +27111988 +27111989 +27111990 +27111991 +27111992 +27111993 +27111994 +27121977 +27121978 +27121979 +27121980 +27121981 +27121982 +27121983 +27121984 +27121985 +27121986 +27121987 +27121988 +27121989 +27121990 +27121991 +27121992 +27121993 +27121994 +27121995 +27140621 +27254931 +27272727 +27352735 +27412678 +275-22-74 +28011980 +28011981 +28011982 +28011983 +28011984 +28011985 +28011986 +28011987 +28011988 +28011989 +28011990 +28011991 +28011992 +28011993 +28011994 +28021978 +28021980 +28021981 +28021982 +28021983 +28021984 +28021985 +28021986 +28021987 +28021988 +28021989 +28021990 +28021991 +28021992 +28021993 +28021994 +28021995 +28021996 +28031979 +28031980 +28031981 +28031982 +28031983 +28031984 +28031985 +28031986 +28031987 +28031988 +28031989 +28031990 +28031991 +28031992 +28031993 +28031994 +28031995 +28031996 +28041977 +28041979 +28041980 +28041981 +28041982 +28041983 +28041984 +28041985 +28041986 +28041987 +28041988 +28041989 +28041990 +28041991 +28041992 +28041993 +28041994 +28041995 +28051978 +28051979 +28051980 +28051981 +28051982 +28051983 +28051984 +28051985 +28051986 +28051987 +28051988 +28051989 +28051990 +28051991 +28051992 +28051993 +28051994 +28051995 +28051996 +28061977 +28061979 +28061980 +28061981 +28061982 +28061983 +28061984 +28061985 +28061986 +28061987 +28061988 +28061989 +28061990 +28061991 +28061992 +28061993 +28061994 +28071976 +28071977 +28071979 +28071980 +28071981 +28071982 +28071983 +28071984 +28071985 +28071986 +28071987 +28071988 +28071989 +28071990 +28071991 +28071992 +28071993 +28071994 +28071995 +28081976 +28081978 +28081980 +28081981 +28081982 +28081983 +28081984 +28081985 +28081986 +28081987 +28081988 +28081989 +28081990 +28081991 +28081992 +28081993 +28081994 +28081995 +28081996 +28082008 +28091979 +28091980 +28091981 +28091982 +28091983 +28091984 +28091985 +28091986 +28091987 +28091988 +28091989 +28091990 +28091991 +28091992 +28091993 +28091994 +28091995 +28101977 +28101978 +28101979 +28101980 +28101981 +28101982 +28101983 +28101984 +28101985 +28101986 +28101987 +28101988 +28101989 +28101990 +28101991 +28101992 +28101993 +28101994 +28101995 +28111980 +28111981 +28111982 +28111983 +28111984 +28111985 +28111986 +28111987 +28111988 +28111989 +28111990 +28111991 +28111992 +28111993 +28111994 +28121976 +28121977 +28121978 +28121979 +28121980 +28121981 +28121982 +28121983 +28121984 +28121985 +28121986 +28121987 +28121988 +28121989 +28121990 +28121991 +28121992 +28121993 +28121994 +28121995 +2813308004 +28282828 +28462846 +28972323 +28zxrpunfa +28zxrpvnfa +29011980 +29011981 +29011982 +29011983 +29011984 +29011985 +29011986 +29011987 +29011988 +29011989 +29011990 +29011991 +29011992 +29011993 +29011994 +29011996 +29021980 +29021984 +29021988 +29021992 +29031979 +29031980 +29031981 +29031982 +29031983 +29031984 +29031985 +29031986 +29031987 +29031988 +29031989 +29031990 +29031991 +29031992 +29031993 +29031994 +29031995 +29041979 +29041980 +29041981 +29041982 +29041983 +29041984 +29041985 +29041986 +29041987 +29041988 +29041989 +29041990 +29041991 +29041992 +29041993 +29041994 +29041995 +29041996 +29051978 +29051979 +29051980 +29051981 +29051982 +29051983 +29051984 +29051985 +29051986 +29051987 +29051988 +29051989 +29051990 +29051991 +29051992 +29051993 +29051994 +29051995 +29061979 +29061980 +29061981 +29061982 +29061983 +29061984 +29061985 +29061986 +29061987 +29061988 +29061989 +29061990 +29061991 +29061992 +29061993 +29061994 +29061995 +29061996 +29071980 +29071981 +29071982 +29071983 +29071984 +29071985 +29071986 +29071987 +29071988 +29071989 +29071990 +29071991 +29071992 +29071993 +29071994 +29071995 +29081979 +29081980 +29081981 +29081982 +29081983 +29081984 +29081985 +29081986 +29081987 +29081988 +29081989 +29081990 +29081991 +29081992 +29081993 +29081994 +29081995 +29091976 +29091977 +29091978 +29091979 +29091980 +29091981 +29091982 +29091983 +29091984 +29091985 +29091986 +29091987 +29091988 +29091989 +29091990 +29091991 +29091992 +29091993 +29091994 +29091995 +29101978 +29101979 +29101980 +29101981 +29101982 +29101983 +29101984 +29101985 +29101986 +29101987 +29101988 +29101989 +29101990 +29101991 +29101992 +29101993 +29101994 +29101995 +29101996 +29111978 +29111979 +29111980 +29111981 +29111982 +29111983 +29111984 +29111985 +29111986 +29111987 +29111988 +29111989 +29111990 +29111991 +29111992 +29111993 +29111994 +29121978 +29121979 +29121980 +29121981 +29121982 +29121983 +29121984 +29121985 +29121986 +29121987 +29121988 +29121989 +29121990 +29121991 +29121992 +29121993 +29121994 +29121995 +29271188 +292814lolo +29292929 +29422277 +29662012 +29694419 +29710455d +299792458 +299kgj8hgf +29rsavoy +2babyboys +2babygirls +2bananas +2beautiful +2bfiy28byl +2bigballs +2bigtits +2bitches +2blessed +2blueeyes +2boobies +2bornot2b +2boys1girl +2brothers +2children +2cookies +2cool4you +2cute4you +2cxdn8s271 +2daughters +2doggies +2dollars +2dragons +2dumb2live +2ealtd3y4y +2fast4you +2flowers +2friends +2fuckyou +2gangsta +2gelaf3h4a +2gether4ev +2gether4ever +2good4you +2grandkids +2h7vkzo266 +2hdq6c9azv +2hot2handl +2hot4you +2jab4x2c +2kids4me +2kittens +2kitties +2kroliczek +2letmein +2loveyou +2m66xf2ajt +2manykids +2million +2mndonaaa +2monkeys +2muchfun +2muchlove +2muchmoney +2myspace +2n66xg2ziu +2n6ezl7xhp +2n76xg2yiu +2ndchance +2nipples +2nqw7a1517 +2ofakind +2p76xg2yhv +2p76xh2xhv +2pac2pac +2pac4ever +2pac4life +2pacshakur +2password +2princess +2ps5wlc4xq +2psxvvd7 +2puppies +2q2w3e8r5t +2q3w4e5r +2q87xi3vfx +2q87xi3wgw +2qaz2wsx +2qefx7t3sy +2r97xj3xex +2r97xj3xey +2roh8tl433 +2sexy4you +2sisters +2smart4u +2sweet4u +2titties +2turtles +2w3e4r5t +2wsx1qaz +2wsx2wsx +2wsx3edc +2wsxcde3 +2wsxzaq1 +2wwerty1 +3.1415926 +3.141592654 +30003000 +30011978 +30011979 +30011980 +30011981 +30011982 +30011983 +30011984 +30011985 +30011986 +30011987 +30011988 +30011989 +30011990 +30011991 +30011992 +30011993 +30011994 +30011995 +30031977 +30031978 +30031979 +30031980 +30031981 +30031982 +30031983 +30031984 +30031985 +30031986 +30031987 +30031988 +30031989 +30031990 +30031991 +30031992 +30031993 +30031994 +30031995 +30033003 +30041978 +30041979 +30041980 +30041981 +30041982 +30041983 +30041984 +30041985 +30041986 +30041987 +30041988 +30041989 +30041990 +30041991 +30041992 +30041993 +30041994 +30041996 +30041997 +30051978 +30051979 +30051980 +30051981 +30051982 +30051983 +30051984 +30051985 +30051986 +30051987 +30051988 +30051989 +30051990 +30051991 +30051992 +30051993 +30051994 +30051995 +30051996 +30061978 +30061979 +30061980 +30061981 +30061982 +30061983 +30061984 +30061985 +30061986 +30061987 +30061988 +30061989 +30061990 +30061991 +30061992 +30061993 +30061994 +30061995 +30063006 +30071979 +30071980 +30071981 +30071982 +30071983 +30071984 +30071985 +30071986 +30071987 +30071988 +30071989 +30071990 +30071991 +30071992 +30071993 +30071994 +30081980 +30081981 +30081982 +30081983 +30081984 +30081985 +30081986 +30081987 +30081988 +30081989 +30081990 +30081991 +30081992 +30081993 +30081994 +30081995 +30091978 +30091980 +30091981 +30091982 +30091983 +30091984 +30091985 +30091986 +30091987 +30091988 +30091989 +30091990 +30091991 +30091992 +30091993 +30091994 +30091995 +30101978 +30101979 +30101980 +30101981 +30101982 +30101983 +30101984 +30101985 +30101986 +30101987 +30101988 +30101989 +30101990 +30101991 +30101992 +30101993 +30101994 +30101995 +30101996 +30103010 +30111978 +30111979 +30111980 +30111981 +30111982 +30111983 +30111984 +30111985 +30111986 +30111987 +30111988 +30111989 +30111990 +30111991 +30111992 +30111993 +30111994 +30111995 +30121978 +30121979 +30121980 +30121981 +30121982 +30121983 +30121984 +30121985 +30121986 +30121987 +30121988 +30121989 +30121990 +30121991 +30121992 +30121993 +30121994 +30121996 +30123012 +301285mn +30303030 +305miami +30624700 +30seconds +30secondstomars +31011979 +31011980 +31011981 +31011982 +31011983 +31011984 +31011985 +31011986 +31011987 +31011988 +31011989 +31011990 +31011991 +31011992 +31011993 +31011994 +31011995 +31011996 +31011997 +31031977 +31031978 +31031979 +31031980 +31031981 +31031982 +31031983 +31031984 +31031985 +31031986 +31031987 +31031988 +31031989 +31031990 +31031991 +31031992 +31031993 +31031994 +31031995 +31051977 +31051979 +31051980 +31051981 +31051982 +31051983 +31051984 +31051985 +31051986 +31051987 +31051988 +31051989 +31051990 +31051991 +31051992 +31051993 +31051994 +31051995 +31051996 +3106934abc +31071979 +31071980 +31071981 +31071982 +31071983 +31071984 +31071985 +31071986 +31071987 +31071988 +31071989 +31071990 +31071991 +31071992 +31071993 +31071994 +31071995 +31081977 +31081978 +31081979 +31081980 +31081981 +31081981rs +31081982 +31081983 +31081984 +31081985 +31081986 +31081987 +31081988 +31081989 +31081990 +31081991 +31081992 +31081993 +31081994 +31081995 +31101977 +31101978 +31101979 +31101980 +31101981 +31101982 +31101983 +31101984 +31101985 +31101986 +31101987 +31101988 +31101989 +31101990 +31101991 +31101992 +31101993 +31101994 +31101995 +31101996 +31103110 +31121977 +31121978 +31121979 +31121980 +31121981 +31121982 +31121983 +31121984 +31121985 +31121986 +31121987 +31121988 +31121989 +31121990 +31121991 +31121992 +31121993 +31121994 +31121995 +31122008 +31122009 +31123112 +31133113 +312881040 +31313131 +31415926 +314159265 +3141592653 +31415926535 +3141592654 +31415927 +31p5wtdyg +31p5wtdyg/wgq +31x7t5xbke +32103210 +32113211 +32123212 +321321321 +32143214 +321456987 +321478965 +321654987 +321654987a +3216732167 +3219993xx +321meins +32323232 +32342711 +32503250 +326159487 +32615948worms +33103310 +33221100 +33223322 +333222111 +33333333 +333333333 +3333333333 +33334444 +333444555 +333555777 +333666999 +333777333 +33443344 +33445566 +3353212li +33663366 +33rjhjds +34343434 +34416912 +34523452 +34563456 +34567890 +34erdfcv +3500sucks +350chevy +3526535265 +35353535 +35365123 +35793579 +357magnum +360modena +36363636 +3651118xun +36903690 +369258147 +369369369 +369852147 +36987412 +369874125 +36chambers +37213721 +37217086 +37373737 +37gudoplfs45 +38253825 +38383838 +38gjgeuftd +38special +39073588 +393041123 +39393939 +3ans97t397 +3bitches +3blindmice +3boys1girl +3brothers +3children +3d8cubaj2e +3daughters +3daysgrace +3dognight +3doorsdown +3e4r5t6y +3edc4rfv +3edcvfr4 +3ehd1ixi1y +3fozaqb33q +3friends +3grandkids +3iverson +3kids4me +3kitties +3l3phant +3monkeys +3odi14ngxb +3odi15ngxb +3odi55ngxb +3password +3pointer +3puppies +3q2w3e4r3t +3qdlqb49js +3qvn5k4qgv +3rjs1la2qe +3rjs1la7qe +3rjs5la8qe +3s43pth5aea +3sa8xk4xdz +3sisters +3stooges +3syqo15hil +3tb8xl42bj +3tb9xm42xi +3tktkthth +3tutso24qf +3u7wrkaa8j +3ub9xm53xi +3uc9xn53xh +3yixda15hr +3zibuvmrx6 +40028922 +40404040 +4040782as +4077mash +41034103 +41234123 +41414141 +41563445 +420420420 +4204life +420allday +420bitch +420blaze +420smoke +420stoner +421uiopy258 +42424242 +42684268 +427cobra +4294967296 +43046721 +43211234 +43214321 +4321rewq +43434343 +4391634m +43922572 +44332211 +44442013vkkv +44444444 +444444444 +4444444444 +44445555 +44448888 +444555666 +44554455 +44556677 +44f16f17f +44magnum +45124512 +45214521 +45454545 +4545454545 +45533990 +45544554 +456123789 +456456456 +45654565 +45674567 +45678910 +456789123 +45683968 +45874587 +45m2do5bs +46265216 +463395727 +46464646 +46466452 +46494649 +46709394 +47114711 +47474747 +47593893 +476730751 +48151623 +4815162342 +4815162342a +4815162342lost +4815162342q +48484848 +48624862 +49494949 +49ersrule +4beatles +4brothers +4children +4eternity +4everlove +4everluv +4evermine +4evermore +4everurs +4everyoung +4everyours +4f51eijvif +4forever +4freedom +4friends +4g3uvrxn7w +4getmenot +4grandkids +4horsemen +4j9r4rnttp +4linkedin +4me2know +4monkeys +4mutdfgvtp +4myfamily +4mygirls +4myspace +4password +4r3e2w1q +4r5t6y7u +4rfv5tgb +4rfvbgt5 +4seasons +4shizzle +4sisters +4success +4sunshine +4thekids +4thofjuly +4vdaxp542g +4vgyvq46aj +4wdaxp642f +4wdaxq642f +4weaxq642e +4wheeler +4xeaxr653e +4xebxr653d +4xxlqu94yo +4yfb2s753c +4yfb2s753d +5.254.105.20:test +5.254.105.20:test1 +50505050 +50cent123 +50cent50 +51200000 +51286700 +51505150 +51515151 +51525354 +5152535455 +51535759 +51615801 +52013140 +5201314520 +5201314a +520520520 +520love101182 +52105210 +521521521 +52253823 +52255225 +523456789 +523698741 +52525252 +52545658 +52hoover +53472235 +53535353 +54226269 +5432112345 +5432154321 +54545454 +54565456 +547896321 +551976ms +55225522 +55255525 +5532361cnjqrf +5544332211 +555151asd +55554444 +55555555 +555555555 +5555555555 +55555555555 +555555555555 +555555555555555 +5555555tl +5555566666 +55555lvl +55556666 +55558888 +555666777 +55665566 +55667788 +5566778899 +563214789 +5647382910 +56565656 +567567567 +56785678 +5678dance +56835683 +5683love +569874123 +56tyghbn +57575757 +579395571 +584131420 +584131421 +5841314520 +5841314521 +584201314 +5845201314 +5845211314 +58565254 +58585858 +59230120 +594love168 +595490067ua1 +59595959 +59635963 +5a8b9c2d +5ahc2v875z +5bhc2v875z +5bt2jtztke +5children +5element +5fingers +5grandkids +5hsu75kpot +5jn16uxpid +5million +5monkeys +5plk4l5uc7 +5q2w3e4r5t +5qwerty67890 +5starbitch +5starchick +5t4r3e2w1q +5t6y7u8i +5tgb6yhn +5tgbnhy6 +5x1cjdsb9p +5xfgs3ii9d +5xq57cgseb +5zgb2t764b +5zgc2t764b +60606060 +61616161 +619619619 +61atnakaeva +622906268 +62543234 +62626262 +63145151 +63245009 +63256632 +634142554 +63636363 +63impala +64646464 +64impala +650829yjm +65432100 +654321123456 +654321987 +654321abc +654654654 +654987321 +65656565 +65impala +65mustang +6610_2006 +66613666 +66666666 +666666666 +6666666666 +666666666666 +6666666666empulgara +66667777 +66668888 +66669999 +666777888 +666999666 +666beast +666devil +666fafnir +666satan +66778899 +66996699 +66chevelle +66mustang +673kobby +67529353 +67676767 +67896789 +67camaro +67chevelle +67mustang +67shelby +6817zd57 +68582988 +68686868 +68camaro +68charger +68chevelle +68mustang +69664848 +69696969 +6969696969 +69966996 +69camaro +69camero +69charger +69chevelle +69cougar +69mustang +69qd5cgxhu +6acaxa54be +6cctbbk516 +6children +6cs2huaulf +6cxd2x986x +6d2-24e5r +6dnwch275049 +6exe3za97v +6feetunder +6grandkids +6hbf28w791 +6letters +6lfxlo629ui +6shooter +6strings +6thgrade +6v21wbgad +6y4rv0a992 +6yhn7ujm +70142021103 +70707070 +70chevelle +71191926 +71310615 +713houston +71717171 +71chevelle +723723723 +72727272 +72chevelle +73439984 +73501505 +73737373 +737kkblskv +73jagtk4q +74107410 +74108520 +741085209630 +7410852963 +74123698 +741236985 +741258963 +741456963 +741741741 +74185296 +741852963 +7418529630 +741852963a +741852963q +741852963z +741963852 +742617000027 +74699723 +74747474 +748159263 +74a82s78 +74gangsta +753951456 +753951852 +753951852456 +75757575 +759123asd +76543210 +7654321a +7654321q +76767676 +774517397 +7753191a +77585210 +776158ab +777555333 +777555666 +77777771 +77777777 +777777777 +7777777777 +777777777777 +77777778 +7777777a +7777777c +7777777d +7777777j +7777777k +7777777m +7777777n +7777777q +7777777s +7777777v +7777777z +77778888 +77779999 +777888999 +777dashuta157 +777jesus +777kroxa +7783757s +77887788 +77889900 +784512963 +784951623 +786786786 +786allah +78787878 +78907890 +7890uiop +789123456 +78917891 +78945612 +789456123 +7894561230 +7894561231 +789456123a +789456123b +789456123m +789456123q +789456123z +789456321 +789456qwe +78951230 +789512357 +7895123z +78963214 +789632145 +789632147 +789654123 +7896541230 +789654321 +789789789 +789852123 +789987789 +78kdow9spf +791159392 +79137913 +794613258 +794613852 +79621601378.kirill +79641777070 +79797979 +79camaro +79transam +7children +7cr2gubvmg +7e9lnk3fc01 +7e9lnk3fco +7elephants +7f4df451 +7fperlangel +7fxf3jaa7u +7fxf3jba8t +7grandkids +7jokx7b9du +7nc4lqw7to +7samurai +7sfqc8zi5d +7so2ekbc6r +7thgrade +7thheaven +7u8i9o0p +7ugd5hip2j +7uqbwx8n4z +7v8bv5teow +8-9899578642 +80173rroom5 +80808080 +808state +80959002443 +80fefune +811224bai +814336633 +81726354 +81818181 +82214989 +824553435ss +82468246 +82597971 +827ccb0eea8a706c4c +82828282 +82airborne +830928urodziny +83742222 +83773049 +84131421 +84268426 +84569280 +84728472 +84848484 +849vak17 +85200258 +85207410 +85208520 +85218812 +852456852456 +852741963 +852852852 +852963741 +85726648 +85858585 +858877108aop +8602229096klo +86026403 +86248624 +86402241 +8675309a +8675309j +86868686 +870621345 +87651234 +87654321 +876543210 +87654321a +87654321q +87654321q. +87878787 +88002000600 +88488848 +88552200 +88888888 +888888881 +888888888 +8888888888 +88888888a +88889999 +88998899 +88mustang +89058895869cth +89140041205 +89173371487v +89216279708a +89217657066 +89272585 +89631139 +89898989 +89moocows +89mustang +8ba9klw1ce +8en3dwdxpi +8iiw4ct9rq +8ix6s1fceh +8letters +8phrowz622 +8phrowz624 +8rlb9l1squ +8seconds +8thgrade +8uxzd1b3bd +8wwh19duyj +8x2h4eddan +8x2h4fccap +8x2h4fddap +8xxg4gcc9q +9-11-1961 +90107142a +9021090210 +9052950013 +9086916264 +90909090 +9090909090 +911911911 +911turbo +9121318barssuki +91827364 +918273645 +91866709 +91919191 +9198425200 +91camaro +91mustang +92246247 +92298899 +922i4ceebk +922i4ddebm +922i4deebm +922j5cefcj +92631043 +9268356683 +92702689 +9293709b13 +92camaro +92dk2cidp +92k2cizcdp +9379992a +9379992q +93mustang +94246843 +94327579 +94793763 +94mustang +9508402243id +95135876 +951753123 +951753456 +951753654 +951753852 +951753852456 +951753aa +951951951 +95279527 +95368452 +95959595 +95camaro +95mustang +9602929770 +96132925 +96321478 +963214785 +963258741 +9632587410 +963741852 +96385274 +963852741 +9638527410 +963852741a +963963963 +96969696 +96impala +96mustang +9749676621ok +9797183185 +97979797 +987321654 +98741236 +987412365 +987456123 +987456321 +9874563210 +987654123 +98765432 +987654321 +9876543210 +98765432100 +9876543211 +987654321123456789 +987654321a +987654321b +987654321c +987654321d +987654321g +987654321j +987654321k +987654321l +987654321m +987654321n +987654321p +987654321q +987654321r +987654321s +987654321t +987654321w +987654321z +98766789 +98769876 +987987987 +98989898 +98mustang +99009900 +99887766 +9988776655 +99889988 +999666333 +999888777 +99990000 +99998888 +99999999 +999999999 +9999999999 +999999999999 +999999999a +99bottles +99mustang +99problems +99xfxlo19ui +9ac9hb7vvx +9inchnails +9itz78vufw +9uzp9jek3f +9xx7c8gseb +9yqss2h9ub +9yue27ri + +???????? +????????? +?????????? +??????????? +???????????? +??????????????? +??????@mail.ru +@@@@@@@@@@ +@bigmir.net +@elit-centr.com.ua +@gmail.com.mx +@mail.ru +@yahoo.com +a!515253 +a0000000 +a00000000 +a0123456 +a1111111 +a11111111 +a111111111 +a11223344 +a1169619 +a12121212 +a123123123 +a123123a +a123321a +a12341234 +a12344321 +a1234567 +a12345678 +a123456789 +a1234567890 +a123456789a +a123456a +a123456b +a123456z +a123654789 +a123a123 +a123b456 +a12b13c14 +a1314520 +a147258369 +a1a1a1a1 +a1a1a1a1a1 +a1a2a3a4 +a1a2a3a4a5 +a1a2a3a4a5a6 +a1b1c1d1 +a1b2c3d4 +a1b2c3d4e5 +a1b2c3d4e5f6 +a1l2e3x4 +a1s2d3f4 +a1s2d3f4g5 +a1s2d3f4g5h6 +a1z2e3r4 +a22j5bffci +a2345678 +a23456789 +a2a2a2a2 +a33k5afgdh +a3eilm2s2y +a42904290 +a5201314 +a6543210 +a741852963 +a7654321 +a7758521 +a7777777 +a789456123 +a7ckuntldy +a7x4life +a7xrocks +a838hfid +a8675309 +a87654321 +a88888888 +a987654321 +a9999999 +a999999999 +a:sldkfj +aa000000 +aa111111 +aa112233 +aa11bb22 +aa123123 +aa123321 +aa123456 +aa1234561 +aa1234567 +aa12345678 +aa123456789 +aa224466 +aa261599 +aa3030316 +aa456852 +aa5201314 +aaa111aaa +aaa123123 +aaa12345 +aaa123456 +aaaa0000 +aaaa1111 +aaaa1234 +aaaaa11111 +aaaaaa11 +aaaaaa12 +aaaaaa123 +aaaaaaa1 +aaaaaaa7 +aaaaaaaa +aaaaaaaa1 +aaaaaaaaa +aaaaaaaaa1 +aaaaaaaaaa +aaaaaaaaaaa +aaaaaaaaaaaa +aaaaaaaaaaaaaaa +aaaaaaaaaaaaaaaa +aaaabbbb +aaaassss +aaabbbccc +aaasssddd +aabb1122 +aabbcc123 +aabbccdd +aaliyah01 +aaliyah08 +aaliyah1 +aaliyah12 +aaliyah123 +aaliyah2 +aaliyah22 +aaliyah3 +aaliyah4 +aaliyah5 +aaliyah7 +aaprintbb +aardvark +aardvark1 +aaron123 +aaron1234 +aaron431 +aassddff +aavlg728 +ab123456 +ab12345678 +ab12cd34 +ab7f23rsv +abab1122 +abababab +abaybay1 +abbaabba +abbey123 +abbey2010 +abbeyroad +abbie123 +abbigail +abby1234 +abbydog1 +abbygail +abbygirl +abbygirl1 +abc123!@# +abc123123 +abc123321 +abc12345 +abc123456 +abc123456! +abc1234567 +abc12345678 +abc123456789 +abc123abc +abc123abc123 +abc123def +abc123def456 +abc123xyz +abcabc123 +abcabcabc +abcd1234 +abcd12345 +abcd123456 +abcd2244 +abcd4321 +abcd@1234 +abcdabcd +abcde123 +abcde1234 +abcde12345 +abcdef12 +abcdef123 +abcdef1234 +abcdef123456 +abcdefg! +abcdefg. +abcdefg1 +abcdefg12 +abcdefg123 +abcdefg2 +abcdefg3 +abcdefg5 +abcdefg7 +abcdefgh +abcdefgh1 +abcdefgh12 +abcdefghi +abcdefghi1 +abcdefghij +abcdefghijk +abcdefghijkl +abcxyz123 +abdallah +abdelkader +abdellah +abdoulaye +abdul123 +abdulaziz +abdullah +abdullah1 +abdullahi +abelardo +abenteuer +abercrombi +abercrombie +aberdeen +aberdeen1 +abgos999 +abhi1234 +abhijeet +abhilash +abhilasha +abhimanyu +abhishek +abigail01 +abigail1 +abigail11 +abigail12 +abigail123 +abigail2 +abigail3 +abigail4 +abigail5 +abigail7 +abimbola +abiodun1 +abnormal +abracadabr +abracadabra +abraham1 +abrakadabra +abramova +abrejkina +absinthe +absolut1 +absolute +absolute1 +abstract +abstract1 +abubakar +abucanda +abudhabi +abuelita +abulafia +abundance +abundance1 +abuse_123456_abuse +ac123456 +ac3sg728 +academia +academic +academy1 +acapulco +acapulco1 +accenture +access01 +access12 +access123 +accident +account1 +account123 +account2 +accountant +accounting +accounts +acdc1234 +acdcacdc +acdcrocks1 +ace12345 +ace154ever +aceeva.irina +acer1234 +aceracer +aceraspire +aceshigh +achiever +achilles +achilles1 +acidburn +acmilan1 +acmilan1899 +acoustic +acoustic1 +acquario +action123 +actionman +activate +actlg728 +actress1 +acuario1 +aczx7812 +ad123456 +adadadad +adalberto +adam1234 +adam12345 +adam2326 +adamadam +adams33486 +addicted +addicted1 +addiction +addison1 +addison2 +addl0223 +address1 +adebayo1 +adebayor +adebowale +adedoyin +adejimi1 +adekunle +adekunle1 +adelaida +adelaide +adelaide1 +adelante +adelina1 +adeline1 +adeniran +aderonke +adeshina +adetunji +adewale1 +adewunmi +adeyinka +adgjmptw +adgjmptw0 +adgjmptw1 +adidas01 +adidas10 +adidas11 +adidas12 +adidas123 +adidas13 +adidas14 +adidas21 +adidas22 +adidas23 +adidas69 +adidas777 +adidas88 +aditya123 +admin1213 +admin123 +admin1234 +admin12345 +admin123456 +admin2010 +admin@123 +adminadmin +administra +administrator +admiral1 +adnan123 +adolfhitler +adoption +adorable +adorable1 +adrenalin +adrenalina +adrenaline +adrian01 +adrian05 +adrian06 +adrian07 +adrian08 +adrian09 +adrian10 +adrian11 +adrian12 +adrian123 +adrian1234 +adrian13 +adrian14 +adrian15 +adrian16 +adrian17 +adrian18 +adrian21 +adrian22 +adrian23 +adrian24 +adrian28 +adriana1 +adriana12 +adriana123 +adriana13 +adriana2 +adrianita +adrianna +adrianna1 +adrianne +adriano1 +adriano10 +adrienne +adrienne1 +advance1 +advanced +advanced1 +advantage +adventure +adventure1 +advertising +advocate +aeiou123 +aeiou12345 +aekara21 +aerobics +aeroplane +aeropostal +aerosmith +aerosmith1 +aerospace +aezakmi1 +aezakmi123 +af123456 +affection +affinity +afganistan +afghan123 +afghanistan +afireinside +africa12 +africa123 +african1 +afrodita +afrodite +afroman1 +afterlife +aftermath +aftermath1 +agamemnon +agbdlcid +agent007 +agente007 +aggarwal +aggies12 +aggroberlin +agnieszka +agnieszka1 +agostina +agostino +agriculture +aguacate +aguilar1 +aguilas1 +aguilas10 +aguilera +agustin1 +agustina +ahbird1984 +ahmad123 +ahmed123 +ahmed12345 +ahmed_orudzhov +ahmedabad +ahmedahmed +ahmet123 +ahovbipw +ahovwpib +aidan123 +aiden123 +aikman08 +aiman123 +aimee123 +aini1314 +airborne +airborne1 +airborne82 +airbus320 +airbus380 +airbusa380 +aircraft +airedale +airforce +airforce1 +airforce2 +airhead1 +airjordan +airjordan1 +airjordan2 +airjordan23 +airmax95 +airplane +airplane1 +airplanes +airport1 +airsoft1 +airwalk1 +aisha123 +aishiteru +aishiteru1 +aishwarya +aissatou +aj123456 +ajcuivd289 +ajnjuhfabz +ak123456 +ak47ak47 +akademia +akademiks11 +akanksha +akash123 +akatsuki +akatsuki1 +akax89wn +akhilesh +akindele +akinsanmi +akinsola +akinwale +akinyemi +akira123 +akkolesnikov +akomismo +akopa123 +akril2442 +aksaray68 +aksenov.dms +aksrms8010 +akucantik +akucinta +akucintaka +akucintakamu +akuganteng +akunamatata +akusayangk +akusayangkamu +al123456 +al3xand3r +alabama1 +alabama12 +alabama123 +alabama2 +alabama3 +alabaster +aladdin1 +alakazam +alamakota +alamierda +alan1234 +alana123 +alanalan +alannah1 +alaska11 +alaska12 +alaska123 +alastair +albacete +albachiara +albania1 +albastru +albatros +albatross +albert01 +albert11 +albert12 +albert123 +albert13 +alberta1 +albertina +alberto1 +alberto10 +alberto12 +alberto123 +alberto13 +alberto2 +albina-1945 +alcantara +alcapone +alcatraz +alcatraz1 +alchemist +alchemist1 +alchemy1 +alcohol1 +aldebaran +alegria1 +alejandra +alejandra. +alejandra1 +alejandra2 +alejandra3 +alejandra7 +alejandra9 +alejandro +alejandro. +alejandro0 +alejandro1 +alejandro123 +alejandro2 +alejandro3 +alejandro5 +alejandro7 +alejandro8 +alejandro9 +aleks-270379 +aleksandar +aleksander +aleksandr +aleksandr.ustinov.2012 +aleksandra +aleksandra1 +alekseev +alekseeva +aleksej.shorin.86 +aleksis1611 +alemanha +alemania +alena123 +alena_plotnikova_1995 +alenushka +alesana1 +alessandra +alessandro +alessandro1 +alessia1 +alessio1 +alevtina +alex1234 +alex12345 +alex123456 +alex1972 +alex1973 +alex1974 +alex1975 +alex1976 +alex1977 +alex1978 +alex1979 +alex1980 +alex1981 +alex1982 +alex1983 +alex1984 +alex1985 +alex1986 +alex1987 +alex1988 +alex1989 +alex1990 +alex1991 +alex1992 +alex1993 +alex1994 +alex1995 +alex1996 +alex1997 +alex1998 +alex1999 +alex2000 +alex2001 +alex2002 +alex2003 +alex2004 +alex2005 +alex2006 +alex2007 +alex2008 +alex2009 +alex2010 +alex2011 +alex2539 +alex4ever +alexa123 +alexalex +alexalex1 +alexande +alexander +alexander! +alexander. +alexander0 +alexander1 +alexander11 +alexander12 +alexander123 +alexander2 +alexander3 +alexander4 +alexander5 +alexander6 +alexander7 +alexander8 +alexander9 +alexandr +alexandra +alexandra0 +alexandra1 +alexandra2 +alexandra3 +alexandra7 +alexandra9 +alexandre +alexandre1 +alexandrea +alexandria +alexandro +alexandros +alexandru +alexandru1 +alexdelpiero +alexdok76 +alexis00 +alexis01 +alexis02 +alexis03 +alexis04 +alexis05 +alexis06 +alexis07 +alexis08 +alexis09 +alexis10 +alexis11 +alexis12 +alexis123 +alexis1234 +alexis13 +alexis14 +alexis15 +alexis16 +alexis17 +alexis18 +alexis20 +alexis21 +alexis22 +alexis23 +alexis24 +alexis25 +alexis96 +alexis97 +alexis98 +alexis99 +alexrv_06 +alexsander +alexsandr +alexsandra +alexzander +alfaalfa +alfabeta +alfakran +alfaomega +alfaromeo +alfaromeo1 +alfie123 +alfonso1 +alfred123 +alfred19 +alfredo1 +alfredo123 +algebra1 +algebra2 +algernon +alhambra +alhamdulillah +ali12345 +ali123456 +alialiali +alianza1 +alianzalima +alibaba1 +alicante +alice123 +aliceadsl +alicia01 +alicia10 +alicia11 +alicia12 +alicia123 +alicia13 +alicia21 +alicia22 +alicia23 +alien123 +alienware +aliev0583 +aligator +alija-gatina0 +alina123 +alina1995 +alina1997 +alina1998 +alina2010 +alinaalina +aline123 +alino4ka +alinochka +alinutza +alisa123 +alisha123 +alison12 +alison123 +alistair +alitalia +aliya.mutallapova +alkaline +alkaline3 +all4jesus +all4love +allaboutme +alladin79 +allah123 +allah786 +allahabad +allahakbar +allahallah +allahhoo +allahis1 +allahisgreat +allahisone +allahoakbar +allahswt +allahuakba +allahuakbar +allalone +allalone1 +allan123 +allblack +allblacks +allblacks1 +allegra1 +allegria +allegro1 +alleluia +allen123 +alleniverson +alleycat +alleycat1 +allezlom +allgood1 +alliance +alliance1 +allie123 +alliecat +alligator +alligator1 +alligator3 +allinone +allison! +allison1 +allison11 +allison12 +allison123 +allison13 +allison2 +allison3 +allison4 +allison5 +allison7 +allister +alliswell +allmeu112 +allmine1 +allmine2 +allmylife +alloallo +allochka +allrecipes +allright +allsaints +allstar1 +allstar11 +allstar12 +allstar123 +allstar13 +allstar2 +allstar23 +allstar3 +allstar5 +allstar7 +allstars +allstars1 +allstate +allstate1 +allthebest +alltheway +alltimelow +allycat1 +allyson1 +allyssa1 +almario927 +almaz_kiramov +almendra +almighty +almighty1 +almighty5 +almudena +aloevera +aloha123 +alohamora +alohomora +alondra1 +alone4ever +alonso14 +alouette +aloysius +alpacino +alpha123 +alpha1906 +alphabet +alphabet1 +alphabeta +alphaomega +alphonse +alquimia +already1 +alright1 +alskdjfhg +alskdjfhg1 +altagracia +altamira +altavista +alteclansing +alterego +alterego1 +alternate +alternativ +alternativa +alternative +altoids1 +alucard1 +alucard666 +aluminum +alvarado +alvarado1 +alvarez1 +alvarito +alvin123 +always12 +always123 +alwaysandf +alyssa01 +alyssa02 +alyssa03 +alyssa04 +alyssa05 +alyssa06 +alyssa07 +alyssa08 +alyssa09 +alyssa10 +alyssa11 +alyssa12 +alyssa123 +alyssa13 +alyssa14 +alyssa15 +alyssa16 +alyssa21 +alyssa22 +alyssa23 +alyssa99 +am123456 +amadeus1 +amadeus55 +amanaman +amanda00 +amanda01 +amanda02 +amanda03 +amanda05 +amanda06 +amanda07 +amanda08 +amanda09 +amanda10 +amanda101 +amanda11 +amanda12 +amanda123 +amanda1234 +amanda13 +amanda14 +amanda15 +amanda16 +amanda17 +amanda18 +amanda19 +amanda20 +amanda21 +amanda22 +amanda23 +amanda24 +amanda25 +amanda26 +amanda27 +amanda33 +amanda69 +amanda77 +amanda86 +amanda87 +amanda88 +amanda89 +amanda92 +amanda93 +amanda95 +amanda99 +amandeep +amandine +amanecer +amarachi +amaretto +amarillo +amarillo1 +amarnath +amaterasu +amazing! +amazing1 +amazing123 +amazing2 +amazinggrace +amazonas +amazonia +amazonka +ambassador +amber101 +amber123 +amber1234 +amberlynn +ambiente +ambition +ambition1 +ambrose1 +ambrosia +ambrosio +ambulance +ambulance1 +amdturion64 +amelia12 +amelia123 +amenamen +america! +america#1 +america. +america01 +america07 +america08 +america09 +america1 +america10 +america100 +america11 +america12 +america123 +america13 +america14 +america15 +america16 +america17 +america18 +america2 +america21 +america22 +america23 +america3 +america4 +america5 +america6 +america7 +america8 +america9 +american +american1 +american12 +american2 +americana +americano +americanpie +americas +amerika1 +amerikanblend +amethyst +amethyst1 +ametistfatal +amicizia +amidamaru +amigo123 +amina123 +aminin94 +aminlove +amiramir +amiret2015 +amirkhan +amistad1 +amit1234 +amitkumar +ammaamma +ammaappa +ammananna +ammukutty +amoah2010 +amojesus +amor1234 +amor2009 +amoramor +amorcito +amorcito1 +amoremio +amoremio1 +amoremiotiamo +amoreterno +amoretiamo +amormio1 +amorsito +amorypaz +amorzinho +amour100 +amoureuse +amoureux +amritsar +amsterdam +amsterdam1 +an123456 +an4oys12120 +ana12345 +ana123456 +anabelen +anabella +anabelle +anacarolina +anaclara +anacleto +anaconda +anaconda1 +anaheim1 +anaheim714 +anaisabel +anajulia +anakaren +anakonda +analaura +analsex1 +analsex69 +analucia +analuisa +analuiza +anamaria +anamaria1 +anamarie +anand123 +anapaula +anarchia +anarchie +anarchist +anarchy1 +anarchy666 +anarchy99 +anarquia +anasofia +anastacia +anastacia1 +anastasia +anastasia1 +anastasija +anastasija3010 +anastasiy +anastasiya +anastasya +anathema +anatolii +anatoliy +anatomia +anatomy1 +anchorage +ancient1 +andalucia +anderlecht +andersen +anderson +anderson1 +anderson12 +anderson2 +andersson +andg1705 +andi121382 +andiamo1 +andrade1 +andre123 +andre1986 +andre3000 +andrea01 +andrea05 +andrea06 +andrea07 +andrea08 +andrea09 +andrea10 +andrea11 +andrea12 +andrea123 +andrea1234 +andrea13 +andrea14 +andrea15 +andrea16 +andrea17 +andrea18 +andrea19 +andrea20 +andrea21 +andrea22 +andrea23 +andrea24 +andrea25 +andrea69 +andrea77 +andrea88 +andrea89 +andrea99 +andreas1 +andreas123 +andreea1 +andreeva +andrei123 +andrei_rew +andreika +andreina +andreita +andrejka +andres01 +andres10 +andres12 +andres123 +andres13 +andresito +andressa +andrew00 +andrew01 +andrew02 +andrew03 +andrew04 +andrew05 +andrew06 +andrew07 +andrew08 +andrew09 +andrew10 +andrew101 +andrew11 +andrew12 +andrew123 +andrew1234 +andrew13 +andrew14 +andrew15 +andrew16 +andrew17 +andrew18 +andrew19 +andrew20 +andrew21 +andrew22 +andrew23 +andrew24 +andrew25 +andrew26 +andrew27 +andrew28 +andrew29 +andrew33 +andrew55 +andrew69 +andrew77 +andrew86 +andrew87 +andrew88 +andrew89 +andrew91 +andrew92 +andrew93 +andrew94 +andrew95 +andrew96 +andrew97 +andrew98 +andrew99 +andrews1 +andrey-1983_08 +andrey.shalanov +andrey123 +andrey1412ua +andrey1983 +andrey1995 +andrey1996 +andrey1997 +andreyka +andreyka.gorshkov.98 +andreyka.zhilin.1981 +andriana +android1 +andromeda +andromeda1 +andruhova.1982 +andrusha +andrusic1 +andrzej1 +andy1234 +andy1999 +andyandy +andyouone +andypandy +andysixx +anetka11 +anewlife +anfield1 +angarova81 +angcuteko +angedemon +angel001 +angel007 +angel100 +angel101 +angel111 +angel123 +angel1234 +angel12345 +angel143 +angel1985 +angel1987 +angel1988 +angel1989 +angel1990 +angel1991 +angel1992 +angel1993 +angel1994 +angel1995 +angel1996 +angel1997 +angel1998 +angel2000 +angel2001 +angel2003 +angel2004 +angel2005 +angel2006 +angel2007 +angel2008 +angel2009 +angel2010 +angel2011 +angel321 +angel333 +angel420 +angel4ever +angel4life +angel555 +angel637 +angel666 +angel675 +angel777 +angel911 +angel999 +angela01 +angela08 +angela10 +angela11 +angela12 +angela123 +angela13 +angela14 +angela15 +angela18 +angela21 +angela22 +angela23 +angela69 +angelangel +angelbaby +angelbaby1 +angelbaby2 +angelboy +angeldevil +angeldog +angeldust +angeles1 +angeleyes +angeleyes1 +angeleyes2 +angelface +angelface1 +angelfire +angelfire1 +angelfish +angelgirl +angelgirl1 +angelheart +angelic1 +angelica +angelica1 +angelica12 +angelica13 +angelica2 +angelidis +angelika +angelika1 +angelina +angelina1 +angelina12 +angelina2 +angelina3 +angeline +angeline1 +angelino +angelique +angelique1 +angelita +angelita1 +angelito +angelito1 +angelitos +angellove +angellove1 +angelo01 +angelo12 +angelo123 +angelo4ek +angelochek +angels01 +angels02 +angels07 +angels10 +angels11 +angels12 +angels123 +angels13 +angels21 +angels22 +angels23 +angels27 +angels69 +angels77 +angelseye22 +angelus1 +angelwings +anggandako +angie123 +angioletto +angle123 +angpogiko +angrybirds +angus123 +angusyoung +angwar77 +anhmaiyeuem +anhnhoem +anhyeuem +anhyeuem1 +anhyeuem123 +ania1986 +anilkumar +animal11 +animal12 +animal123 +animal13 +animal69 +animales +animals1 +animals12 +animals123 +animals2 +animals3 +animation +animation1 +animator +anime101 +anime123 +anime4ever +animefreak +animelover +anindita +anisoara +anita123 +anjaneya +anjelika +anjing123 +ankara06 +ankit123 +anna.savickaya.1986 +anna1234 +anna12345 +anna1982 +anna1983 +anna1984 +anna1985 +anna1986 +anna1987 +anna1988 +anna1989 +anna1990 +anna1991 +anna1992 +anna1993 +anna1994 +anna1995 +anna1996 +anna1997 +anna1998 +anna1999 +anna2000 +anna2001 +anna2002 +anna2003 +anna2004 +anna2005 +anna2006 +anna2007 +anna2008 +anna2009 +anna2010 +anna2011 +anna2976 +annaanna +annaba23 +annabel1 +annabell +annabell1 +annabella +annabella1 +annabelle +annabelle1 +annagor20 +annalena +annalisa +annalise +annaliza +annamaria +annamaria1 +annamarie +annamarie1 +annapurna +annarella +annarita +annarose +anneanne +annelies +anneliese +annelise +annemarie +annemarie1 +annette1 +annie123 +anniedog +anniversary +annmarie +annmarie1 +anno1602 +annoying +annoying1 +annushka +annywka_86 +anointed +anointed1 +anonelbe +anonymous +anonymous1 +anorexia +another1 +anoushka +anshuman +antalya07 +antares1 +anteater +antelope +anthony! +anthony. +anthony0 +anthony00 +anthony01 +anthony02 +anthony03 +anthony04 +anthony05 +anthony06 +anthony07 +anthony08 +anthony09 +anthony1 +anthony10 +anthony101 +anthony11 +anthony12 +anthony123 +anthony13 +anthony14 +anthony15 +anthony16 +anthony17 +anthony18 +anthony19 +anthony2 +anthony20 +anthony200 +anthony21 +anthony22 +anthony23 +anthony24 +anthony25 +anthony26 +anthony27 +anthony28 +anthony29 +anthony3 +anthony33 +anthony4 +anthony5 +anthony6 +anthony69 +anthony7 +anthony77 +anthony8 +anthony88 +anthony89 +anthony9 +anthony99 +anthrax1 +antichrist +antiflag +antiflag1 +antigone +antigua1 +antihero +antilles +antiques +antivirus +antoha50a +antoine1 +antoinette +anton123 +anton1995 +anton1996 +antonanton +antonela +antonella +antonella1 +antonello +antonette +antonia1 +antonichmeli +antonietta +antonina +antonine1 +antonino +antonio. +antonio01 +antonio1 +antonio10 +antonio11 +antonio12 +antonio123 +antonio13 +antonio14 +antonio15 +antonio16 +antonio17 +antonio18 +antonio2 +antonio21 +antonio22 +antonio23 +antonio3 +antonio4 +antonio5 +antonio6 +antonio69 +antonio7 +antonio8 +antonio9 +antonius +antonova +antoshka +antsiferova1973 +antusenok_zhekonya +antwerpen +anuoluwapo +anupriya +anuradha +anushree +anycall123 +anything +anything1 +anything12 +anything2 +anytime1 +anywhere +aobo2010 +aolsucks +aosamples +aotearoa +apalkova.tatiana +aparecida +apartment +apfelbaum +aphrodite +aphrodite1 +apjsqpm844 +apocalipse +apocalipsis +apocalypse +apokalipsa +apokalipsis +apollo11 +apollo12 +apollo123 +apollo13 +apologize +apolonia +appaamma +appaloosa +appelsap +apple101 +apple111 +apple123 +apple1234 +apple12345 +appleapple +applebees1 +applejack +applejack1 +applejacks +applejuice +applemac +applepie +applepie1 +applepie12 +applepie2 +apples01 +apples10 +apples11 +apples12 +apples123 +apples13 +apples22 +apples23 +applesauce +appleseed +appleseed1 +appleton +appletree +appletree1 +application +approtec +approved +april123 +april1987 +april1988 +april1990 +april1991 +april1992 +april1994 +april2006 +april2007 +april2008 +april2009 +april2010 +april420 +aprilfool +aprilia1 +apsk0518 +apsk54321 +aptx4869 +aq123456 +aq1sw2de3 +aqswdefr +aquafina +aquafina1 +aqualung +aquamarine +aquarium +aquarius +aquarius1 +aqwleeb_6e0pk59 +aqwzsx123 +aqwzsxedc +ar123456 +arabella +arabella1 +arabella24630 +arabian1 +araceli1 +aracely1 +aradhana +aragorn1 +aram198309 +arancione +arcadia1 +arcangel +arcangel1 +arcenciel +archangel +archangel1 +archery1 +archibald +archie01 +archie12 +archie123 +archimede +archimedes +architect +architect1 +architecture +architetto +archived +archuleta +arcobaleno +arcoiris +arcticcat +arellano +aremania +arequipa +argentina +argentina1 +argentina2 +argentine +argentum +arhangel +ari-kyarova +ariana12 +ariana123 +arianna1 +arianna2 +ariel123 +arielle1 +aries123 +arina-sharapova-80 +arinayu0 +aristide +aristotle +arividerchi_shatalov +arizona1 +arizona123 +arizona2 +arjun123 +arkangel +arkansas +arkansas1 +arkoximsp +arlington +arlington1 +arlingtonp +armada-n +armadillo +armageddon +armagedon +armagedon1 +armando1 +armando123 +armando2 +armenia1 +armitage +armorgames +armstrong +armstrong1 +army1234 +armyach-aleksandra +armyman1 +armystrong +arnold123 +arquitecto +arquitectura +arrahman +arrowhead +arrowhead1 +arsch123 +arschloch +arschloch1 +arsehole +arselect +arsenal01 +arsenal07 +arsenal08 +arsenal09 +arsenal1 +arsenal10 +arsenal11 +arsenal12 +arsenal123 +arsenal13 +arsenal14 +arsenal2 +arsenal22 +arsenal23 +arsenal3 +arsenal4 +arsenal5 +arsenal7 +arsenal8 +arsenal9 +arsenalfc +arsenalfc1 +arshavin +arshavin23 +arsik-di-noxcho95 +art131313 +artem123 +artem1994 +artem1995 +artem1996 +artem1997 +artem1998 +artem1999 +artem2010 +artemblya +artemida +artemis1 +artemisa +artemisia +arthur01 +arthur12 +arthur123 +artichoke +article456 +articolo31 +articuno +artistic +artov.95 +artur123 +arturamirov89 +arturito +arunkumar +as123123 +as123456 +as123456789 +as12as12 +as12df34 +as790433 +asabsmelik5g +asadasad +asakapa123 +asas1122 +asas1212 +asasas12 +asasasas +asasasasas +asassin1997 +asawakoh +asbestos +ascension +asd123123 +asd123321 +asd12345 +asd123456 +asd1234567 +asd123456789 +asd123asd +asd123asd123 +asd123qwe +asd123zxc +asd666fds +asdasd11 +asdasd12 +asdasd123 +asdasd123123 +asdasd12313d +asdasd456 +asdasd666 +asdasdas +asdasdasd +asdasdasd1 +asdasdasd123 +asdasdasdasd +asddsa123 +asdewq123 +asdf0987 +asdf1234 +asdf12345 +asdf123456 +asdf3423 +asdf4321 +asdf:lkj +asdf;lkj +asdfasdf +asdfasdf1 +asdfasdf12 +asdfasdf123 +asdfasdf2 +asdfasdfasdf +asdffdsa +asdffdsa1 +asdfg123 +asdfg1234 +asdfg12345 +asdfg456 +asdfgasdfg +asdfgh01 +asdfgh11 +asdfgh12 +asdfgh123 +asdfgh1234 +asdfgh123456 +asdfghj1 +asdfghj12 +asdfghj123 +asdfghjk +asdfghjk1 +asdfghjk12 +asdfghjkl +asdfghjkl! +asdfghjkl. +asdfghjkl0 +asdfghjkl1 +asdfghjkl12 +asdfghjkl123 +asdfghjkl12345 +asdfghjkl2 +asdfghjkl3 +asdfghjkl4 +asdfghjkl456 +asdfghjkl5 +asdfghjkl7 +asdfghjkl9 +asdfghjkl: +asdfghjkl:': +asdfghjkl:' +asdfghjkl; +asdfghjkl;' +asdfghjkl;' +asdfghjklz +asdfghjklzxcvbnm +asdfgzxcvb +asdfjkl1 +asdfjkl123 +asdfjkl: +asdfjkl:1 +asdfjkl; +asdflkjh +asdfqwer +asdfqwer1 +asdfqwer123 +asdfqwer1234 +asdfrewq +asdfvcxz +asdfzxcv +asdfzxcv1 +asdqwe12 +asdqwe123 +asdqwezxc +asdzxc12 +asdzxc123 +asdzxcqwe +asecret1 +asemmanis +ash12345 +ashanti1 +ashish123 +ashishbiyani +ashland1 +ashlee12 +ashlee123 +ashleigh +ashleigh1 +ashley00 +ashley01 +ashley02 +ashley03 +ashley04 +ashley05 +ashley06 +ashley07 +ashley08 +ashley09 +ashley10 +ashley101 +ashley11 +ashley12 +ashley123 +ashley1234 +ashley13 +ashley14 +ashley15 +ashley16 +ashley17 +ashley18 +ashley19 +ashley20 +ashley21 +ashley22 +ashley23 +ashley24 +ashley25 +ashley26 +ashley27 +ashley28 +ashley33 +ashley69 +ashley77 +ashley85 +ashley86 +ashley87 +ashley88 +ashley89 +ashley90 +ashley91 +ashley92 +ashley93 +ashley94 +ashley95 +ashley96 +ashley97 +ashley98 +ashley99 +ashlynn1 +ashok123 +ashokkumar +ashton01 +ashton11 +ashton12 +ashton123 +ashtray1 +ashu1992 +ashutosh +asiamarketing +asian123 +asil.dovlatov.1982 +askim123 +askimaskim +askimbenim +askimsin +aslan123 +asmodeus +asparagus +aspen123 +aspirina +aspirine +aspirine1 +asroma1927 +ass12345 +ass123456 +ass1ass1 +assaassa +assasin1 +assass123 +assassass +assassin +assassin1 +assassins +assassinscreed +assclown +assclown1 +asscrack1 +assface1 +assfuck1 +assfucker +asshole! +asshole. +asshole0 +asshole01 +asshole1 +asshole10 +asshole101 +asshole11 +asshole12 +asshole123 +asshole13 +asshole14 +asshole2 +asshole21 +asshole22 +asshole23 +asshole24 +asshole3 +asshole4 +asshole420 +asshole5 +asshole6 +asshole666 +asshole69 +asshole7 +asshole8 +asshole9 +asshole99 +assholes +assholes1 +assinantes +assistant +asskicker +asskicker1 +assman69 +assmaster +assmonkey +assmonkey1 +assmunch +assmunch1 +asstastic +assumption +asswhole +asswhole1 +asswipe1 +assword1 +astalavista +astaroth +asterisk +asterix1 +asterlam +asteroid +astigako +astonmartin +astonvilla +astonvilla1 +astoria1 +astra123 +astrid29 +astro123 +astroboy +astrology +astronaut +astronomy +asturias +asuncion +asusasus +atalanta +ateneo123 +athena12 +athletic +athletics +athletics1 +athlon64 +atkinson +atlanta1 +atlanta123 +atlanta2 +atlanta3 +atlanta7 +atlantic +atlantic1 +atlantida +atlantis +atlantis1 +atlars10 +atlas123 +atletico +atljhjdf +atmosphere +atreides +attention +atticus1 +attitude +attitude1 +attorney +attorney1 +aubergine +auburn12 +auckland +auction1 +audi1991 +audiopel +audioslave +audition +audrey01 +audrey12 +audrey123 +aug!272010 +augsburg +august01 +august02 +august03 +august04 +august05 +august06 +august07 +august08 +august09 +august10 +august11 +august12 +august123 +august13 +august14 +august15 +august16 +august17 +august18 +august19 +august20 +august21 +august22 +august23 +august24 +august25 +august26 +august27 +august28 +august29 +august30 +august31 +august88 +august89 +augusta1 +augustin +augustine +augustine1 +augusto1 +augustus +augustus1 +aukewpyrt +aurelia1 +aurelie1 +aurelien +aurevoir +aurora32 +austin00 +austin01 +austin02 +austin03 +austin04 +austin05 +austin06 +austin07 +austin08 +austin09 +austin10 +austin101 +austin11 +austin12 +austin123 +austin1234 +austin13 +austin14 +austin15 +austin16 +austin17 +austin18 +austin19 +austin20 +austin21 +austin22 +austin23 +austin24 +austin25 +austin316 +austin512 +austin69 +austin88 +austin94 +austin95 +austin96 +austin97 +austin98 +austin99 +australia +australia0 +australia1 +australia2 +australie +australien +austria1 +authentic +autobahn +autobots +automatic +automobil +automobile +automotive +autumn01 +autumn08 +autumn11 +autumn12 +autumn123 +autumn13 +av8ygj1f2u +avadakedavra +available +avalanche +avalanche1 +avalon08 +avanesov +avangard +avantika +avatar12 +avatar123 +avefenix +avellino +avemaria +avenged1 +avenged7 +avenged7x +avengedsev +avengedsevenfold +avenger1 +avengers +aventura +aventura1 +aventure +avery123 +avetisyanartur +aviation +aviation1 +aviator1 +avikuzen +avkhachev78 +avm6ubdunj +avondale +avondale1 +avril123 +avrillavig +avrillavigne +avto55.rus +avvocato +awdrgyjilp +awei1616 +awesome! +awesome. +awesome1 +awesome101 +awesome11 +awesome12 +awesome123 +awesome13 +awesome2 +awesome22 +awesome3 +awesome4 +awesome5 +awesome7 +awesome8 +awesomeness +awsome12 +awsome123 +axlrose1 +ayamgoreng +aybaybay1 +aylyan2001 +ayman2008 +ayodeji1 +ayomide1 +ayomikun +aysa2423 +ayurveda +az123456 +az123456789 +az147258 +aza_93-93 +azazazaz +azazello +azbest777 +azefirov.inno1987.r +azeqsdwxc +azer1234 +azerazer +azerbaijan +azerbaycan +azert123 +azerty00 +azerty01 +azerty10 +azerty11 +azerty12 +azerty123 +azerty1234 +azerty123456 +azerty13 +azerty31 +azerty59 +azerty69 +azerty77 +azerty78 +azerty789 +azertyui +azertyuio +azertyuiop +azertyuiop1 +azertyuiop123 +azn4life +aznpride +aznpride1 +azsxdc12 +azsxdc123 +azsxdcfv +azsxdcfv1 +azsxdcfvgb +azteca13 +aztyvl_ka44ze +azulazul +azxcvbnm +b00mb00m +b0ll0cks +b1234567 +b12345678 +b123456789 +b1b2b3b4 +b1lkeb6711 +b1x7qn2tug +b2spirit +b33m6yghef +b4272327 +b43m6xhiee +b43m6xhife +b43n6whifd +b8ca6yz1nj +baba1234 +babababa +babajaga +babajide +babala123 +babalola +babamama +babatunde +babatunde1 +babbygirl1 +babe1234 +babebabe +baberuth +babi1234 +babich.e +babies123 +babigurl +babigurl1 +babiigurl1 +babilonia +babmicmar +babochka +baboshka +babouche +babubabu +babushka +baby-girl +baby1234 +baby12345 +baby123456 +baby2000 +baby2004 +baby2005 +baby2006 +baby2007 +baby2008 +baby2009 +baby2010 +baby2011 +baby_girl +baby_gurl +babyangel +babyangel1 +babybaby +babybaby1 +babybash +babybash1 +babybear +babybear1 +babybird +babyblu3 +babyblue +babyblue1 +babyblue12 +babyblue13 +babyblue2 +babyblue3 +babyblue7 +babyboi1 +babyboo! +babyboo1 +babyboo12 +babyboo123 +babyboo13 +babyboo2 +babyboo3 +babyboo7 +babyboom +babyboss +babyboy! +babyboy01 +babyboy06 +babyboy07 +babyboy08 +babyboy09 +babyboy1 +babyboy10 +babyboy11 +babyboy12 +babyboy123 +babyboy13 +babyboy14 +babyboy15 +babyboy16 +babyboy17 +babyboy18 +babyboy2 +babyboy21 +babyboy22 +babyboy23 +babyboy24 +babyboy3 +babyboy4 +babyboy5 +babyboy6 +babyboy69 +babyboy7 +babyboy8 +babyboy9 +babyboys +babycake +babycake1 +babycakes +babycakes! +babycakes1 +babycakes2 +babycakes3 +babycakes7 +babycat1 +babycute +babydaddy +babydaddy1 +babydog1 +babydoll +babydoll1 +babydoll12 +babydoll13 +babydoll2 +babydoll3 +babydoll69 +babydoll7 +babyface +babyface1 +babyface12 +babyface2 +babyfat1 +babyg123 +babyg1rl +babygirl +babygirl! +babygirl#1 +babygirl. +babygirl0 +babygirl00 +babygirl01 +babygirl02 +babygirl03 +babygirl04 +babygirl05 +babygirl06 +babygirl07 +babygirl08 +babygirl09 +babygirl1 +babygirl10 +babygirl11 +babygirl12 +babygirl123 +babygirl13 +babygirl14 +babygirl15 +babygirl16 +babygirl17 +babygirl18 +babygirl19 +babygirl2 +babygirl20 +babygirl21 +babygirl22 +babygirl23 +babygirl24 +babygirl25 +babygirl26 +babygirl27 +babygirl28 +babygirl29 +babygirl3 +babygirl30 +babygirl31 +babygirl32 +babygirl33 +babygirl34 +babygirl4 +babygirl44 +babygirl45 +babygirl5 +babygirl55 +babygirl56 +babygirl6 +babygirl69 +babygirl7 +babygirl77 +babygirl78 +babygirl8 +babygirl87 +babygirl88 +babygirl89 +babygirl9 +babygirl90 +babygirl91 +babygirl92 +babygirl93 +babygirl94 +babygirl95 +babygirl96 +babygirl97 +babygirl98 +babygirl99 +babygirls +babygirls2 +babygril +babygril1 +babygrl1 +babygurl +babygurl! +babygurl01 +babygurl06 +babygurl07 +babygurl08 +babygurl09 +babygurl1 +babygurl10 +babygurl11 +babygurl12 +babygurl13 +babygurl14 +babygurl15 +babygurl16 +babygurl17 +babygurl18 +babygurl19 +babygurl2 +babygurl20 +babygurl21 +babygurl22 +babygurl23 +babygurl24 +babygurl3 +babygurl4 +babygurl5 +babygurl6 +babygurl69 +babygurl7 +babygurl8 +babygurl9 +babyjack +babyjames +babyjane +babyjay1 +babyjoker1 +babykitty +babykitty1 +babylon1 +babylon5 +babylone +babylove +babylove1 +babylove12 +babylove2 +babylove3 +babyluv1 +babymama +babymama1 +babymomma1 +babynames +babyoneone +babypapa +babyphat +babyphat1 +babyphat12 +babyphat2 +babypink +babypink1 +babyruth +bacardi1 +bacardi151 +bacchus1 +bachelor +back2back +backbone +backdoor +backdraft +backflip +backflip1 +backlash +backoff1 +backpack +backpack1 +backsdau +backspace +backspace1 +backspace2 +backstab +backstreet +backstreetboys +backyard +backyard1 +bacon123 +bacteria +bad_boys_adience +badabing +badakhshan +badalona +badass11 +badass12 +badass123 +badass13 +badass21 +badass22 +badass23 +badass69 +badbitch +badbitch1 +badboy01 +badboy08 +badboy09 +badboy10 +badboy11 +badboy12 +badboy123 +badboy13 +badboy14 +badboy15 +badboy21 +badboy22 +badboy23 +badboy69 +badboys1 +badboys2 +badboyz1 +badcompany +baddest1 +badger123 +badgers1 +badgirl1 +badgirl12 +badgirl123 +badgirl2 +badgirls +badgurl1 +badkitty +badlands +badman123 +badminton +badminton1 +badoo.com +badoo123 +badoo2012 +badoobadoo +badromance +baerchen +baggies1 +baggins1 +baggio10 +bagheera +bagpipes +bagpuss1 +bahalana +bahamas1 +bahamut0 +bahamut1 +bahia1979 +bailarina +bailey00 +bailey01 +bailey02 +bailey03 +bailey04 +bailey05 +bailey06 +bailey07 +bailey08 +bailey09 +bailey10 +bailey11 +bailey12 +bailey123 +bailey13 +bailey14 +bailey15 +bailey16 +bailey17 +bailey21 +bailey22 +bailey23 +bailey24 +bailey33 +bailey69 +bailey77 +bailey98 +bailey99 +baili123com +bajaonel12 +bajingan +bajsbajs +bajskorv +bajskorv1 +bakabaka +bakekang +baker123 +bakugan1 +bakuman.manga.drawing +balance1 +baldeagle +balderdash +baldrick +baldwin1 +balentinra +baleri22 +balerina +balikpapan +ball4life +balla123 +balla4life +ballack13 +ballard1 +ballball +baller01 +baller03 +baller07 +baller08 +baller09 +baller10 +baller101 +baller11 +baller12 +baller123 +baller13 +baller14 +baller15 +baller16 +baller17 +baller20 +baller21 +baller22 +baller23 +baller24 +baller25 +baller32 +baller33 +baller34 +baller44 +baller45 +baller4lif +baller69 +ballerina +ballerina1 +ballers1 +ballin01 +ballin07 +ballin08 +ballin09 +ballin10 +ballin101 +ballin11 +ballin12 +ballin123 +ballin13 +ballin14 +ballin15 +ballin21 +ballin22 +ballin23 +ballin24 +ballin69 +balling1 +balloon1 +balloons +balloons1 +ballroom +balls123 +ballsack +ballsack1 +ballsdeep +balmoral +baloncesto +baltazar +balthazar +baltimore +baltimore1 +bamaboy1 +bambam01 +bambam11 +bambam12 +bambam123 +bambam13 +bambam23 +bambam69 +bambi123 +bambino1 +bambolina +bambucha +bamidele +bammargera +banan123 +banana01 +banana10 +banana11 +banana12 +banana123 +banana13 +banana14 +banana21 +banana22 +banana23 +banana33 +banana69 +banana77 +banana88 +banana99 +bananaman +bananarama +bananas! +bananas1 +bananas11 +bananas12 +bananas123 +bananas2 +bananas3 +bananas7 +banderas +bandgeek +bandgeek1 +bandicoot +bandidas747 +bandit01 +bandit07 +bandit08 +bandit10 +bandit11 +bandit12 +bandit1200 +bandit123 +bandit13 +bandit14 +bandit21 +bandit22 +bandit23 +bandit600 +bandit69 +bandit77 +bandit99 +bandito1 +bandits1 +bandung1 +bangalore +bangaram +bangbang +bangbang1 +bangkok1 +bangladesh +banjaluka +banjo123 +bankhead1 +banking1 +bannana1 +bannono8 +banshee1 +banshee350 +baphomet +baptist1 +baptiste +barabashka +baracuda +barakuda +baranova +barbados +barbados1 +barbapapa +barbara1 +barbara12 +barbara123 +barbara2 +barbarella +barbarian +barbarita +barbarossa +barber24 +barbie01 +barbie07 +barbie08 +barbie09 +barbie10 +barbie101 +barbie11 +barbie12 +barbie123 +barbie1234 +barbie13 +barbie14 +barbie15 +barbie16 +barbie17 +barbie18 +barbie21 +barbie22 +barbie23 +barbie69 +barbiedoll +barbiegirl +barborka +barca123 +barcellona +barcelon +barcelona +barcelona0 +barcelona1 +barcelona10 +barcelona123 +barcelona2 +barcelona3 +barcelona5 +barcelona7 +barcelona8 +barcelona9 +barcelone +barchetta +barclays +barefoot +barefoot1 +barfield13 +bariloche +baritone +baritone1 +barkley1 +barkov_65 +barmaley +barnabas +barnaby1 +barney01 +barney10 +barney11 +barney12 +barney123 +barney13 +barnsley +barnyard +baronessa87 +barracuda +barracuda1 +barrett1 +barrington +barrio13 +barrister +barry123 +barselona +bartbart +bartek123 +bartender +bartender1 +bartlett +bartman1 +bartolome +bartolomeo +bartsimpson +bas3ball +baseba11 +basebal1 +baseball +baseball! +baseball. +baseball0 +baseball00 +baseball01 +baseball02 +baseball03 +baseball04 +baseball05 +baseball06 +baseball07 +baseball08 +baseball09 +baseball1 +baseball10 +baseball11 +baseball12 +baseball123 +baseball13 +baseball14 +baseball15 +baseball16 +baseball17 +baseball18 +baseball19 +baseball2 +baseball20 +baseball21 +baseball22 +baseball23 +baseball24 +baseball25 +baseball26 +baseball27 +baseball28 +baseball29 +baseball3 +baseball30 +baseball31 +baseball32 +baseball33 +baseball34 +baseball35 +baseball4 +baseball42 +baseball44 +baseball45 +baseball5 +baseball55 +baseball6 +baseball69 +baseball7 +baseball77 +baseball8 +baseball88 +baseball9 +baseball99 +baseline +basement +basement1 +bashful1 +basil123 +bask3tball +basket10 +basket101 +basket11 +basket12 +basket123 +basket13 +basket23 +basketba +basketba11 +basketbal +basketbal1 +basketbal2 +basketbal9 +basketball +basketball1 +basketball10 +basketball11 +basketball12 +basketball123 +basketball13 +basketball22 +basketball23 +basketball3 +basketbol +basketcase +bass1234 +bassbass +bassboat +bassfish +bassguitar +basshunter +bassist1 +bassline +bassman1 +bassmaster +bassoon1 +bassplayer +basspro1 +bastard1 +bastardo +bastards +basti_1014 +bastian1 +bastille +batangas +batgirl1 +bathroom +bathroom1 +batista1 +batista12 +batista123 +batista2 +batista619 +batistuta +batman00 +batman007 +batman01 +batman07 +batman08 +batman09 +batman10 +batman101 +batman11 +batman12 +batman123 +batman1234 +batman13 +batman14 +batman15 +batman16 +batman17 +batman18 +batman19 +batman20 +batman21 +batman22 +batman23 +batman24 +batman25 +batman27 +batman33 +batman44 +batman45 +batman55 +batman66 +batman666 +batman69 +batman77 +batman88 +batman89 +batman99 +batteria +batterie +batteries +battery1 +battlefield +battlefield2 +battleon +battleship +battousai +baudelaire +baumhaus +bautista +bautista1 +bavixepym +baxter01 +baxter11 +baxter12 +baxter123 +bayarea1 +bayarea510 +bayern94 +bayliner +bayrafis +bayside1 +baywatch +bazooka1 +bazueva.1990 +bb123456 +bball101 +bball123 +bball4life +bballer1 +bbbbbbbb +bbbbbbbbbb +bbleo1zz +bcp201109a +bdfyeirf +bdfyjdbx +beach123 +beachbabe +beachbabe1 +beachboy +beachbum +beachbum1 +beaches1 +beanbean +beaner12 +beaner123 +beaner13 +beanhead +beans123 +bear1234 +bear2327 +bearbear +bearbear1 +bearcat1 +bearcats +bearcats1 +beardog1 +bears123 +bearshare +bearshare1 +beasley1 +beast123 +beast556 +beast666 +beastie0 +beastie1 +beastly1 +beastmode +beastmode1 +beatbox1 +beatiful +beatles1 +beatles2 +beatles4 +beatrice +beatrice1 +beatriz1 +beaubeau +beaufort +beaumont +beaumont1 +beauregard +beautifu +beautiful +beautiful! +beautiful. +beautiful0 +beautiful1 +beautiful2 +beautiful3 +beautiful4 +beautiful5 +beautiful6 +beautiful7 +beautiful8 +beautiful9 +beautifulg +beautifull +beauty01 +beauty08 +beauty101 +beauty11 +beauty12 +beauty123 +beauty21 +beaver69 +beavers1 +bebe1234 +bebebebe +because1 +becca123 +beccaboo +beckham07 +beckham1 +beckham23 +beckham7 +becky123 +bedford1 +bedrock1 +bedroom1 +beechwood +beefcake +beefcake1 +beepbeep +beepbeep1 +beerbeer +beerbeer1 +beerman1 +beerpong1 +beethoven +beethoven1 +beethoven9 +beetlejuice +behappy1 +behappy2 +behemoth +behemoth1 +beijing2008 +bela2404 +belfast1 +belgarion +belgique +belgrano +believe1 +believer +belinda1 +belinea1 +belinea85 +belinova14 +bella101 +bella123 +bella1234 +bella2007 +bella2008 +bella2009 +bella2010 +bellabella +bellaboo +bellaboo1 +belladog +belladonna +bellagio +bellamia +bellatrix +bellavista +bellavita +bellbell +belldandy +belle123 +bellevue +bellezza +bellisima +bellissima +bellissimo +bellsouth +bellsouth1 +bellydance +belmont1 +belmonte +belochka +beloved1 +beloved_a_devil +belvedere +ben12345 +ben123456 +benbenben +bendover +benedetta +benedetto +benedict +benedict1 +benedicte +benedikt +benetton +benfica1 +bengals1 +bengals85 +bengbeng +benidorm +benjam1n +benjamin +benjamin! +benjamin01 +benjamin1 +benjamin10 +benjamin11 +benjamin12 +benjamin123 +benjamin13 +benjamin15 +benjamin2 +benjamin22 +benjamin3 +benjamin4 +benjamin5 +benjamin7 +benji123 +benladen +bennett1 +bennie!! +bennington +benny123 +bennyboy +bennyboy1 +benson12 +benson123 +benten10 +bentley1 +bentley2 +beograd1 +beowulf1 +bepositive +ber217an +berbatov +berenice +berenice1 +beretta1 +bergkamp +bergkamp10 +berkeley +berkeley1 +berkley1 +berkshire +berlin12 +berlin123 +berliner +berlingo +berlusconi +bermuda1 +bermudez +bernadette +bernard1 +bernard2 +bernardino +bernardo +bernardo1 +bernhard +bernice1 +bernie01 +berries1 +berry123 +berserk1 +berserker +bertrand +besiktas +besiktas1 +besiktas1903 +best1234 +bestbest +bestbuds +bestbuy1 +bestfriend +bestfriend1 +bestfriends +besties1 +bestmom1 +bestrong +bethany1 +bethany12 +bethany123 +bethany2 +bethesda +bethoven +betrayed +betrayed1 +betsynx0kof +betterdays +bettina1 +bettina23 +bettis36 +betty123 +bettyboo +bettyboo1 +bettyboop +bettyboop1 +bettyboop2 +bettyboop3 +bettyboop7 +bettylou +between121 +beverley +beverley1 +beverly1 +beyblade +beyblade1 +beyonce1 +beyonce12 +beyonce123 +beyonce2 +beyourself +bff4ever +bff4life +bgt56yhn +bhabycoh +bhabykoh +bhabyqoh +bharat123 +bharathi +bhardwaj +bhargavi +bhbyjxrf +bhebheko +bholenath +bianca01 +bianca10 +bianca11 +bianca12 +bianca123 +bianca13 +biancaneve +biarritz +bibibibi +bible123 +biblioteca +biblioteka +bichette +bicicleta +bicicletta +bicycle1 +bidadari +bieberfeve +biedronka +bienchen +bienvenido +bienvenu +bienvenue +bigapple +bigbaby1 +bigbad#13 +bigballer +bigballer1 +bigballs +bigballs1 +bigballs2 +bigbang1 +bigbang123 +bigbass1 +bigbear1 +bigben07 +bigbird1 +bigbitch1 +bigblack +bigblack1 +bigblock +bigblue1 +bigboobs +bigboobs1 +bigbooty +bigbooty1 +bigboss1 +bigboy01 +bigboy08 +bigboy09 +bigboy10 +bigboy11 +bigboy12 +bigboy123 +bigboy13 +bigboy14 +bigboy15 +bigboy21 +bigboy22 +bigboy23 +bigboy69 +bigbrother +bigbuck1 +bigbucks +bigbucks1 +bigbutt1 +bigbutts +bigcock1 +bigcountry +bigdaddy +bigdaddy01 +bigdaddy1 +bigdaddy10 +bigdaddy11 +bigdaddy12 +bigdaddy13 +bigdaddy2 +bigdaddy23 +bigdaddy3 +bigdaddy5 +bigdaddy69 +bigdaddy7 +bigdave1 +bigdawg1 +bigdick1 +bigdick12 +bigdick123 +bigdick2 +bigdick69 +bigdick7 +bigdick9 +bigdicks +bigdog01 +bigdog10 +bigdog11 +bigdog12 +bigdog123 +bigdog13 +bigdog22 +bigdog23 +bigdog69 +bigdogg1 +bigfish1 +bigfoot1 +bigfoot2 +biggdogg +biggirl1 +biggles1 +bighead1 +bighead2 +bighouse +bigjohn1 +bigmama1 +bigmama2 +bigman12 +bigman123 +bigmike1 +bigmomma +bigmomma1 +bigmoney +bigmoney1 +bigmoney2 +bigmouth +bignasty +bignose1 +bigpapa1 +bigpapi34 +bigpenis +bigpimp1 +bigpimpin +bigpimpin1 +bigpimpin2 +bigpoppa +bigpoppa1 +bigred12 +bigred123 +bigsexy1 +bigshow1 +bigsister +bigsister1 +bigtime1 +bigtimerus +bigtits1 +bigtits2 +bigtits69 +bigtruck +bigtruck1 +bigwill1 +bigworm1 +bike4life +biker123 +bikerboy +bikerboy1 +bilabong +bilal123 +bilancia +bilgisayar +bill1234 +bill1989 +billabong +billabong1 +billabong2 +billabong7 +billbill +billgates +billgeitslox +billiards +billiejean +billiejoe +billiejoe1 +billings +billionaire +billions +billkaulit +billkaulitz +billups1 +billy123 +billy1234 +billybob +billybob1 +billybob12 +billybob2 +billyboy +billyboy1 +billygoat +billygoat1 +billyjoe +billyjoe1 +billyray +bingbing +bingbong +bingo123 +binladen +bintang1 +binweevils +biochemistry +biohazard +biohazard1 +biologia +biologie +biology1 +bionicle +bionicle1 +bioshock +biotechnology +bipolar1 +biquette +birdbird +birdcage +birddog1 +birdhouse +birdhouse1 +birdie123 +birdman1 +birmingham +birtanem +birthday +birthday1 +birthday12 +birthvillage +biscoito +biscotte +biscotto +biscuit1 +biscuit2 +biscuit22 +biscuits +biscuits1 +bisexual +bisexual1 +bismarck +bismilah +bismilla +bismillah +bismillah1 +bismillah123 +bismillah786 +bisounours +bitch100 +bitch101 +bitch111 +bitch123 +bitch1234 +bitch12345 +bitch2008 +bitch2009 +bitch2010 +bitch321 +bitch420 +bitch4life +bitch666 +bitchass +bitchass1 +bitchass12 +bitchass2 +bitchbitch +bitches! +bitches. +bitches01 +bitches1 +bitches12 +bitches123 +bitches13 +bitches2 +bitches3 +bitches4 +bitches5 +bitches69 +bitches7 +bitchez1 +bitchface +bitchface1 +bitchin1 +bitchnigga +bitchpleas +bitchplease +bitchplz1 +biteme01 +biteme11 +biteme12 +biteme123 +biteme13 +biteme22 +biteme69 +bittersweet +bkl29m2bk +bl8lygb0 +blabla12 +blabla123 +blablabla +blablabla1 +black101 +black123 +black1234 +black12345 +black666 +blackadder +blackandwhite +blackangel +blackangel09021 +blackass +blackass1 +blackbear +blackbear1 +blackbeauty +blackbelt +blackbelt1 +blackberry +blackberry1 +blackbird +blackbird1 +blackblack +blackbox +blackboy +blackboy1 +blackburn +blackburn1 +blackcat +blackcat1 +blackcat123 +blackcat13 +blackdeath +blackdevil +blackdog +blackdog1 +blackdragon +blackeye +blackfire +blackfoot +blackgirl +blackgirl1 +blackhawk +blackhawk1 +blackhawks +blackheart +blackhole +blackhole1 +blackhorse +blackice +blackice1 +blackie1 +blackie123 +blackie2 +blackjack +blackjack1 +blackjack2 +blackjack21 +blackknight +blacklab +blacklab1 +blacklabel +blacklight +blacklist +blackmagic +blackmamba +blackman +blackman1 +blackmetal +blackmoon +blackmore +blackness +blacknight +blackops +blackops1 +blackops2 +blackout +blackout1 +blackpanther +blackpearl +blackpool +blackpool1 +blackpower +blackrock +blackrose +blackrose1 +blacksabbath +blacksheep +blacksmith +blackstar +blackstar1 +blackstone +blacksun +blacktiger +blackveilb +blackwater +blackwell +blackwhite +blackwidow +blackwolf +blackwood +blacky12 +blacky123 +blade123 +bladerunner +blah1234 +blahblah +blahblah! +blahblah1 +blahblah12 +blahblah123 +blahblah2 +blahblahbl +blahblahblah +blahkg321 +blake123 +blanchard +blanche1 +blanco10 +blandine +blanket1 +blanquita +blasted1 +blaster1 +blastoff +blaze123 +blaze420 +blazedup42 +blazeit420 +blazer01 +blazer12 +blazers1 +blaziken +blbjn007 +blbyf[eq +blckd_sa_unpaidfee_oct06 +bleach12 +bleach123 +bleeding +bleeding1 +blessed! +blessed01 +blessed07 +blessed08 +blessed09 +blessed1 +blessed11 +blessed12 +blessed123 +blessed2 +blessed3 +blessed4 +blessed5 +blessed7 +blessedbe +blessing +blessing1 +blessing12 +blessing123 +blessing2 +blessings +blessings1 +blessings7 +blessme1 +blessyou +blind123 +bling123 +blingbling +blink-182 +blink123 +blink1234 +blink182 +blink183 +blinkblink +blissful +blitzkrieg +blizzard +blizzard1 +bljs2v85pt +blkdrag0ns +blockbuster +blockhead +bloger01 +blogs123 +blonde12 +blonde123 +blondie! +blondie01 +blondie1 +blondie101 +blondie11 +blondie12 +blondie123 +blondie13 +blondie2 +blondie3 +blondie69 +blondie7 +blondinka +blood101 +blood123 +blood4life +blood666 +bloodbath +bloodbath1 +bloodgang +bloodgang5 +bloodhound +bloodline +bloodline1 +bloodlust +bloodlust1 +bloodmoney +bloodrayne +bloodred +bloodyhell +bloodymary +bloomfield +blooming +blossom1 +blossoms +blowfish +blowfish1 +blowjob1 +blowjob69 +blowjobs +blowme123 +blowme69 +blubber1 +blue1234 +blue12345 +blue2000 +blue2222 +blue4ever +blueangel +blueangel1 +bluearmy +bluebaby +blueballs +blueballs1 +bluebear +bluebear1 +bluebell +bluebell1 +blueberry +blueberry1 +blueberry2 +bluebird +bluebird1 +bluebird2 +bluebirds +blueblue +blueblue1 +blueboy1 +bluecat1 +bluedevil +bluedevil1 +bluedevils +bluedog1 +bluedragon +blueeyes +blueeyes1 +blueeyes2 +bluefire +bluefish +bluefish1 +bluegill +bluegirl +bluegirl1 +bluegrass +bluegrass1 +bluegreen +bluegreen1 +bluejay1 +bluejays +bluejays1 +bluejeans +bluelight +blueline +bluem00n +blueman1 +bluemonkey +bluemoon +bluemoon1 +bluenose +bluenose1 +bluenote +blueprint +blueprint1 +bluerose +bluerose1 +blues123 +bluesclues +blueskies +bluesky1 +bluesky2 +bluesman +bluesman1 +bluestar +bluestar1 +bluetooth +bluetooth1 +bluewater +bluewater1 +blumentopf +blunt420 +blunts420 +blyad_be_90 +bmw318is +bmw325is +bmw330ci +bmwm3gtr +bmx4life +boarder1 +boarding +boating1 +boavista +bob12345 +bob123456 +bobafett +bobafett1 +bobbob12 +bobbob123 +bobbobbob +bobby101 +bobby123 +bobby1234 +bobbyboy +bobbyjack1 +bobbyjoe +bobcat12 +bobcats1 +bobdole1 +bobdylan +bobdylan1 +bobesponja +bobmarley +bobmarley1 +bobmarley2 +bobo1234 +bobobobo +bobsaget +bobsaget1 +bobsmith +bobthebuilder +bocajuniors +bocephus +bocephus1 +bodensee +bodyboard +bodyguard +bodyshop +boeing737 +boeing747 +boeing777 +bogdanova +boguska123 +bohemian +boing747 +bojangles +bojangles1 +bolabola +bolatov.almaz +bolinhas +bolivia1 +bollocks +bollocks1 +bollywood +bolno_18035 +bologna1 +bolshoj_zmej +boluwatife +bomberman +bomberos +bombers1 +bombshell +bombshell1 +bonanza1 +bonaparte +bond0007 +bondage1 +bondarenko +bonefish +bonehead +bonehead1 +bones123 +bonethug +bonethug1 +bonethugs +bonethugs1 +bongbong +bonghits +boniface +bonifacio +bonita12 +bonita123 +bonita13 +bonjour1 +bonjour123 +bonjours +bonjovi1 +bonkers1 +bonnechance +bonneville +bonnie01 +bonnie10 +bonnie11 +bonnie12 +bonnie123 +bonnie13 +boobear1 +boobies! +boobies1 +boobies12 +boobies123 +boobies2 +boobies69 +booboo01 +booboo07 +booboo08 +booboo09 +booboo10 +booboo11 +booboo12 +booboo123 +booboo1234 +booboo13 +booboo14 +booboo15 +booboo16 +booboo18 +booboo21 +booboo22 +booboo23 +booboo69 +booboo99 +booboobear +boobooboo +boobs123 +boogaloo +booger01 +booger11 +booger12 +booger123 +booger13 +booger69 +boogers1 +boogie01 +boogie12 +boogie123 +boogieman +boogieman1 +bookbook +bookitty +bookmark +bookmark1 +books123 +bookworm +bookworm1 +boomboom +boomboom1 +boomboom2 +boomer01 +boomer10 +boomer11 +boomer12 +boomer123 +boomer13 +boomer22 +boomerang +boomerang1 +boondock +boondocks +boondocks1 +booster1 +bootcamp +bootleg1 +boots123 +bootsie1 +booty123 +bootycall +bootycall1 +bootylicious +bootymeat1 +booyaka619 +borabora +borabora1 +boragud02 +borboleta +bordeaux +bordeaux33 +borderline +borec123654 +bored123 +boricua1 +boricua12 +boricua123 +boricua2 +boricua21 +boricua7 +boriqua1 +boris123 +borismf5tsh +borisova +born2die +born2kill +born2run +born2win +bornagain +bornfree +borntorun +borntowin +boromirus +borracho +borussia +borussia09 +bosco123 +boss1234 +bossbitch1 +bossboss +bosshog1 +bosshogg +bosslady +bosslady1 +bossman1 +boston01 +boston04 +boston07 +boston08 +boston10 +boston11 +boston12 +boston123 +boston13 +boston21 +boston22 +boston23 +boston24 +boston33 +boston34 +boston617 +boston69 +botafogo +botswana +bouboule +boulanger +boulder1 +boulette +boulevard +boulogne +bouncer1 +bourbon1 +boutique +bowhunter +bowhunter1 +bowling1 +bowling300 +bowwow11 +bowwow12 +bowwow123 +bowwow13 +boxer123 +boxerdog +boxing123 +boy12345 +boy123456 +boycrazy +boycrazy1 +boyfriend +boyfriend1 +boyfriend2 +boylover +boylover1 +boys2men +boyscout +boysoverfl +boyssuck +boyssuck1 +boyz2men +bqktqqn844 +bqktrqn844 +bqlk8kx79u +br00klyn +br123456 +br1ttany +braceface1 +bracelet +bracken1 +brad1234 +bradford +bradford1 +bradley01 +bradley1 +bradley11 +bradley12 +bradley123 +bradley2 +bradley3 +bradley4 +bradley5 +bradley7 +bradpitt +bradpitt1 +bradshaw +brady123 +braeden1 +braindead +brainiac +brainstorm +bramble1 +branden1 +brandi12 +brandi123 +brandie1 +brandnew +brandnew1 +brandon! +brandon. +brandon0 +brandon00 +brandon01 +brandon02 +brandon03 +brandon04 +brandon05 +brandon06 +brandon07 +brandon08 +brandon09 +brandon1 +brandon10 +brandon101 +brandon11 +brandon12 +brandon123 +brandon13 +brandon14 +brandon15 +brandon16 +brandon17 +brandon18 +brandon19 +brandon2 +brandon20 +brandon21 +brandon22 +brandon23 +brandon24 +brandon25 +brandon27 +brandon3 +brandon4 +brandon5 +brandon6 +brandon69 +brandon7 +brandon8 +brandon88 +brandon9 +brandon98 +brandon99 +brandonlee +brandy01 +brandy10 +brandy11 +brandy12 +brandy123 +brandy13 +brandy21 +brandy22 +brandy23 +brandy69 +branson1 +brasil10 +brasil12 +brasil123 +brasileiro +brasilia +brasilien +bratislava +bratwurst +bratz123 +braveheart +braves10 +braves11 +braves12 +braves25 +braves95 +bravo123 +braxton1 +brayden08 +brayden1 +brayden2 +brayden3 +braydon1 +brazil10 +brazil123 +brazilia +brazzers +bread123 +breakdance +breakdown +breakdown1 +breaker1 +breakers +breakfast +breakfast1 +breaking +breanna1 +breanna12 +breanna123 +breanna2 +breanna3 +breanne1 +breathe1 +brebre12 +brebre123 +breebree +breebree1 +breitling +brenda01 +brenda10 +brenda11 +brenda12 +brenda123 +brenda13 +brenda14 +brenda15 +brenda69 +brendan1 +brenden1 +brendon1 +brennan1 +brennen1 +brent123 +brentford +brenton1 +brentwood +brentwood1 +breonna1 +bretagne +brethart +brett123 +brewers1 +brewster +brewster1 +brian123 +brian1234 +briana12 +briana123 +brianna! +brianna01 +brianna06 +brianna07 +brianna08 +brianna09 +brianna1 +brianna10 +brianna11 +brianna12 +brianna123 +brianna13 +brianna14 +brianna2 +brianna23 +brianna3 +brianna4 +brianna5 +brianna6 +brianna7 +brianna8 +brianna9 +brianne1 +bribri12 +bribri123 +briciola +bricksquad +bridget1 +bridgett +bridgette +bridgette1 +brielle1 +brigadeiro +brighteyes +brighton +brighton1 +brigitta +brigitte +brigitte1 +brilliant +brilliant1 +brinchen23 +brindisi +bringiton +bringiton1 +brinkley +brisbane +brisbane1 +brisingr +bristol1 +britbrat1 +british1 +britney1 +britney123 +britney2 +britneys +britneyspears +britt123 +brittani +brittani1 +brittany +brittany! +brittany. +brittany01 +brittany07 +brittany08 +brittany09 +brittany1 +brittany10 +brittany11 +brittany12 +brittany13 +brittany14 +brittany15 +brittany16 +brittany17 +brittany18 +brittany19 +brittany2 +brittany20 +brittany21 +brittany22 +brittany23 +brittany3 +brittany4 +brittany5 +brittany6 +brittany69 +brittany7 +brittany8 +brittany9 +brittney +brittney1 +brittney12 +brittney2 +britton1 +brizet07 +broadband +broadband1 +broadway +broadway1 +broccoli +brodie10 +brody123 +broken12 +broken123 +broken13 +brokencyde +brokenhear +brokenheart +broncos07 +broncos1 +broncos12 +broncos2 +broncos24 +broncos7 +bronson1 +brontolo +bronx718 +bronzewing +broodwar +brook123 +brooke01 +brooke06 +brooke07 +brooke08 +brooke09 +brooke10 +brooke11 +brooke12 +brooke123 +brooke13 +brooke14 +brooke15 +brooke21 +brooke22 +brooke23 +brookie1 +brooklin +brooklyn +brooklyn! +brooklyn01 +brooklyn07 +brooklyn08 +brooklyn09 +brooklyn1 +brooklyn10 +brooklyn11 +brooklyn12 +brooklyn13 +brooklyn2 +brooklyn21 +brooklyn22 +brooklyn23 +brooklyn3 +brooklyn4 +brooklyn5 +brooklyn6 +brooklyn7 +brooklyn71 +brooklynn +brooklynn1 +brookside +broomfield +bros4life +brosb4hoes +brother1 +brother12 +brother123 +brother2 +brother3 +brother4 +brotherhood +brothers +brothers1 +brothers2 +brothers3 +brown123 +brownbear +browncow +browndog +browndog1 +browneyes +browneyes1 +browneyes2 +brownie1 +brownie12 +brownie123 +brownie2 +brownie3 +brownies +brownies1 +browning +browning1 +brownpride +brownsuga1 +brownsugar +bruce123 +brucelee +brucelee1 +brucewayne +bruins77 +bruiser1 +brunette +brunette1 +bruninha +bruninho +bruno123 +brunomars +brunswick +brunswick1 +brussels +brutus01 +brutus11 +brutus12 +brutus123 +bruxelles +bruxinha +bryan123 +bryanna1 +bryant08 +bryant24 +bryce123 +bsxxbgs322 +bubamara +bubba101 +bubba123 +bubba1234 +bubbadog +bubbagump +bubbagump1 +bubble01 +bubble11 +bubble12 +bubble123 +bubblebutt +bubblegum +bubblegum! +bubblegum1 +bubblegum2 +bubblegum3 +bubblegum5 +bubblegum7 +bubblegum9 +bubbles! +bubbles. +bubbles0 +bubbles01 +bubbles07 +bubbles08 +bubbles09 +bubbles1 +bubbles10 +bubbles101 +bubbles11 +bubbles12 +bubbles123 +bubbles13 +bubbles14 +bubbles15 +bubbles16 +bubbles17 +bubbles18 +bubbles2 +bubbles21 +bubbles22 +bubbles23 +bubbles24 +bubbles3 +bubbles4 +bubbles5 +bubbles6 +bubbles69 +bubbles7 +bubbles8 +bubbles88 +bubbles9 +bubbles99 +bubblez1 +bubby123 +bubububu +bubulina +buburuza +buccaneers +buchanan +buckaroo +buckethead +buckeye1 +buckeyes +buckeyes1 +buckfast +buckingham +buckley1 +buckmaster +buckshot +buckshot1 +buckwheat +buckwheat1 +bucuresti +budapest +budapest1 +buddies1 +buddy101 +buddy111 +buddy123 +buddy1234 +buddy12345 +buddyboy +buddyboy1 +buddycat +buddydog +buddydog1 +buddyholly +buddylee +buddylove +buddylove1 +budlight +budlight1 +budlight12 +budlight2 +budlight3 +budlight69 +budlite1 +budweiser +budweiser1 +budweiser2 +budweiser8 +budwiser +buenavista +buenosaires +buffalo1 +buffalo2 +buffalo66 +buffett1 +buffy123 +bugaboo1 +bugatti1 +bugmenot +bugsbunny +bugsbunny1 +bugsbunny2 +builder1 +building +bukowski +bul5tacumi +bulaklak +bulgakov +bulgaria +bulgaria1 +bulka-a-shah +bulldawg +bulldog1 +bulldog10 +bulldog11 +bulldog12 +bulldog123 +bulldog13 +bulldog2 +bulldog21 +bulldog22 +bulldog23 +bulldog3 +bulldog4 +bulldog5 +bulldog6 +bulldog69 +bulldog7 +bulldog8 +bulldog9 +bulldogs +bulldogs! +bulldogs08 +bulldogs09 +bulldogs1 +bulldogs10 +bulldogs11 +bulldogs12 +bulldogs13 +bulldogs2 +bulldogs3 +bulldogs5 +bulldogs7 +bulldozer +bulldozer1 +bullet12 +bullet123 +bullet13 +bullet695 +bullet83 +bulletproof +bullets1 +bullfrog +bullfrog1 +bullhead +bullrider +bullrider1 +bullseye +bullseye1 +bullsh1t +bullshit +bullshit! +bullshit1 +bullshit12 +bullshit2 +bullshit3 +bullshit69 +bullshit7 +bullwinkle +bumblebee +bumblebee1 +bumblebee2 +bumerang +bumfluff +bumhole1 +bundeswehr +bungalow +bunghole +bunghole1 +bunnies1 +bunnies2 +bunny101 +bunny123 +bunnyboo +bunnyboo1 +bunnyhop +bunnyrabbit +buongiorno +burak123 +buratino +burberry +burberry1 +burchenkovi +burgerking +burgess1 +burgundy +burlington +burning1 +burnley1 +burnout1 +burnout3 +burnside +burrito1 +bursaspor +burton12 +burton123 +burton13 +burunduk +busdriver +busdriver1 +bushido1 +bushido123 +bushido7 +business +business1 +business12 +business123 +bustamante +busted123 +buster00 +buster01 +buster02 +buster05 +buster06 +buster07 +buster08 +buster09 +buster10 +buster101 +buster11 +buster12 +buster123 +buster1234 +buster13 +buster14 +buster15 +buster16 +buster17 +buster18 +buster21 +buster22 +buster23 +buster24 +buster25 +buster33 +buster44 +buster55 +buster69 +buster77 +buster88 +buster99 +busterboy +busterbrown +busterdog +butch123 +butcher1 +butchie1 +buterfly +buterfly1 +buthead1 +buthole1 +butt3rfly +buttbutt +buttbutt1 +buttcrack1 +butter01 +butter11 +butter12 +butter123 +butter13 +butter22 +butter44 +butterball +butterbean +buttercup +buttercup! +buttercup0 +buttercup1 +buttercup2 +buttercup3 +buttercup5 +buttercup7 +buttercup9 +butterfing +butterfinger +butterfl +butterflie +butterflies +butterfly +butterfly! +butterfly. +butterfly0 +butterfly1 +butterfly12 +butterfly123 +butterfly2 +butterfly3 +butterfly4 +butterfly5 +butterfly6 +butterfly7 +butterfly8 +butterfly9 +butterflys +buttermilk +butternut +butters1 +butterscotch +buttface +buttface1 +buttfuck +buttfuck1 +butthead +butthead1 +butthead12 +butthead2 +butthole +butthole1 +butthole2 +buttmunch +buttmunch1 +buttonquail +buttons1 +buttons123 +buttons2 +buttplug +buttsex1 +buttsex69 +buzhidao +buzzard1 +buzzbuzz +bvgthfnjh +bvp33w7epu +bwfq23jp7f +byabybnb +byajhvfnbrf +byakugan +bycnbnen +bynthytn +bytheway +bytopmcd +byusdg23 +c.ronaldo +c.ronaldo7 +c0cac0la +c0l0rad0 +c0mput3r +c0mputer +c0raplok +c0urtney +c1234567 +c12345678 +c123456789 +c3por2d2 +c43qpul5rz +c44n6vijfc +c44n6vijgc +c54p7uikgb +c6djvmskcx +c7777777 +c9p5au8naa +ca123456 +caballero +caballero1 +caballo1 +caballos +cabbage1 +cabbage95 +cabbages +cabernet +cableguy +caboose1 +caboverde +cabowabo +cabrera1 +cabriolet +cabrones +caca1234 +cacaboudin +cacacaca +cacahuate +cacahuete +cacamaca +cacapipi +cacat123 +cachondo +cachorra +cachorro +cachorro1 +cadbury1 +cadence1 +cadillac +cadillac1 +caffeine +cagliari +cagnolino +caitlin1 +caitlin12 +caitlin123 +caitlin2 +caitlyn1 +calabaza +calabria +calamaro +calamity +calavera +calculator +calculus +calcutta +calderon +calderon1 +caldwell +caldwell1 +caleb123 +caledonia +calendar +calendar1 +calendario +calender +calgary1 +calhoun1 +cali1234 +cali4nia +calibra1 +caliente +caliente1 +califas1 +califas13 +california +california1 +californication +caligirl +caligirl1 +caligula +calilove1 +calimero +calimero1 +callahan +callaway +callaway1 +callie01 +callie11 +callie12 +callie123 +calliope +callista +callisto +callofduty +callofduty1 +callofduty2 +callofduty4 +callum01 +callum12 +callum123 +calogero +calvary1 +calvin01 +calvin11 +calvin12 +calvin123 +calvin23 +calypso1 +camacho1 +camaleon +camaleonte +camaro01 +camaro123 +camaro67 +camaro68 +camaro69 +camaro95 +camaro99 +camaross +camaroz28 +cambiami +cambodia +cambodia1 +cambria1 +cambridge +cambridge1 +camel123 +camel232 +cameleon +camelot1 +cameltoe +cameltoe1 +camera12 +camera123 +cameron! +cameron01 +cameron02 +cameron03 +cameron04 +cameron05 +cameron06 +cameron07 +cameron08 +cameron09 +cameron1 +cameron10 +cameron11 +cameron12 +cameron123 +cameron13 +cameron14 +cameron15 +cameron2 +cameron21 +cameron22 +cameron23 +cameron3 +cameron4 +cameron5 +cameron6 +cameron7 +cameron8 +cameron9 +cameron99 +cameroon +cameroun +camila01 +camila10 +camila12 +camila123 +camilita +camilla1 +camille1 +camille2 +camille22 +camilo123 +cammello +camomilla +campanile +campanilla +campanita +campanita1 +campbell +campbell1 +campeon1 +campeones +campinas +camping1 +campione +campioni +camprock +camprock1 +canabis1 +canada01 +canada10 +canada11 +canada12 +canada123 +canada13 +canada99 +canadian +canadian1 +canadien +canadiens +canaille +canarias +canarino +canberra +cancer12 +cancer123 +cancer13 +cancer22 +cancer69 +cancerian +candace1 +canddcard1 +candela1 +candelaria +candice1 +candice123 +candies1 +candles1 +candy101 +candy123 +candy1234 +candyapple +candyass +candybar +candybar1 +candycandy +candycane +candycane1 +candycane2 +candyfloss +candygirl +candygirl1 +candygirl2 +candygurl1 +candyland +candyland1 +candyman +candyman1 +candyshop +candyshop1 +canelita +cangrejo +cannabis +cannabis1 +cannavaro +cannelle +cannibal +cannibal1 +cannonball +cannondale +canon123 +cantante +canterbury +cantona07 +cantona1 +cantona7 +canucks1 +caonima123 +capa2008 +capecod1 +capetown +capetown1 +capitaine +capital1 +capitals +capitals11 +capitan1 +capitano +capoeira +capoeira1 +cappuccino +caprice1 +capricho +capricon +capricorn +capricorn1 +capricorn2 +capricorn7 +capricorne +capricorni +capricornio +capricorno +caprisun1 +capslock +capslock1 +captain1 +captain2 +capucine +car0line +cara4com +carabinieri +caracas1 +caracola +caracoles +caraculo +caralho1 +caramail +carambar +carambola +caramel1 +caramelito +caramella +caramelle +caramelo +caramelo1 +caravaggio +caravan1 +carbon12 +cardenas +cardenas1 +cardiff1 +cardigan +cardinal +cardinal1 +cardinals +cardinals1 +cardinals2 +cardinals5 +carebear +carebear1 +carebear12 +carebear2 +carebear3 +carebears +carebears1 +carebears2 +career121 +carefree +caregiver +careless +carhartt +caribbean +carissa1 +carla123 +carletto +carling1 +carlinha +carlinhos +carlisle +carlisle1 +carlito1 +carlitos +carlitos1 +carlo123 +carlos01 +carlos05 +carlos06 +carlos07 +carlos08 +carlos09 +carlos10 +carlos11 +carlos12 +carlos123 +carlos1234 +carlos13 +carlos14 +carlos15 +carlos16 +carlos17 +carlos18 +carlos19 +carlos20 +carlos21 +carlos22 +carlos23 +carlos24 +carlos25 +carlos26 +carlos27 +carlos28 +carlos69 +carlos88 +carlos99 +carlotta +carlotta1 +carlsberg +carlson1 +carlton1 +carly123 +carmela1 +carmelina +carmelita +carmella +carmella1 +carmelo1 +carmelo15 +carmen01 +carmen10 +carmen11 +carmen12 +carmen123 +carmen13 +carmen22 +carmen23 +carmen69 +carmencita +carmine1 +carnage1 +carnation +carnaval +carnegie +carneiro +carnell1 +carnival +carnival1 +carol123 +carolann +carolin1 +carolina +carolina. +carolina01 +carolina1 +carolina10 +carolina11 +carolina12 +carolina13 +carolina15 +carolina2 +carolina22 +carolina23 +carolina3 +carolina5 +carolina7 +caroline +caroline. +caroline1 +caroline12 +caroline2 +carollo12 +carolyn1 +carousel +carpediem +carpediem1 +carpenter +carpenter1 +carranza +carrasco +carrefour +carrera1 +carrera4 +carrie12 +carrie123 +carrillo +carrillo1 +carrington +carroll1 +carrots1 +cars1234 +carson12 +carson123 +cartagena +carter01 +carter08 +carter09 +carter10 +carter11 +carter12 +carter123 +carter13 +carter15 +carter22 +carter23 +carthage +cartman1 +cartman2 +cartoon1 +cartoon10 +cartoon123 +cartoons +cartoons1 +cartouche +carvalho +carwash1 +casa1234 +casablanca +casacasa +casamento +casandra +casandra1 +casanova +casanova1 +cascada1 +cascade1 +cascades +casey123 +caseydog +cash1234 +cashcash +cashcrate +cashflow +cashflow1 +cashmere +cashmere1 +cashmoney +cashmoney1 +cashmoney2 +cashmoney3 +cashmoney5 +casillas +casillas1 +casimiro +casino123 +casio123 +casiopea +casper01 +casper10 +casper11 +casper12 +casper123 +casper13 +casper14 +casper21 +casper22 +casper23 +casper69 +casper99 +cassandra +cassandra1 +cassandra2 +cassandre +cassanova +cassidy1 +cassidy12 +cassidy123 +cassidy2 +cassidy3 +cassie01 +cassie08 +cassie09 +cassie10 +cassie11 +cassie12 +cassie123 +cassie13 +cassie14 +cassie15 +cassie16 +cassie21 +cassie22 +cassie23 +cassie69 +cassiopea +cassiopeia +cassius1 +castaneda +castanha1 +castaway +castellano +castello +castillo +castillo1 +cat12345 +cat123456 +cat15175 +catalina +catalina1 +catalunya +catalyst +catanddog +catania46 +catarina +catarina1 +catcat12 +catcat123 +catcatcat +catcher1 +catdaddy +catdaddy1 +catdog11 +catdog12 +catdog123 +catdog13 +catdog22 +caterham7 +caterina +catering +caterpillar +catfish1 +catfish2 +catfood1 +catgirl1 +cathedral +catherin +catherine +catherine1 +catherine2 +catherine3 +cathleen +catholic +catholic1 +cathrine +cathy123 +catlover +catlover1 +catolica +catracho +catracho1 +catrina1 +catriona +cats1234 +catsanddogs +catscats +catsdogs +catsmeow +catsrule +catsrule1 +catwoman +catwoman1 +caution1 +cavalier +cavalier1 +cavaliere +cavaliers +cavaliers1 +caveman1 +cazzarola +cazzimiei +cazzo1001 +cazzoduro +cb123456 +cbr1000rr +cbr1100xx +cbr600rr +cbr900rr +cc123456 +cccccccc +cccccccccc +ccopacell1 +cd123456 +cde34rfv +cdexswzaq +cds04121989 +cdtnjxrf +cdtnkfyf +cdtnkfyrf +cdtnkzxjr +cdznjckfd +cebucity +cecelia1 +cecilia1 +ceckbrcerfkbxyjcnm2 +cegthgfhjkm +cegthvty +celebrate +celebration +celebrity +celebrity1 +celeron1 +celeste1 +celeste2 +celestial +celestial1 +celestin +celestina +celestine +celestino +celibataire +celinedion +celinesimon +cellardoor +cellphone +cellphone1 +cellphone2 +cellphone3 +cellular +cellulare +celtic01 +celtic12 +celtic123 +celtic1888 +celtic1967 +celtic67 +celtic88 +celticfc +celticfc1 +celtics1 +celtics33 +celtics34 +celtics5 +celular1 +cemetery +cenation +cendrillon +cenerentola +cenicienta +centauro +central1 +centrino +centrino1 +centurion +century1 +century21 +cepetsugih +ceramics +cerberus +cerberus1 +cerfcerf +certified +certified1 +cerulean +cervantes +cervantes1 +cerveza1 +cesar123 +cessna152 +cessna172 +cestlavie +cet333333 +cfdxtyrj +cfiekmrf +cfifcfif +cfitymrf +cfvfzkexifz +cghfibdfq +ch0c0late +ch123456 +ch_vitalij +chacha12 +chacha123 +chachacha +chaching +chachita +chad1234 +chadreed22 +chadwick +chadwick1 +chaingang +chaingang1 +chainsaw +chainsaw1 +chairman +chaitanya +chakkara +challenge +challenge1 +challenger +chalupa1 +chamber1 +chambers +chambers1 +chameleon +chamonix +champ123 +champagne +champagne1 +champion +champion1 +champion12 +champion2 +champions +champions1 +chance01 +chance10 +chance11 +chance12 +chance123 +chance13 +chance22 +chanchal +chanchan +chandana +chandigarh +chandler +chandler1 +chandler12 +chandler2 +chandra1 +chandran +chandrika +chanel05 +chanel11 +chanel12 +chanel123 +chanelbag +chanelle +chanelle1 +change08 +change09 +change12 +change123 +change1234 +changed1 +changeit +changeme +changeme1 +changeme123 +changeme2 +changepass +changes1 +channel1 +channing +channing1 +chantal1 +chantel1 +chantell +chantelle +chantelle1 +chantilly +chaochao +chaos123 +chaos666 +chaotic1 +chaparra +chaparra1 +chaparrita +chaparro +chaparro1 +chaplain +chapman1 +chapstick +chapstick1 +chapter1 +chapulin +character +character1 +characters +charchar +charcoal +charcoal1 +chardonnay +charger06 +charger1 +charger2 +charger21 +charger69 +chargers +chargers1 +chargers12 +chargers13 +chargers2 +chargers21 +charisma +charisma1 +charissa +charisse +charity1 +charizard +charizard1 +charl0tte +charlee1 +charlene +charlene1 +charles! +charles. +charles01 +charles1 +charles10 +charles11 +charles12 +charles123 +charles13 +charles2 +charles21 +charles22 +charles23 +charles3 +charles4 +charles5 +charles6 +charles69 +charles7 +charles8 +charles9 +charleston +charley1 +charlie! +charlie. +charlie0 +charlie01 +charlie02 +charlie03 +charlie04 +charlie05 +charlie06 +charlie07 +charlie08 +charlie09 +charlie1 +charlie10 +charlie101 +charlie11 +charlie12 +charlie123 +charlie13 +charlie14 +charlie15 +charlie16 +charlie17 +charlie18 +charlie19 +charlie2 +charlie20 +charlie200 +charlie21 +charlie22 +charlie23 +charlie24 +charlie25 +charlie27 +charlie3 +charlie33 +charlie4 +charlie5 +charlie6 +charlie69 +charlie7 +charlie77 +charlie8 +charlie88 +charlie9 +charlie99 +charlieb +charlieboy +charliebrown +charliedog +charlies +charline +charlize +charlote +charlott +charlotte +charlotte0 +charlotte1 +charlotte2 +charlotte3 +charlotte7 +charlotte9 +charlton +charlton1 +charly2004 +charmaine +charmaine1 +charmander +charmed! +charmed1 +charmed12 +charmed123 +charmed2 +charmed3 +charmedp3 +charmin1 +charming +charming1 +charter1 +chartered +chase123 +chasity1 +chasseur +chastity +chatchat +chatnoir +chatter1 +chatterbox +chatting +chaudhary +chauncey +chauncey1 +chaussette +chayanne +cheater! +cheater1 +cheater123 +cheater2 +cheaters +cheaters1 +cheating +cheating1 +cheburashka +check123 +checker1 +checkers +checkers1 +checking +checking1 +checkitout +checkmate +checkmate1 +cheddar1 +cheekymonkey +cheer101 +cheer123 +cheer4life +cheerbabe1 +cheerful +cheergirl1 +cheering1 +cheerio1 +cheerios +cheerios1 +cheerleade +cheerleader +cheerleadi +cheerleading +cheese01 +cheese10 +cheese101 +cheese11 +cheese12 +cheese123 +cheese1234 +cheese13 +cheese14 +cheese15 +cheese21 +cheese22 +cheese23 +cheese24 +cheese33 +cheese44 +cheese69 +cheese88 +cheese99 +cheeseball +cheeseburger +cheesecake +cheesehead +cheeseman +cheesey1 +cheetah1 +cheetah12 +cheetah2 +cheetos1 +cheezit1 +cheguevara +chelito19 +chelle1234 +chelsea! +chelsea. +chelsea01 +chelsea05 +chelsea06 +chelsea07 +chelsea08 +chelsea09 +chelsea1 +chelsea10 +chelsea11 +chelsea12 +chelsea123 +chelsea13 +chelsea14 +chelsea15 +chelsea16 +chelsea17 +chelsea18 +chelsea2 +chelsea21 +chelsea22 +chelsea23 +chelsea25 +chelsea26 +chelsea3 +chelsea4 +chelsea5 +chelsea6 +chelsea69 +chelsea7 +chelsea8 +chelsea88 +chelsea9 +chelsea99 +chelseafc +chelseafc1 +chelsey1 +chelsie1 +chemical +chemical1 +chemicals +chemistry +chemistry1 +chenchen +chenjian +chennai123 +chepalle +cherish1 +cherokee +cherokee1 +cherries +cherries1 +cherry01 +cherry07 +cherry08 +cherry09 +cherry10 +cherry101 +cherry11 +cherry12 +cherry123 +cherry1234 +cherry13 +cherry14 +cherry15 +cherry16 +cherry17 +cherry18 +cherry21 +cherry22 +cherry23 +cherry24 +cherry25 +cherry69 +cherry88 +cherrybomb +cherrycoke +cherrypie +cherrypie1 +cherrys1 +cherrytree +cheshire +chesney1 +chess123 +chessie1 +chessmaster +chester! +chester01 +chester1 +chester10 +chester11 +chester12 +chester123 +chester13 +chester2 +chester22 +chester3 +chester4 +chester5 +chester7 +chester8 +chesterfield +chestnut +chestnut1 +chevalier +chevelle +chevelle1 +chevelle69 +chevrolet +chevrolet1 +chevy123 +chevy1500 +chevy2500 +chevy350 +chevy454 +chevy4x4 +chevyman +chevyman1 +chevys10 +chevytruck +chevyz71 +chewbacca +chewbacca1 +chewy123 +cheyanne +cheyanne1 +cheyenne +cheyenne01 +cheyenne1 +cheyenne11 +cheyenne12 +cheyenne13 +cheyenne2 +cheyenne3 +cheyenne7 +chi-town +chiamaka +chiaretta +chibuike +chibuzor +chica123 +chicago01 +chicago08 +chicago1 +chicago10 +chicago11 +chicago12 +chicago123 +chicago13 +chicago2 +chicago21 +chicago22 +chicago23 +chicago3 +chicago4 +chicago5 +chicago6 +chicago7 +chicago8 +chicago9 +chicana1 +chicano1 +chicano13 +chicca39 +chicharito +chichi11 +chichi12 +chichi123 +chick123 +chickadee +chickboy +chicken! +chicken. +chicken0 +chicken01 +chicken1 +chicken10 +chicken101 +chicken11 +chicken12 +chicken123 +chicken13 +chicken14 +chicken15 +chicken2 +chicken21 +chicken22 +chicken23 +chicken24 +chicken3 +chicken4 +chicken44 +chicken5 +chicken6 +chicken69 +chicken7 +chicken8 +chicken9 +chicken99 +chickenbutt +chickens +chickens1 +chickie1 +chicklet +chico123 +chicosci +chidinma +chidori1 +chigozie +chihuahua +chihuahua1 +chijioke +chijioke123 +chikita1 +chilango +chilango1 +childcare +childofgod +children +children1 +children2 +children3 +children4 +children5 +children6 +children7 +chilidog +chillin1 +chilling +chillout +chimchim +chimera1 +china123 +chinacat +chinadoll +chinadoll1 +chinaman +chinaman1 +chinatown +chinatown1 +chinchilla +chinchin +chinchin1 +chinedu1 +chinenye +chinese1 +chingching +chingon1 +chinita1 +chino123 +chinonso +chinook1 +chinyere +chiodos1 +chipchip +chipmunk +chipmunk1 +chipmunks +chipper1 +chipper10 +chipper2 +chips123 +chipster +chiquis1 +chiquita +chiquita1 +chiquitin +chiquitita +chiquito +chiquito1 +chispita +chitarra +chitchat +chitown1 +chivas#1 +chivas01 +chivas07 +chivas09 +chivas10 +chivas100 +chivas101 +chivas11 +chivas12 +chivas123 +chivas1234 +chivas13 +chivas14 +chivas15 +chivas16 +chivas17 +chivas18 +chivas19 +chivas21 +chivas22 +chivas23 +chivas99 +chloe123 +chloedog +chobits1 +choclate +choclate1 +choco123 +chocobo1 +chococat +chocolat +chocolat1 +chocolat3 +chocolate +chocolate! +chocolate. +chocolate0 +chocolate1 +chocolate11 +chocolate12 +chocolate123 +chocolate2 +chocolate3 +chocolate4 +chocolate5 +chocolate6 +chocolate7 +chocolate8 +chocolate9 +chocolates +chois777 +chokolate +cholo123 +chomper1 +chonchon +choochoo +choochoo1 +choosen1 +chopchop +chopper1 +chopper12 +chopper123 +chopper2 +chopper3 +chopper69 +chopper7 +choppers +choppers1 +chopsuey +chosenone +chouchou +chouchou1 +choucroute +choudhary +chouette +choupette +choupinette +choupinou +chouquette +chowchow +chowchow1 +chowdary +chowder1 +chr1st1an +chris007 +chris100 +chris101 +chris111 +chris123 +chris1234 +chris12345 +chris143 +chris1988 +chris1989 +chris1990 +chris1991 +chris1993 +chris2006 +chris2007 +chris2008 +chris2009 +chris2010 +chris420 +chris4ever +chris4life +chris666 +chrisbln +chrisbrow1 +chrisbrown +chrischris +chrispaul3 +chrissie +chrissy1 +chrissy123 +chrissy2 +christ01 +christ11 +christ12 +christ123 +christ777 +christa1 +christal +christel +christelle +christen +christen1 +christi1 +christia +christiaan +christian +christian! +christian. +christian0 +christian1 +christian12 +christian123 +christian2 +christian3 +christian4 +christian5 +christian6 +christian7 +christian8 +christian9 +christiana +christiane +christiano +christie +christie1 +christin +christin1 +christina +christina! +christina0 +christina1 +christina2 +christina3 +christina4 +christina5 +christina7 +christina8 +christina9 +christine +christine! +christine0 +christine1 +christine2 +christine3 +christine5 +christine7 +christine8 +christine9 +christmas +christmas! +christmas0 +christmas1 +christmas2 +christmas3 +christmas7 +christo1 +christop +christoph +christoph1 +christoph89 +christophe +christopher +christopher1 +christos +christy1 +chronic1 +chronic2 +chronic420 +chrysler +chrysler1 +chrystal +chrystal1 +chubby123 +chucha0810 +chuck123 +chuckie1 +chuckles +chuckles1 +chucknorris +chucky12 +chucky123 +chucky13 +chukwudi +chukwuma +chula123 +chumchum +chunchun +chupacabra +chupachups +chupamela +church12 +church123 +churchill +churchill1 +chutrung +ciao1234 +ciaoatutti +ciaobella +ciaociao +ciaociao1 +ciaociaociao +ciara123 +cicamica +cicciobello +cicciolina +cicciona +ciccione +cicero1324 +ciclismo +cieloazul +cigarette +cimbom1905 +cimbombom +cincinnati +cinderela +cinderella +cinders1 +cindrella +cindy123 +cindylou +cinghiale +cingular +cingular1 +cinnamon +cinnamon1 +cinta123 +cintaku1 +cintasejat +cinthia1 +cioccolata +cioccolato +ciocolata +cipollina +cippalippa +cisco123 +cisneros +citation +citibank +citizen1 +citroen1 +citroenc4 +cityboy1 +cityhunter +civilwar +cj123456 +cjdthitycndj +cjkysirj +cjmasterinf +cjrjkjdf +cjxb2014 +ckiue73jp +cksdnd12 +claire01 +claire12 +claire123 +clairebear +clapton1 +clara123 +claremont +clarence +clarence1 +clarinet +clarinet1 +clarinette +clarinha +clarissa +clarissa1 +clarisse +clark123 +clarkkent +clarkkent1 +clarkson +class2006 +class2007 +class2008 +class2009 +class2010 +class2011 +class2012 +class2013 +classic1 +classical +classics +classified +classmate +classof05 +classof06 +classof07 +classof08 +classof09 +classof10 +classof11 +classof12 +classof13 +classof200 +classof201 +classof2010 +classof2011 +classof2012 +classof99 +classroom +claudette +claudia1 +claudia12 +claudia123 +claudia13 +claudia2 +claudia7 +claudine +claudio1 +claudita +claudius +claymore +clayton1 +clayton2 +cleaner1 +cleaning +cleaning1 +clearwater +clemence +clement1 +clemente +clemente21 +clementina +clementine +clements +clemson1 +cleocleo +cleopatra +cleopatra1 +cleopatre +clermont +cleveland +cleveland1 +cleveland2 +click123 +clifford +clifford1 +clifton1 +climber1 +climbing +clinique +clinton1 +clipper1 +clippers +clippers1 +clitoris +clochette +clock123 +clockwork +clockwork1 +clothes1 +clotilde +cloud123 +cloudstrife +clover12 +clover123 +clown123 +club2030 +clubpenguin +clueless +clueless1 +clusters +clyde123 +cm6e7aumn9 +cneltynrf +cnfybckfd +cnhfyybr +cnhjbntkm +cnhtrjpf +cnjvfnjkju +cntgfirf +cntgfyjd +cntgfyjdf +cnthdjxrf +coach123 +coaching +coastal1 +coaster1 +cobblers +cobra123 +cobra427 +coca-cola +cocacola +cocacola! +cocacola0 +cocacola1 +cocacola10 +cocacola11 +cocacola12 +cocacola123 +cocacola13 +cocacola2 +cocacola3 +cocacola7 +cocaine1 +coccinella +coccinelle +coccodrillo +cochise1 +cockroach +cocksucker +cocktail +cocktail1 +coco1234 +cocoa123 +cocobean +cocochanel +cocococo +cocodrilo +cocolino +cocoliso +cocoloco +cocoloco1 +cocomero +coconut1 +coconut12 +coconut123 +coconut2 +coconuts +coconuts1 +cocopops +cocopuff +cocopuff1 +cocopuffs +cocopuffs1 +cocorico +cod12qw75rqyi59n +codeblue +codegeass +codelyoko +codeman1 +codename +codename47 +codered1 +cody1234 +codybear +codybear1 +codyboy1 +codycody +codydog1 +coffee01 +coffee11 +coffee12 +coffee123 +coffee22 +coffee4me +coffeecup +coglione +coimbatore +coincoin +cokacola +cokecoke +cokolada +colacola +colasisi +colby123 +colchester +coldbeer +coldfire +coldplay +coldplay1 +coldwater +cole1234 +coleman1 +colette1 +colgate1 +colin123 +collect1 +collection +collector +colleen1 +college08 +college09 +college1 +college123 +college2 +collette +collin12 +collingwood +collins1 +colocolo +colocolo1 +colombia +colombia1 +colombia10 +colombia12 +colombia2 +colombiano +colonel1 +colonial +color123 +colorado +colorado1 +colorado12 +colorado2 +colorful +colorguard +colossus +colt1911 +colton12 +coltrane +coltrane1 +colts123 +columbia +columbia1 +columbus +columbus1 +comanche +comanche1 +comandante +comander +comandos +combat123654 +combat18 +comcast1 +comeback +comedian1 +comeon11 +comeon111 +comercial +comet123 +cometome +comfort1 +command1 +commander +commander1 +commando +commando1 +commandos +commerce +commerce1 +commercial +commodore +commodore1 +common123 +commons21 +commrades +communication +community +community1 +company1 +company123 +compaq01 +compaq11 +compaq12 +compaq123 +compaq13 +compaq6720 +compass1 +compassion +complete +complete1 +complex1 +complicate +complicated +composer +compound +compton1 +compton13 +compton310 +computador +computadora +computer +computer! +computer. +computer0 +computer01 +computer1 +computer10 +computer11 +computer12 +computer123 +computer13 +computer2 +computer20 +computer21 +computer22 +computer23 +computer3 +computer4 +computer5 +computer6 +computer69 +computer7 +computer8 +computer9 +computers +computers1 +comrades +conan123 +concepcion +concept1 +concerto +concetta +conchita +concord1 +concorde +concorde1 +concordia +concours +concrete +concrete1 +condition +condorito +conejita +conejito +confiance +confidence +confident +confident1 +confidential +confirm1 +confirmed +conflict +confused +confused1 +confused2 +confusion +congress +coniglio +connect1 +connect123 +connect2 +connect4 +connected +connecting +connection +connections +conner12 +conner123 +connexion +connie12 +connie123 +connolly +connor01 +connor02 +connor03 +connor04 +connor05 +connor06 +connor07 +connor08 +connor10 +connor11 +connor12 +connor123 +connor13 +connor99 +conpro73 +conquest +constance +constance1 +constance626boilard1987 +constant +constanta +constantin +constantine +constanza +construction +consuelo +consuelo1 +consultant +consulting +consumer +contact1 +contacts +contador +contender +contessa +contest1 +continental +continue +continue1 +contract +contractor +contrase +contrase+a +contrasea +contrasena +contreras +contreras1 +control1 +control2 +controle +controller +converse +converse1 +converse12 +convict1 +cookbook +cookie00 +cookie01 +cookie02 +cookie06 +cookie07 +cookie08 +cookie09 +cookie10 +cookie101 +cookie11 +cookie12 +cookie123 +cookie1234 +cookie13 +cookie14 +cookie15 +cookie16 +cookie17 +cookie18 +cookie19 +cookie20 +cookie21 +cookie22 +cookie23 +cookie24 +cookie25 +cookie33 +cookie44 +cookie45 +cookie55 +cookie69 +cookie77 +cookie88 +cookie99 +cookiemons +cookiemonster +cookies! +cookies. +cookies01 +cookies1 +cookies10 +cookies101 +cookies11 +cookies12 +cookies123 +cookies13 +cookies2 +cookies22 +cookies23 +cookies3 +cookies4 +cookies5 +cookies6 +cookies7 +cookies8 +cookies9 +cooking1 +cool1234 +cool12345 +cool123456 +coolbaby +coolbeans +coolbeans1 +coolblue +coolboy1 +coolboy123 +coolbreeze +coolbuddy +coolbuddy1 +coolcat1 +coolcat12 +coolcat123 +coolcat2 +coolcats +coolchick +coolchick1 +coolcool +coolcool1 +cooldog1 +cooldude +cooldude09 +cooldude1 +cooldude12 +cooldude2 +cooler12 +cooler123 +coolest1 +coolgirl +coolgirl1 +coolgirl12 +coolguy1 +coolguy123 +coolguy2 +coolhand +coolio12 +coolio123 +coolkid1 +coolkid12 +coolkid123 +coolkid2 +coolkids +coolkids1 +coolman1 +coolman12 +coolman123 +coolman2 +coolness +coolness1 +coolwater +coolwhip +coondog1 +cooper01 +cooper06 +cooper07 +cooper08 +cooper09 +cooper10 +cooper11 +cooper12 +cooper123 +cooper13 +cooper14 +cooper21 +cooper22 +cooper23 +cooper24 +coorslight +copacabana +copeland +copeland1 +copenhagen +copper01 +copper11 +copper12 +copper123 +copper22 +copperhead +copyright +copyright1 +coquelicot +coraline +corazon1 +corazon12 +corazon123 +corazon2 +corazoncito +corazones +cordelia +cordell1 +cordell123 +cordero1 +cordova1 +core2duo +coregmedia +corentin +corey123 +corinna1 +corinne1 +corinthian +corinthians +corleone +corleone1 +cornbread +cornbread1 +corncake21 +corndog1 +cornelia +cornelia1 +cornelio +cornelis +cornelius +cornelius1 +cornell1 +cornerstone +cornflake +cornflakes +cornhole +cornholio +cornwall +cornwall1 +corolla1 +corona12 +corona123 +corona13 +corona69 +coronado +coronado1 +corporal +corporate +corporation +corrado1 +corrine1 +corsica1 +cortland +cortney1 +corvette +corvette1 +corvette2 +corvette69 +cosanostra +cosmo123 +cosmopolitan +cosmos0901 +costantino +costanza +costarica +costarica1 +costello +cosworth +cosworth1 +cottage1 +cotton12 +cottoncand +cottoncandy +cougar12 +cougars1 +counselor +countdown +counter1 +counter123 +counterstrike +country1 +country12 +country123 +country2 +countryboy +countrygir +countrygirl +countylib +couponmom +coupons1 +couponsc10 +courage1 +courage9 +court123 +courtney +courtney! +courtney01 +courtney1 +courtney10 +courtney11 +courtney12 +courtney13 +courtney14 +courtney16 +courtney2 +courtney22 +courtney3 +courtney4 +courtney5 +courtney6 +courtney7 +courtney8 +courtney9 +couscous +cousins1 +couture1 +covenant +covenant1 +coventry +coventry1 +covergirl +cowabunga +cowboy01 +cowboy09 +cowboy10 +cowboy11 +cowboy12 +cowboy123 +cowboy13 +cowboy21 +cowboy22 +cowboy23 +cowboy24 +cowboy69 +cowboy88 +cowboys! +cowboys#1 +cowboys01 +cowboys07 +cowboys08 +cowboys09 +cowboys1 +cowboys10 +cowboys11 +cowboys12 +cowboys123 +cowboys13 +cowboys14 +cowboys2 +cowboys21 +cowboys22 +cowboys23 +cowboys24 +cowboys3 +cowboys31 +cowboys33 +cowboys4 +cowboys5 +cowboys69 +cowboys7 +cowboys8 +cowboys81 +cowboys88 +cowboys9 +cowboyup +cowboyup1 +cowboyz1 +cowgirl1 +cowgirl2 +cowgirls +cowgirlup +cowgirlup1 +cppzfrc933 +cr1st1an +crabtree +crack123 +cracker1 +cracker12 +cracker123 +cracker2 +crackerjack +crackers +crackers1 +crackhead +crackhead1 +cracovia +cradle666 +cradleoffilth +craig123 +cranberry +cranberry1 +crapper1 +crash123 +crawfish +crawfish1 +crawford +crawford1 +crawling +crayola1 +crayons1 +crazy101 +crazy111 +crazy123 +crazy1234 +crazy4life +crazy4you +crazy666 +crazyass1 +crazybitch +crazyboy +crazyboy1 +crazycat +crazychick +crazydog +crazyfrog +crazyfrog1 +crazygirl +crazygirl1 +crazygirl2 +crazygurl1 +crazyhorse +crazykid1 +crazylady +crazylady1 +crazylove +crazylove1 +crazyman +crazyman1 +crazyone +cre8tive +cream123 +creampie +creampuff +creat1ve +creatine +creation +creation1 +creations +creative +creative1 +creative12 +creative123 +creative2 +creativity +creator1 +creature +creature1 +creeper1 +creosote +crepusculo +crescent +crevette +cricket1 +cricket11 +cricket12 +cricket123 +cricket2 +cricket7 +cricketer +crickett +criminal +criminal1 +crimson1 +crip4life +crippin1 +crissangel +cristal1 +cristhian +cristian +cristian1 +cristian12 +cristiana +cristiane +cristiano +cristiano1 +cristiano7 +cristianor +cristianoronaldo +cristina +cristina1 +cristina12 +cristine +cristobal +cristofer +cristopher +cristovive +critical +critter1 +critters +crjhgbjy +crjhjcnm +crkurrp954 +croatia1 +crockett +crocodil +crocodile +crocodile1 +cromwell +cronaldo +cronaldo7 +cronic420 +croquette +crosby87 +cross123 +crossbow +crosscountry +crossfire +crossfire1 +crossover +crossroad +crossroads +crossword +crowbird +crownvic1 +cruiser1 +crunchie +crunchy1 +crusader +crusader1 +crusaders +crusaders1 +crusher1 +cruzazul +cruzazul1 +cruzazul10 +cruzeiro +crybaby1 +crystal! +crystal01 +crystal08 +crystal09 +crystal1 +crystal10 +crystal11 +crystal12 +crystal123 +crystal13 +crystal14 +crystal16 +crystal18 +crystal2 +crystal21 +crystal22 +crystal23 +crystal3 +crystal4 +crystal5 +crystal6 +crystal69 +crystal7 +crystal8 +crystal9 +crystals +crystalsaga +cs123456 +ctcnhtyrf +ctdfcnjgjkm +cthuttdbx +cthuttdf +cthuttdyf +ctvtyjdf +cualquiera +cubalibre +cubanita +cubanito +cubbies1 +cubs1908 +cubswin1 +cucaracha +cucciola +cucciolo +cucumber +cucumber1 +cuddles1 +cuddles12 +cuddles123 +cuddles2 +culiacan1 +culinary +culinary1 +culture1 +cumberland +cummings +cummins1 +cunningham +cuntface +cuntface1 +cuoricino +cupcake! +cupcake. +cupcake01 +cupcake09 +cupcake1 +cupcake10 +cupcake101 +cupcake11 +cupcake12 +cupcake123 +cupcake13 +cupcake14 +cupcake15 +cupcake2 +cupcake21 +cupcake22 +cupcake23 +cupcake24 +cupcake3 +cupcake4 +cupcake5 +cupcake6 +cupcake69 +cupcake7 +cupcake8 +cupcake9 +cupcakes +cupcakes1 +cupcakes12 +cupoftea +cuppycake1 +curious1 +curitiba +currency +current1 +curtains +curtis12 +curtis123 +custard1 +custodio +customer +customer1 +cute1234 +cuteako1 +cuteangel +cutebaby +cuteboy1 +cutecute +cutegirl +cutegirl1 +cutegurl +cuteness +cuteness1 +cuthbert +cutie101 +cutie123 +cutie1234 +cutie4life +cutiegirl +cutiepie +cutiepie! +cutiepie01 +cutiepie09 +cutiepie1 +cutiepie10 +cutiepie11 +cutiepie12 +cutiepie13 +cutiepie14 +cutiepie2 +cutiepie23 +cutiepie3 +cutiepie4 +cutiepie5 +cutiepie7 +cutiepie9 +cutlass1 +cuttiepie1 +cvbhyjdf +cvbncvbn +cvtifhbrb +cvzefh1gkc +cxfcnkbdfz +cxfcnmttcnm +cxy831126 +cxzdsaewq +cyber123 +cyberman +cybernet +cyberonline +cybershot +cyclone1 +cyclones +cyclones1 +cyclops1 +cyecvevhbr +cygnusx1 +cyjdsvujljv +cynthia1 +cynthia12 +cynthia123 +cynthia2 +cypress1 +cyrielle +cytuehjxrf +cytujdbr +cyy813zrvr +czekolada +czekolada1 +czsxumtf +czz000000 +czz123456 +czz224466 +d0023500 +d04081999 +d0r1nc0urt +d1234567 +d12345678 +d123456789 +d1bd6bc58c1d74df41a957489c9942f5 +d1d2d3d4 +d1e234tp +d1i2m3a4 +d1lakiss +d21lwz1zjs +d2itsr81jo +d2tqqn28tc +d2xyw89sxj +d41d8cd98f00 +d41d8cd98f00b204e980 +d54p7xjkha +d54q7xjmhx +d68pyfuh2v +d6ug7epz +d71lwz9zjs +d7777777 +d85lwz0zjs +d9160847880 +d9189498 +d9zufqd92n +da123456 +da1andonly +da1nonly +dabaddest1 +dabears1 +dachshund +dadadada +daddy'sgir +daddy101 +daddy123 +daddy1234 +daddycool +daddygirl +daddygirl1 +daddygirl2 +daddygurl1 +daddysboy1 +daddysgirl +daddysgurl +daddyyanke +daddyyankee +dadounet +dadsgirl +dadsgirl1 +daedalus +daewoo65 +daffodil +daffodil1 +daffodils +daffyduck +daffyduck1 +daftpunk +daftpunk1 +dagestan +dagestan05 +dagobert +dagreat1 +daili123com +dairymilk +daisuke1 +daisy101 +daisy123 +daisy1234 +daisydog +daisydog1 +daisyduke +daisyduke1 +daisygirl +daisymae +daisymae1 +daisymay +daisymay1 +dakota00 +dakota01 +dakota02 +dakota03 +dakota04 +dakota05 +dakota06 +dakota07 +dakota08 +dakota09 +dakota10 +dakota11 +dakota12 +dakota123 +dakota13 +dakota14 +dakota15 +dakota21 +dakota22 +dakota23 +dakota69 +dakota98 +dakota99 +dalailama +dalbas73 +dalejr08 +dalejr88 +dallas01 +dallas05 +dallas06 +dallas07 +dallas08 +dallas09 +dallas10 +dallas11 +dallas12 +dallas123 +dallas13 +dallas14 +dallas15 +dallas21 +dallas214 +dallas22 +dallas23 +dallas24 +dallas31 +dallas33 +dallas41 +dallas69 +dallas81 +dallas88 +dallas99 +dallascowb +dallascowboys +dallastx +dalmatian +dalmation +dalmation1 +dalton01 +dalton12 +dalton123 +damaris1 +damascus +damian01 +damian11 +damian12 +damian123 +damian13 +damian666 +damien12 +damien123 +damien666 +damilare +damilola +damilola1 +damira.shagabutdinova +damon123 +dan12345 +dan1elle +dan_cheb +dana1234 +danadana +dance101 +dance123 +dance4ever +dance4life +dance4me +dance5678 +dancedance +dancehall +dancer01 +dancer07 +dancer08 +dancer09 +dancer10 +dancer101 +dancer11 +dancer12 +dancer123 +dancer13 +dancer14 +dancer15 +dancer16 +dancer17 +dancer18 +dancer21 +dancer22 +dancer23 +dancer24 +dancer87 +dancer88 +dancers1 +dancing1 +dancing123 +dancing2 +dancingqueen +dandan123 +dandandan +dandelion +danecook1 +danger12 +danger123 +dangermouse +dangerous +dangerous1 +dangerous12 +dani1234 +danidani +daniel00 +daniel007 +daniel01 +daniel02 +daniel03 +daniel04 +daniel05 +daniel06 +daniel07 +daniel08 +daniel09 +daniel10 +daniel101 +daniel11 +daniel12 +daniel123 +daniel1234 +daniel13 +daniel14 +daniel15 +daniel16 +daniel17 +daniel18 +daniel19 +daniel1994 +daniel20 +daniel2000 +daniel2007 +daniel2008 +daniel2009 +daniel2010 +daniel21 +daniel22 +daniel23 +daniel24 +daniel25 +daniel26 +daniel27 +daniel28 +daniel29 +daniel30 +daniel31 +daniel33 +daniel55 +daniel69 +daniel77 +daniel82 +daniel83 +daniel84 +daniel85 +daniel86 +daniel87 +daniel88 +daniel89 +daniel90 +daniel91 +daniel92 +daniel93 +daniel94 +daniel95 +daniel96 +daniel97 +daniel98 +daniel99 +daniela. +daniela1 +daniela10 +daniela12 +daniela123 +daniela13 +daniela2 +daniele1 +danielita +danielito +danielito1 +daniella +daniella1 +danielle +danielle! +danielle. +danielle01 +danielle07 +danielle08 +danielle09 +danielle1 +danielle10 +danielle11 +danielle12 +danielle123 +danielle13 +danielle14 +danielle15 +danielle16 +danielle17 +danielle18 +danielle19 +danielle2 +danielle20 +danielle21 +danielle22 +danielle23 +danielle3 +danielle4 +danielle5 +danielle6 +danielle69 +danielle7 +danielle8 +danielle9 +daniels1 +danijela +danil123 +danilova +dannielle +danny101 +danny123 +danny1234 +dannyboy +dannyboy1 +dante123 +dante666 +dantheman +dantheman1 +danville +danyelle +danzig666 +dardevilk +daredevil +daredevil1 +darius12 +darius123 +darjeeling +dark1234 +darkangel +darkangel1 +darkangel2 +darkangel6 +darkblue +darkdark +darkdevil +darkdragon +darkfire +darkhorse +darkknight +darklight +darklight1 +darklord +darklord1 +darkman1 +darkmanx +darkmaster +darkmoon +darkn3ss +darkness +darkness! +darkness0 +darkness1 +darkness11 +darkness12 +darkness13 +darkness2 +darkness3 +darkness5 +darkness6 +darkness66 +darkness7 +darknight +darknight1 +darkone1 +darkorbit +darkshadow +darkside +darkside1 +darksoul +darkstar +darkstar1 +darkwing +darkwolf +darlene1 +darling1 +darling123 +darlington +darnell1 +darrell1 +darren12 +darren123 +darrius1 +darshana +dartagnan +darthmaul +darthvader +dartmouth +dasdasdas +dasha123 +dasha1996 +dasha1998 +dasha2010 +dashadasha +dashawn1 +dashboard +dashboard1 +dashenka +database +datnigga1 +daughter +daughter1 +daughter2 +daughters +daughters2 +daughters3 +dauphine +dauphins +dave1234 +davedave +davenport +davenport1 +david007 +david101 +david111 +david123 +david1234 +david12345 +david2000 +david2006 +david2007 +david2008 +david2009 +david2010 +david666 +david777 +davidbeckham +davidbowie +daviddavid +davidic1 +davidlee +davidoff +davidson +davidson1 +davidstrokov +davidvilla +davinchi +davinci1 +davis123 +dawid123 +dawidek1 +dawkins20 +dayanara +daybreak +daycare1 +dayday12 +dayday123 +daydream +daydream1 +daydreamer +daylight +daylight1 +daytona1 +daytona500 +daywalker +dbjktnnf +dbnzyxbr +dbrfdbrf +dbrnjhbz +dbrnjhjdbx +dbrnjhjdyf +dbyjuhfl +dc123456 +dcba4321 +dcltabih01 +dcshoes1 +dctdjkjl +dctktyyfz +dctvghbdtn +dd123456 +dddddddd +ddddddddd +dddddddddd +ddzj39cb3 +ddzj49nb3 +deaddead +deadfish +deadhead +deadhead1 +deadline +deadlock +deadman1 +deadman2 +deadman8 +deadmau5 +deadmeat +deadpool +deadpool1 +deadspace +deadwood +deandre1 +deangelo +deangelo1 +deanna12 +dearbook +deardear +dearmama +death101 +death123 +death2all +death666 +deathangel +deathcore +deathmetal +deathnote +deathnote1 +deathnote2 +deathrow +deathrow1 +deathstar +deathstar1 +deathtoall +deathwish +deathwish1 +debbie01 +debbie12 +debbie123 +debbie69 +deborah1 +debtfree +decatur1 +december +december01 +december05 +december06 +december07 +december08 +december09 +december1 +december10 +december11 +december12 +december13 +december14 +december15 +december16 +december17 +december18 +december19 +december2 +december20 +december21 +december22 +december23 +december24 +december25 +december26 +december27 +december28 +december29 +december3 +december30 +december31 +december4 +december5 +december6 +december7 +december8 +december9 +decembre +decembrie +deception +dedamiwa +dededede +dedewang +dedicated +dedication +dedmoroz +deedee11 +deedee12 +deedee123 +deedee13 +deedeedee1 +deepak123 +deepblue +deepfrequency +deeppurple +deepspace9 +deerhunt +deerhunt1 +deerhunter +deerpark +deerpark1 +deerslayer +deeter_1 +deeznuts +deeznuts1 +deeznutz +deeznutz1 +default05 +default1 +default_password +defender +defender1 +defender101 +defense1 +defiance +defiant1 +defleppard +deftones +deftones1 +degrassi +degrassi1 +deguzman +dehradun +dei3mutter +deicide666 +deinemudda +deinemutter +delacruz +delacruz1 +delaney1 +delarosa +delatorre +delaware +delaware1 +delbert1 +delete123 +deleted1 +delfines +delgado1 +delhi123 +delicious +delicious1 +delight1 +delilah1 +delirium +delirium9111 +delivered +delivery +dell1234 +delldell +delldell1 +deloitte +delorean +delores1 +delosreyes +delphine +delphine1 +delpiero +delpiero10 +delrosario +delta123 +deltaforce +delvalle +demarcus +demarcus1 +demarrer +demented +dementia +dementor +demetria +demetrio +demetrius +demetrius1 +demilovato +democrat +demolition +demon123 +demon1234 +demon12345 +demon1q2w3e +demon1q2w3e4r +demon1q2w3e4r5t +demon666 +demonhunter +demonic1 +dempsey1 +den221991 +denilson +denis123 +denis1991 +denis1992 +denis1994 +denis1995 +denis1996 +denis1997 +denis1998 +denis_nazarenko +denisdenis +denise01 +denise07 +denise08 +denise09 +denise10 +denise11 +denise12 +denise123 +denise13 +denise14 +denise15 +denise18 +denise21 +denise22 +denise23 +denise69 +denisse1 +denmark1 +dennis01 +dennis10 +dennis11 +dennis12 +dennis123 +dennis13 +dennis22 +dennis23 +denpasar +dentist1 +dentista +denver07 +denver12 +denver123 +denver15 +denver303 +denya2531914 +depeche1 +depeche101 +depechemode +deportivo +depressed +depressed1 +depression +derbeder +derector-85 +derek123 +derekjeter +derfderf +derp12!@ +derparol +derrick1 +derrick12 +derrick123 +derrick2 +desadesa +descartes +desdemona +desember +desertrose +deshaun1 +deshawn1 +desiderata +desiderio +design123 +designdeal +designer +designer1 +desirae1 +desiree1 +desiree12 +desiree123 +desiree2 +deskjet1 +desktop1 +desmond1 +desmond123 +desperado +desperado1 +desperados +desperate +destination +destinee +destinee1 +destiney +destiney1 +destini1 +destiny! +destiny. +destiny01 +destiny02 +destiny04 +destiny05 +destiny06 +destiny07 +destiny08 +destiny09 +destiny1 +destiny10 +destiny11 +destiny12 +destiny123 +destiny13 +destiny14 +destiny15 +destiny2 +destiny21 +destiny22 +destiny23 +destiny3 +destiny4 +destiny5 +destiny6 +destiny69 +destiny7 +destiny8 +destiny9 +destiny99 +destroy1 +destroyer +destroyer1 +destruction +detective +detective1 +determination +determined +dethklok +dethklok1 +detroit1 +detroit12 +detroit2 +detroit3 +detroit313 +detroit7 +deuseamor +deusefiel +deutsch1 +deutschlan +deutschland +devante1 +devastator +developer +development +devendra +devil123 +devil666 +devilboy +devildog +devildog1 +devildriver +devilish +devilish1 +deviljin +devilman +devilman1 +devilmaycr +devilmaycry +devilmaycry4 +devin123 +devious1 +devochka +devon123 +devonte1 +devotion +dewayne1 +dexter01 +dexter10 +dexter11 +dexter12 +dexter123 +dexter13 +dexter21 +dexter22 +deyanira +dezember +dezembro +dfa72dfj +dfaeff34232 +dfasnewa +dfcbkbcf +dfcbkmtd +dfcbkmtdf +dfczcghjcbnm +dfczdfcz +dfg5fhg5vgfh1 +dfgdfgdfg +dfkmrbhbz +dfktynby +dfktynbyf +dfktynbyrf +dg123456 +dgkallday +dgkallday1 +dgonni86 +dhananjay +dhjnvytyjub +diabetes +diabetes1 +diablo01 +diablo11 +diablo12 +diablo123 +diablo13 +diablo22 +diablo666 +diablo69 +diabolik +diabolika +diamante +diamante1 +diamond! +diamond. +diamond01 +diamond06 +diamond07 +diamond08 +diamond09 +diamond1 +diamond10 +diamond11 +diamond12 +diamond123 +diamond13 +diamond14 +diamond15 +diamond16 +diamond17 +diamond18 +diamond2 +diamond21 +diamond22 +diamond23 +diamond24 +diamond3 +diamond4 +diamond5 +diamond6 +diamond69 +diamond7 +diamond8 +diamond9 +diamonds +diamonds1 +diamonds12 +diamonds2 +diana123 +diana1998 +dianadiana +diane123 +dianita1 +diank123 +dianochka +dianochka1924 +dicembre +diciembre +diciembre1 +diciembre2 +dick1234 +dickdick +dickens1 +dickface +dickface1 +dickhead +dickhead1 +dickhead12 +dickhead2 +dickhead69 +dickies1 +dickinson +dicksucker +dickweed +dickweed1 +dictionary +diddlina +didididi +diebitch1 +diediedie +diego123 +dieguito +diehard1 +diesel01 +diesel11 +diesel12 +diesel123 +diesel69 +dietcoke +dietcoke1 +dietpepsi +dietpepsi1 +dietrich +dieumerci +different +different1 +difficult +digger12 +digimon1 +digimon123 +digital1 +digital123 +dikoalam +dilbert1 +dilligaf +dilligaf1 +dillinger +dillion1 +dillon01 +dillon11 +dillon12 +dillon123 +dima1234 +dima12345 +dima1984 +dima1986 +dima1987 +dima1988 +dima1989 +dima1990 +dima1991 +dima1992 +dima199219921 +dima1993 +dima1994 +dima1995 +dima1996 +dima1997 +dima1998 +dima1999 +dima2000 +dima2002 +dima2009 +dima2010 +dima35360 +dimabilan +dimadima +dimafilippov +dimanche +dimapet09 +dimaraja +dimas34rus +dimastic +dimebag1 +dimension +dimension1 +dimepiece1 +dimitr692010 +dimitri1 +dimitris +dimlimonov +dimmuborgir +dimochka +dimok091 +dimples1 +dimples2 +dimulya.vasilenko +dinadina +dinamita +dinesh123 +dingbat1 +dingding +dingdong +dingdong1 +dingo123 +dinheiro +dinmamma +dinmamma1 +dino1234 +dinodino +dinosaur +dinosaur1 +dinosaurio +dinosaurs +dinosaurus +dinozavr +diogenes +diogo123 +dionisio +diosesamor +diosesfiel +diosmeama +diosteama +diosteamo +diplomat +diplomat1 +diplomats1 +dipset12 +dipset123 +dipset23 +dipshit1 +dipstick +dipstick1 +direction +director +director1 +direktor +direngrey +dirtbag1 +dirtbike +dirtbike1 +dirtbike12 +dirtbike2 +dirtbike7 +dirtbiker1 +dirtbikes +dirtbikes1 +dirty123 +dirtydog +dirtysouth +disaster +disaster1 +disciple +disciple1 +discipline +disco123 +discount +discover +discover1 +discovery +discovery1 +discreet +disney01 +disney07 +disney08 +disney10 +disney11 +disney12 +disney123 +disney13 +disney22 +disney365 +disney411 +disneyland +disorder +dispatch +dispatch1 +distance +disturbed +disturbed1 +disturbed2 +diva1234 +diva4life +divadiva +divagirl +divagirl1 +diversion +diversity +divinity +division +division1 +divorce1 +divorce2 +divorced +divorced1 +diwtgm8492 +dixie123 +dixiedog +dixiedog1 +dizzy123 +dj123456 +djdjfedor +djedenhit +djhjyf010 +djibouti +djkrjlfd +djkujuhfl +djmaikl86 +djon.net +djtiesto +dkair8dda +dkflbckfd +dkflbckfdf +dkflbdjcnjr +dkflbvbh +dkflbvbhjdbx +dkflbvbhjdyf +dkssud12 +dkxjizc282 +dlfaor09 +dlnvhvu492 +dmedcn23sd +dmitriev +dmitrii-skargo +dmitrij.mironov2014 +dmsgk0103 +dnina666 +doberman +doberman1 +dobermann +docrafts +doctor12 +doctor123 +doctorwho +doctorwho1 +document +dodge123 +dodge1500 +dodge2500 +dodgeram +dodgeram1 +dodgers1 +dodgers11 +dodgers12 +dodgers123 +dodgers13 +dodgers2 +dodgers3 +dodgers5 +dodgers99 +dodgeviper +dodododo +dog12345 +dog123456 +dog4life +dogbone1 +dogbreath +dogbreath1 +dogdogdog +dogeatdog +dogface1 +dogfight +dogfood1 +doggie12 +doggie123 +doggies1 +doggies2 +doggy123 +doggydog +doggydog1 +doggystyle +doghouse +doghouse1 +doglover +doglover1 +dogpound +dogpound1 +dogs1234 +dogshit1 +dogsrule +dogsrule1 +dogtown1 +dogwood1 +dok74rus +dolcevita +dolemite +dolgushina.76 +dollar123 +dollarbill +dollarking5 +dollars1 +dollbaby +dollface +dollface1 +dollhouse +dolly123 +dolores1 +dolphin! +dolphin01 +dolphin1 +dolphin10 +dolphin11 +dolphin12 +dolphin123 +dolphin13 +dolphin2 +dolphin21 +dolphin22 +dolphin23 +dolphin3 +dolphin4 +dolphin5 +dolphin6 +dolphin69 +dolphin7 +dolphin8 +dolphin9 +dolphine +dolphins +dolphins! +dolphins1 +dolphins12 +dolphins13 +dolphins2 +dolphins3 +dolphins7 +domain123 +domenica +domenico +dominate +domination +dominator +dominator1 +domingo1 +domingos +dominguez +dominguez1 +dominic1 +dominic12 +dominic123 +dominic2 +dominic3 +dominic5 +dominic7 +dominica +dominican +dominican1 +dominican2 +dominicana +dominicano +dominick +dominick1 +dominik1 +dominik123 +dominika +dominika1 +dominion +dominion1 +dominique +dominique1 +dominique2 +domino11 +domino12 +domino123 +dominos1 +don12345 +donald01 +donald12 +donald123 +donald356 +donaldduck +donatella +donatello +donavan1 +donbosco +doncaster +dongdong +donjuan1 +donkey11 +donkey12 +donkey123 +donkey69 +donkeykong +donna123 +donnell1 +donnelly +donomar1 +donotenter +donovan1 +donskihv +donsun123 +dont4get +dontcare +dontcare1 +dontforget +donthate +donthate1 +dontknow +dontknow1 +donttouch +dontworry +donvito1 +doodle12 +doodle123 +doodlebug +doodlebug1 +doodles1 +dookenr1 +doolittle +doomdoom +doomsayer.2.7mords.v +doomsayer.2.7mords.vv +doomsday +doomsday1 +doorbell +doorknob +doorknob1 +dopeboy1 +dopeman1 +doradora +doraemon +doraemon1 +doremi123 +doremifa +doris123 +doritos1 +dorothea +dorothee +dorothy1 +dorothy2 +dortmund +dortmund09 +dortmund1 +dossantos +dothedew +dothedew1 +double07 +doubled1 +douchebag +douchebag1 +doudoune +doughboy +doughboy1 +doughnut +doughnut1 +douglas1 +douglas12 +douglas123 +douglas2 +douglass +dovbeshkosushova.1972 +dowitcher +down4life +downhill +downhill1 +download +download1 +downloads +downtown +downtown1 +downunder +dozer123 +dpbk1234 +dpetrucco2 +dr.karaul +dr.pepper +dr0wssap +draconis +dracula1 +dragon00 +dragon007 +dragon01 +dragon02 +dragon05 +dragon06 +dragon07 +dragon08 +dragon09 +dragon10 +dragon100 +dragon101 +dragon11 +dragon12 +dragon123 +dragon1234 +dragon13 +dragon14 +dragon15 +dragon16 +dragon17 +dragon18 +dragon19 +dragon20 +dragon2000 +dragon21 +dragon22 +dragon23 +dragon24 +dragon25 +dragon26 +dragon27 +dragon28 +dragon30 +dragon31 +dragon32 +dragon33 +dragon34 +dragon42 +dragon420 +dragon44 +dragon45 +dragon52 +dragon55 +dragon56 +dragon64 +dragon66 +dragon666 +dragon67 +dragon69 +dragon75 +dragon76 +dragon77 +dragon777 +dragon78 +dragon79 +dragon81 +dragon82 +dragon83 +dragon84 +dragon85 +dragon86 +dragon87 +dragon88 +dragon89 +dragon90 +dragon91 +dragon92 +dragon93 +dragon94 +dragon95 +dragon96 +dragon97 +dragon98 +dragon99 +dragonage +dragonbal1 +dragonball +dragonball1 +dragonballgt +dragonballz +dragonballz1 +dragones +dragonfable +dragonfire +dragonfly +dragonfly1 +dragonfly2 +dragonfly3 +dragonfly7 +dragonforce +dragonheart +dragonite +dragonking +dragonlady +dragonlance +dragonlord +dragonman +dragonmaster +dragons1 +dragons11 +dragons12 +dragons123 +dragons13 +dragons2 +dragons3 +dragons5 +dragons7 +dragonslayer +dragoon1 +dragoste +dragoste123 +dragrace +dragstar +dragster +dragster1 +drake123 +drama101 +drama123 +dramaqueen +drandreb +dream123 +dreambig +dreambig1 +dreamboy +dreamcast +dreamcast1 +dreamcatcher +dreamer1 +dreamer12 +dreamer123 +dreamer13 +dreamer2 +dreamer3 +dreamer7 +dreamer8 +dreamers +dreamgirl +dreamgirl1 +dreaming +dreaming1 +dreamland +dreamon1 +dreams12 +dreams123 +dreamteam +dreamteam1 +dreamtheater +dreamweaver +dreamworld +dresden1 +dressage +drew1234 +drewdrew +drifter1 +drifting +driftking +driftking1 +driftwood +drilling +drink7up +drinking +drinking1 +drjynfrnt +drm199019902323 +drogba11 +dropdead +dropdead1 +dropkick +drowssap +drowssap1 +drowssap12 +drowssap2 +drozdovaksusha +drpepper +drpepper1 +drpepper12 +drpepper2 +drpepper23 +drpepper3 +drpepper7 +drugfree +drumandbass +drumline +drumline1 +drummer1 +drummer12 +drummer123 +drummer2 +drummer3 +drummer7 +drummerboy +drummers +drumming +drummond +drumnbass +drumnbass1 +drums123 +drumset1 +drumstick +drywall1 +ds123456 +dsadsadsa +dsk4r9bskh +dsmvssq955 +dsmwssr955 +dt123456 +dthjybrf +dthjybxrf +dthyjcnm +dtkjcbgtl +dtown214 +dtxyjcnm +dubai123 +dublin16 +dublin22 +ducati1098 +ducati748 +ducati916 +ducati996 +ducati999 +duchess1 +duchesse +duckduck +duckduck1 +duckhunter +duckies1 +duckling +duckman1 +ducky123 +dud_1995 +dude1234 +dudedude +dudedude1 +dudeman1 +duffbeer +duisburg +duke1234 +dukedog1 +dukeduke +dukenukem +dukester +dulce123 +dulcemaria +dulcinea +dumbass! +dumbass1 +dumbass123 +dumbass2 +dumbbitch +dumbbitch1 +dumbdumb +dumbfuck1 +dumbledore +dumbshit1 +dummy123 +dumnezeu +dumpling +dumpster +duncan12 +duncan123 +duncan21 +dune2000 +dungeon1 +dupa1234 +dupablada +dupadupa +dupadupa1 +dupeczka +dupont24 +duracell +duranduran +durango1 +durant35 +duskolyan +dustin01 +dustin11 +dustin12 +dustin123 +dustin13 +dustin14 +dustin23 +dustin69 +dusty123 +dustydog +dustydog1 +dutches1 +dutchess +dutchess1 +dutchman +duval904 +dylan123 +dylandog +dymkovpavel +dynamic1 +dynamite +dynamite1 +dynasty1 +dynomite +dzxtckfd +e-eremeeva1976 +e.ovcharova +e10adc3949ba59abbe56 +e1234567 +e12345678 +e123456789 +e2yfp41b +e3r4t5y6 +e5fhxkqibw +e65r82kni2 +e65r82mnj2 +e65r82mpj2 +e6pz84qfcj +e7yvsskj +e8szn4e5zc +e_dovich +eagle123 +eagleeye +eagleone +eagles01 +eagles05 +eagles06 +eagles07 +eagles08 +eagles09 +eagles10 +eagles11 +eagles12 +eagles123 +eagles13 +eagles14 +eagles15 +eagles20 +eagles21 +eagles22 +eagles23 +eagles24 +eagles25 +eagles33 +eagles36 +eagles69 +eagles81 +eagles99 +eanovozhilov +earnhardt +earnhardt3 +earnhardt8 +earth123 +earthquake +east1999 +eastcoast +eastcoast1 +eastenders +eastern1 +eastside +eastside02 +eastside1 +eastside12 +eastside13 +eastside14 +eastside2 +eastside21 +eastside23 +eastside3 +eastside4 +eastside5 +eastside6 +eastwest +eastwood +eastwood1 +easy1234 +easyas123 +easyeasy +easymoney +easyrider +easyspiro +easytocrack1 +eatadick +eatme123 +eatmenow +eatmyshorts +eatpussy +eatpussy1 +eatpussy69 +eatshit! +eatshit1 +eatshit2 +eatshit69 +ebenezer +ebony123 +ecapsym1 +ecaterina +echizen18 +echoecho +eclipse1 +eclipse2 +eclipse3 +eclipse7 +eclipse99 +economia +economic +economics +economist +ecuador1 +ecureuil +ed123456 +edalwin12 +eddie123 +edelweiss +edgar123 +edgardo1 +edgewood +edhardy1 +edinburgh +edinburgh1 +ediz27v1kq +edmonton +edmonton1 +eduardito +eduardo1 +eduardo10 +eduardo12 +eduardo123 +eduardo13 +eduardo2 +education +education1 +edward01 +edward08 +edward09 +edward10 +edward101 +edward11 +edward12 +edward123 +edward1234 +edward13 +edward14 +edward15 +edward16 +edward17 +edward18 +edward1901 +edward21 +edward22 +edward23 +edward24 +edward25 +edward69 +edwardcull +edwardcullen +edwards1 +edwards99 +edwin123 +edxk20qmfs +ee19920528 +eeeeeeee +eeeeeeeeee +eeyore12 +eeyore123 +efimkin_igor +efnesonline +egghead1 +eggplant +eggplant1 +eggroll1 +egor.vasilin +egorov_maxim +egyptian +eh1k9oh335 +ehdgnl12 +ehlb3c18tw +eiffel65 +eight888 +eightball +eightball1 +eightball8 +eighteen +eighteen18 +eiknon11 +eindhoven +einstein +einstein1 +eintracht +eitaeita +ekaterina +ekx1x3k9bs +el1zabeth +elaine01 +elaine12 +elaine123 +elbereth +elcamino +elcamino1 +elcubano1893a +eldiablo +eldorado +eldorado1 +eleanor1 +electra1 +electric +electric1 +electrical +electrician +electro1 +electron +electronic +electronica +electronics +elefant1 +elefante +elefante1 +elegance +elektra1 +elektrik +elektro73 +element! +element. +element0 +element1 +element11 +element12 +element123 +element13 +element14 +element2 +element3 +element4 +element5 +element6 +element69 +element7 +element8 +element9 +elemental +elemental1 +elementary +elements +elements1 +elena123 +elena2010 +elenaelena +elenanesterova +elenberg +elensobko +elenst14 +eleonora +eleonore +elephant +elephant! +elephant1 +elephant11 +elephant12 +elephant123 +elephant2 +elephant3 +elephant5 +elephant7 +elephants +elephants1 +elevation +elevator +eleven11 +elfenlied +elfriede +elias123 +elie3173 +elijah01 +elijah03 +elijah04 +elijah05 +elijah06 +elijah07 +elijah08 +elijah09 +elijah10 +elijah11 +elijah12 +elijah123 +elijah13 +elijah23 +elisa123 +elisabet +elisabeth +elisabeth1 +elisabetta +elise123 +elite123 +eliza123 +elizabet +elizabeth +elizabeth! +elizabeth. +elizabeth0 +elizabeth1 +elizabeth12 +elizabeth123 +elizabeth2 +elizabeth3 +elizabeth4 +elizabeth5 +elizabeth6 +elizabeth7 +elizabeth8 +elizabeth9 +elizaveta +ellabella +ellabella1 +ellarose +ellehcim +ellen123 +ellie123 +elliemae +elliemae1 +elliemay +elliott1 +ellipsis +elmatador +elmejor1 +elmo1234 +elmoelmo +elnegro1 +elnumero1 +elsalvador +elshadai +elshaddai +eltonjohn +elvira198927 +elvis123 +elvis1977 +elvislives +elvispresley +elynca96 +elzbieta +emachine +emachine1 +emachines +emachines1 +emachines2 +email123 +emailonly +emanuel1 +emanuela +emanuele +embassy1 +emerald1 +emerald7 +emeralds +emeraude +emergency +emergency1 +emerica1 +emerica2 +emerson1 +emiliana +emiliano +emiliano1 +emily101 +emily123 +emily1234 +emily2005 +emilyann +emilyrose +eminem01 +eminem10 +eminem11 +eminem12 +eminem123 +eminem1234 +eminem13 +eminem14 +eminem15 +eminem17 +eminem21 +eminem22 +eminem23 +eminem313 +eminem69 +eminem88 +eminemd12 +emirates +emma1234 +emma2000 +emma2003 +emma2004 +emma2005 +emma2006 +emma2007 +emma2008 +emma2009 +emma2010 +emmaemma +emmagrace +emmagrace1 +emmajane +emmajean +emmalee1 +emmalou1 +emmalouise +emmanuel +emmanuel1 +emmanuel12 +emmanuel123 +emmanuel2 +emmanuel7 +emmanuella +emmanuelle +emmarose +emmarose1 +emmawatson +emmitt22 +emo4ever +emo4life +emo_limonad +emogirl1 +emokid123 +emolove1 +emolover +emopunk1 +emotion1 +emotional +emotional1 +emotions +emperador +emperor1 +employment +empress1 +emreemre +emyeuanh +enamorada +enamorada1 +enamorado +enchanted +encounter +encyclopedia +endeavour +endless1 +endlesslove +endurance +energizer +energizer1 +energy123 +energystar +enfermagem +enfermera +enforcer +engel00007 +engelchen +engelchen1 +engenharia +engineer +engineer1 +engineering +england1 +england10 +england12 +england123 +england2 +england66 +england7 +english1 +english12 +english123 +english2 +english3 +enjoylife +enocnayr +enrique1 +enrique123 +enriquez +ensemble +ensenada +enter123 +enternow +enterprise +enterprise1 +entertainment +entrance +entu6ea64h +envelope +environment +envision +envision1 +enyvbuois +eoce59cl9u +epiphany +epiphone +epiphone1 +episode1 +epsilon1 +eqes606898 +equilibrium +equinox1 +equitydev +er2sizo241 +eragon123 +erast.82 +erdbeere +erection +eremei_vasechkin +eric1234 +erica123 +ericeric +erick123 +erick1234 +erickson +ericsson +ericsson1 +erika123 +erikerik +ermakova +ernest97 +ernestina +ernestine +ernesto1 +ernestsantikov +ernie123 +errereer +eryyv588 +escaflowne +escalade +escalade1 +escalante +escapethef +escargot +escobar1 +escondido +escorpiao +escorpio +escorpion +escorpion1 +esercito +esidez57 +esmeralda +esmeralda1 +esmeralda2 +esoteric +especial +esperanca +esperance +esperanto +esperanza +esperanza1 +espinosa +espinoza +espinoza1 +espiritu +esposito +espresso +essence1 +essendon +essendon1 +essential +establish +esteban1 +estefani +estefania +estefania1 +estefany +estella1 +estelle1 +estetica +esther12 +esther123 +estrada1 +estrela1 +estrelas +estrelinha +estrella +estrella1 +estrella10 +estrella12 +estrella13 +estrella2 +estrella5 +estrella7 +estrellas +estrellita +estudante +estudiante +estupida +estupido +eternal1 +eternity +eternity1 +ethan123 +ethanryan01 +ethernet +ethiopia +ethiopia1 +etienne1 +etnxtxsa65 +etravelmoleoptin +euamojesus +eudlekb645 +eugene12 +eugenia1 +euphoria +euro2008 +euro2012 +eurogunz +euronics +evamaria +evanescenc +evanescence +evangelina +evangeline +evangelion +evangelist +evaristo +evelyn12 +evelyn123 +evenflow +everafter +everclear +everclear1 +everest1 +everett1 +evergreen +evergreen1 +everlast +everlast1 +everlastin +everlasting +everlong +evermore +everquest +everquest1 +everquest2 +everton1 +everton11 +everton123 +everton1878 +evertonfc +evertonfc1 +everybody +everyday +everyday1 +everyone +everything +everytime +evgenii-shenderovich +evgeniya +evgenkac +evial_marina +evidence +evildead +evildead1 +evildick +evolution +evolution1 +evolution2 +evolution7 +evolution8 +evolution9 +evony123 +evony192 +ewankosayo +ewelina1 +ewelinka +ewqdsacxz +excal007 +excaliber +excalibur +excalibur1 +excellence +excellent +excellent1 +excelsior +exchange +exclusive +exclusive1 +executive +executor +exercise +exit_window +expedition +expensive +experience +experiment +expert12 +exploited +explore1 +explorer +explorer1 +explosion +express1 +expresso +extension +extreme1 +eybdthcbntn +eyeball1 +eyeballs +eyecandy +eyecandy1 +eyeliner1 +eyeshield +eyeshield21 +ezekiel1 +ezekiel11989 +ezekiel11991 +ezequiel +ezequiel1 +f00tba11 +f00tball +f0lhvbok +f1234567 +f12345678 +f123456789 +f14tomcat +f15eagle +f1f2f3f4 +f1f2f3f4f5 +f1uuhza723 +f22raptor +f246865h +f5ghyjqhav +f75s83nqk3 +f76t93nqk3 +f76t94prm4 +fabian12 +fabian123 +fabienne +fabietto +fabio123 +fabiola1 +fabolous +fabolous1 +fabregas +fabregas4 +fabricio +fabrizio +fabulous +fabulous1 +faca210898 +face2face +faceb00k +facebook +facebook1 +facebook11 +facebook12 +facebook123 +facebook2 +factory1 +fade2black +faggot12 +faggot123 +faggot69 +fahjlbnf +fahrenheit +fairbanks +fairfield +fairfield1 +fairies1 +fairlady +fairlane +fairmont +fairplay +fairview +fairways +fairy123 +fairydust +fairydust1 +fairytail +fairytale +fairytale1 +faisal123 +faisalabad +faith101 +faith123 +faith777 +faithful +faithful1 +faithfull +faithingod +faithless +fake1234 +fakeass1 +fakebitch1 +fakefake +fakefake1 +fakegirl1 +fakename +fakename1 +fakeone1 +fakepage1 +fakespace1 +falcon01 +falcon10 +falcon11 +falcon12 +falcon123 +falcon13 +falcon16 +falcon69 +falcons07 +falcons1 +falcons12 +falcons2 +falcons7 +fall2007 +fall2008 +fall2011 +fallen12 +fallen123 +fallen13 +fallen_angel +fallenange +fallenangel +falling1 +fallinlove +fallout1 +fallout2 +fallout3 +falloutboy +falp5050 +famar219948 +famiglia +familia1 +familia10 +familia123 +familia4 +familia5 +families +familiyafamiliya +family#1 +family01 +family03 +family04 +family05 +family06 +family07 +family08 +family09 +family10 +family101 +family11 +family12 +family123 +family1234 +family13 +family14 +family15 +family1st +family21 +family22 +family23 +familyguy +familyguy1 +familyguy2 +familylove +familyof4 +familyof5 +familyof6 +famous11 +famous12 +famous123 +famous13 +famous21 +famous23 +fancypants +fandango +fandango1 +fandome1 +fang2008 +fangfang +fanny123 +fanta123 +fantasia +fantasia1 +fantasma +fantastic +fantastic1 +fantastic4 +fantastico +fantasy1 +fantasy12 +fantasy2 +fantasy7 +fantasy8 +fantomas +farah123 +fardubay +farewell +farfalla +farfallina +farhan123 +farmacia +farmboy1 +farmers1 +farmgirl +farmhouse +farmville +farrell1 +farscape +farscape1 +farside1 +fartface +fartface1 +fartfart +farthead +farthead1 +farting1 +fartman1 +fashion! +fashion1 +fashion101 +fashion12 +fashion123 +fashion2 +fashion7 +fashionist +fashionista +fastback +fastball +fastball1 +fastcar1 +fastcars +fastcars1 +fastfood +fastlane +fastrack +fasttrack +fatal1ty +fatality +fatamorgana +fatass12 +fatass123 +fatass13 +fatass69 +fatbastard +fatbitch +fatbitch1 +fatboy01 +fatboy10 +fatboy11 +fatboy12 +fatboy123 +fatboy13 +fatboy21 +fatboy23 +fatboy69 +fatboy99 +fatboyslim +fatcat12 +fatcat123 +fatdaddy +fatdaddy1 +fatfuck1 +fatgirl1 +fathead1 +father12 +father123 +father12345 +fatima12 +fatima123 +fatman12 +fatman123 +fatoumata +fatpussy +fatty123 +faulkner +faustina +faustine +faustino +favored1 +favorite +favorite1 +favorites +favoured +favourite +fazer600 +fbi11213 +fbu89bxx5f +fcbarcelona +fcbayern +fcbayern1 +fckgwrhqq2 +fdcnhfkbz +fdfyufhl +fdsafdsa +fearless +fearless1 +feather1 +feathers +feathers1 +febbraio +februari +february +february1 +february10 +february11 +february12 +february13 +february14 +february15 +february16 +february17 +february18 +february19 +february2 +february20 +february21 +february22 +february23 +february24 +february26 +february27 +february28 +feder_1941 +federal1 +federation +federer1 +federica +federica1 +federico +federico1 +fedorov717 +fedorova +fedotovsa76 +feedback +feelgood +feelings +feelmylove +felicia1 +feliciano +felicidad +felicidad1 +felicidade +felicidades +felicita +felicitas +felicity +felicity1 +felipe01 +felipe10 +felipe12 +felipe123 +felipe13 +felix.1957 +felix123 +felix1952 +felixthecat +fellowes +fellowship +femist22 +fenchel55 +fender01 +fender11 +fender12 +fender123 +fender69 +fener1907 +fenerbahce +fenerbahce1907 +fengfeng +fengshui +fenohasina39 +fenomeno +ferdinand +ferdinand1 +ferdinando +fergie12 +ferguson +ferguson1 +fericire +feride51 +fernand0 +fernanda +fernanda1 +fernanda12 +fernande +fernandes +fernandez +fernandez1 +fernandito +fernando +fernando. +fernando1 +fernando10 +fernando12 +fernando123 +fernando13 +fernando2 +fernando9 +fernandotorres +ferndale +ferrari01 +ferrari1 +ferrari12 +ferrari123 +ferrari2 +ferrari355 +ferrari360 +ferrari430 +ferrari7 +ferrarif1 +ferrarif40 +ferrarif430 +ferrarif50 +ferreira +festival +festival1 +feuerwehr +feuerwehr1 +feyenoord +feyenoord1 +ff123456 +ffffffff +fffffffff +ffffffffff +ffffffffffff +fgdfgdfg +fgfr56hfve6 +fggjkbyfhbq007 +fghfghfgh +fgjrfkbgcbc +fgjrfkbgcbc34 +fgrd58es24 +fgtkmcby +fgtkmcbyrf +fh1hm1wl +fhbyjxrf +fhnehxbr +fhntv1998 +fhutynbyf +fhvfutljy +fiammalex1@hotmail.it +fiatpunto +fibonacci +fickdich +fickdich1 +ficken123 +ficken666 +ficken69 +ficken76 +fiction1 +fidelidade +fidelio1 +fidelity +fidodido +fiesta01 +fietsbel +fifa2000 +fifa2002 +fifa2005 +fifa2006 +fifa2007 +fifa2008 +fifa2009 +fifa2010 +fifa2011 +fifafifa +fifteen15 +fiftycent +fight123 +fightclub +fightclub1 +fighter1 +fighters +fighting +fighting1 +figueroa +figueroa1 +filatov_and +filatovaev1981 +filefront +filip123 +filipina +filipino +filipino1 +filippo1 +fillmore +film@123 +filomena +filosofia +filsdepute +filudskou +final123 +finalfanta +finalfantasy +finalfantasy7 +finally1 +finance1 +financial +financial123 +find1234 +find_pass +findajob +findlove +finestra +finger11 +fingers1 +finland1 +finlandia +finnegan +finnigan +fiona123 +fiorella +fiorellino +fiorello +fiorentina +firakoki +fire1234 +fireandice +fireball +fireball1 +fireball12 +fireball2 +firebird +firebird1 +fireblade +fireblade1 +firebolt +firecracker +firedog1 +firedragon +firefighte +firefighter +firefire +firefire1 +fireflies +firefly1 +firefox1 +firehawk +firehouse +firehouse1 +fireman1 +fireman12 +fireman2 +firenze1 +fireplace +firestar +firestar1 +firestarter +firestone +firestone1 +firestorm +firestorm1 +firetruck +firetruck1 +firewall +firewall1 +firewater +firewire +firewood +firework +fireworks +fireworks1 +firstborn +firstlady +firstlove +firstlove1 +fischer1 +fish1234 +fishbaracuda +fishbone +fishbone1 +fishbowl +fishcake +fisher12 +fisherman +fisherman1 +fishface +fishface1 +fishfish +fishfish1 +fishfood +fishfood1 +fishhead +fishhead1 +fishing! +fishing01 +fishing1 +fishing101 +fishing11 +fishing12 +fishing123 +fishing2 +fishing3 +fishing4 +fishing5 +fishing69 +fishing7 +fishlips +fishman1 +fishpond +fishstick1 +fishsticks +fishtank +fishtank1 +fishy123 +fisioterapia +fit4life +fitness1 +fitzgerald +fivekids +fivestar +fivestar1 +fj5tx19hit +fjodorova-natashenka +fk3456abc +fkbyf001 +fkbyjxrf +fkg7h4f3v6 +fkmnthyfnbdf +fktdnbyf +fktrcfylh +fktrcfylh1 +fktrcfylhf +fktrcfylhjdbx +fktrcfylhjdyf +fktrcttdf +fktyeirf +fktyjxrf +flame123 +flameboy +flameboy1 +flamenco +flamenco1 +flamengo +flamengo1 +flamengo10 +flames12 +flamingo +flamingo1 +flanagan +flanders +flapjack +flapjack1 +flaquita +flaquito +flash123 +flashback +flashlight +flashman +flashpoint +flatblocker +flathead +flatland +flatline +flatron1 +flawless +flawless1 +fleetwood +fleetwood1 +flego0815 +fleming1 +flemming +fler_2351 +fletcher +fletcher1 +flexible +flexible1 +flhtyfkby +flight23 +fling123 +flintstone +flipflop +flipflop1 +flipmode +flipmode1 +flipper1 +flipper2 +flipside +flipside1 +floortje +florcita +florecita +florence +florence1 +florencia +florencia1 +florencio +florentin +florentina +florentino +flores12 +flores123 +flores13 +floresta +florian1 +floriana +floriane +floricienta +florida! +florida01 +florida06 +florida07 +florida08 +florida09 +florida1 +florida10 +florida11 +florida12 +florida123 +florida13 +florida2 +florida22 +florida3 +florida4 +florida5 +florida6 +florida7 +florida8 +florida9 +florinda +florzinha +flossie1 +flounder +flounder1 +flower01 +flower08 +flower09 +flower10 +flower101 +flower11 +flower12 +flower123 +flower1234 +flower13 +flower14 +flower15 +flower16 +flower17 +flower18 +flower21 +flower22 +flower23 +flower24 +flower33 +flower45 +flower69 +flower77 +flower88 +flower99 +flowergirl +flowerpot +flowerpot1 +flowerpowe +flowerpower +flowers! +flowers. +flowers1 +flowers11 +flowers12 +flowers123 +flowers2 +flowers22 +flowers3 +flowers4 +flowers5 +flowers7 +flowers8 +floyd123 +flubber1 +fluffy01 +fluffy10 +fluffy11 +fluffy12 +fluffy123 +fluffy13 +fluffy22 +fluffy69 +fluminense +flutterby +fluturas +flvbybcnhfnjh +flyaway1 +flyers88 +flyfish1 +flyfishing +flygirl1 +flyhigh1 +flyleaf1 +fnkfynblf +focus123 +focused1 +foks8484 +folashade +folletto +followme +fomalex10 +fontaine +food1234 +foodfood +foofighter +foofighters +foolish1 +foolproof +foosball +footba11 +footbal1 +football +football! +football#1 +football. +football0 +football00 +football01 +football02 +football03 +football04 +football05 +football06 +football07 +football08 +football09 +football1 +football10 +football101 +football11 +football12 +football123 +football13 +football14 +football15 +football16 +football17 +football18 +football19 +football2 +football20 +football21 +football22 +football23 +football24 +football25 +football26 +football27 +football28 +football29 +football3 +football30 +football31 +football32 +football33 +football34 +football35 +football36 +football37 +football38 +football4 +football40 +football41 +football42 +football43 +football44 +football45 +football46 +football47 +football48 +football49 +football5 +football50 +football51 +football52 +football53 +football54 +football55 +football56 +football57 +football58 +football59 +football6 +football60 +football61 +football62 +football63 +football64 +football65 +football66 +football67 +football68 +football69 +football7 +football70 +football71 +football72 +football73 +football74 +football75 +football76 +football77 +football78 +football79 +football8 +football80 +football81 +football82 +football83 +football84 +football85 +football86 +football87 +football88 +football89 +football9 +football90 +football91 +football92 +football93 +football94 +football95 +football96 +football97 +football98 +football99 +footballer +foothill +footloose +footprints +forbidden +forbidden1 +ford1234 +ford2000 +ford2001 +fordescort +fordf100 +fordf150 +fordf250 +fordf350 +fordfiesta +fordfocus +fordfocus1 +fordford +fordgt40 +fordman1 +fordmondeo +fordmustang +fordranger +fordtruck +fordtruck1 +foreman1 +forensic +foreplay +foresight +forest12 +forest123 +forester +forever! +forever. +forever0 +forever01 +forever07 +forever08 +forever09 +forever1 +forever10 +forever11 +forever12 +forever123 +forever13 +forever14 +forever15 +forever16 +forever17 +forever18 +forever2 +forever21 +forever22 +forever23 +forever24 +forever25 +forever27 +forever3 +forever4 +forever5 +forever6 +forever69 +forever7 +forever8 +forever9 +foreveralone +foreverand +foreverlov +foreverlove +forevermor +foreveryou +foreveryoung +forget12 +forget123 +forgetful +forgetful1 +forgetit +forgetit1 +forgetme +forgetmenot +forgive1 +forgiveme +forgiven +forgiven1 +forgotit +forgotten +forgotten1 +forklift +forlife1 +formation +formentera +formula1 +formule1 +forreal1 +forrest1 +forsaken +forsaken1 +forsberg +forsberg21 +forsythe +fortaleza +fortress +fortuna1 +fortuna95 +fortunate +fortunato +fortune1 +fortytwo +forum123 +forward1 +forzainter +forzaitalia +forzajuve +forzalazio +forzalecce +forzamilan +forzanapoli +forzaroma +forzatoro +foshizzle +foshizzle1 +fosters1 +fotinia-66 +fotograf +fotografia +foufoune +foundation +fountain +fountain1 +four4444 +fourboys +fourfour +fourkids +fourkids4 +fourteen +fourteen14 +fourtwenty +foxfire1 +foxglove +foxhound +foxmulder +foxracing +foxracing1 +foxracing2 +foxtrot1 +foxylady +foxylady1 +foxyroxy +foxyroxy1 +fpna23aas1 +fqi3p8arjg +fqrg7cs493 +fraggle1 +fragile1 +fragolina +framboise +francais +france12 +france123 +france98 +frances1 +frances2 +francesc +francesca +francesca1 +francesco +francesco1 +franchesca +francheska +franchise +franchise1 +francine +francine1 +francis1 +francis12 +francis123 +francis2 +francis3 +francisca +francisca1 +francisco +francisco1 +francisco2 +franco123 +francois +francois1 +francoise +frank123 +frank1234 +frankenstein +frankfurt +frankfurt1 +frankie! +frankie01 +frankie1 +frankie11 +frankie12 +frankie123 +frankie13 +frankie2 +frankie3 +frankie4 +frankie5 +frankie7 +frankiero1 +frankies +franklin +franklin1 +franklin12 +franklin2 +franklyn +frankreich +frankzappa +frannie1 +frant_nat +franziska +fratello +frazier1 +frdfhbev +frdfvfhby +freak101 +freak123 +freak666 +freakazoid +freakout +freakshow +freakshow1 +freaky12 +freaky123 +freaky69 +frechdachs +freckles +freckles1 +fred1234 +fred1994 +freddie1 +freddie123 +freddie2 +freddurst +freddy01 +freddy11 +freddy12 +freddy123 +freddy13 +frederic +frederic1 +frederick +frederick1 +frederico +frederik +frederique +fredfred +fredfred1 +fredperry +fredrick +fredrick1 +free1234 +free2beme +free2bme +free2rhyme +free4all +free4ever +free4life +freeatlast +freebies +freebird +freebird1 +freedom! +freedom. +freedom0 +freedom01 +freedom06 +freedom07 +freedom08 +freedom09 +freedom1 +freedom10 +freedom101 +freedom11 +freedom12 +freedom123 +freedom13 +freedom2 +freedom200 +freedom201 +freedom2010 +freedom21 +freedom22 +freedom23 +freedom3 +freedom4 +freedom4me +freedom5 +freedom55 +freedom6 +freedom69 +freedom7 +freedom77 +freedom8 +freedom88 +freedom9 +freedoms +freefall +freefall1 +freefood +freefree +freefree1 +freelance +freelancer +freeland +freelander +freelife +freelove +freemail +freeman1 +freeman2 +freemind +freemoney +freemusic +freepass +freeporn +freeport +freeport1 +freeride +freerider +freespirit +freestuff +freestyle +freestyle1 +freestyler +freetime +freetown +freeuser +freeway1 +freewill +freewilly +freeze112 +freiburg +freiheit +freiheit89 +fremont1 +frenchfrie +frenchfries +frenchfry +frenchfry1 +frenchie +frenchie1 +frenchkiss +frenchy1 +fresh101 +fresh123 +fresh2def +freshboy +freshman +freshman09 +freshman1 +freshmen +freshstart +fresita1 +fresno559 +freunde1 +frfltvbz +fri3q9arjg +friday01 +friday11 +friday12 +friday123 +friday13 +fridolin +friedrich +friend11 +friend12 +friend123 +friendly +friendly1 +friendofarriane +friendofearning$1 +friendofemily +friendofeveryemailyouproc +friendofgerly +friendofjoan +friendofthenext18peoplew +friendofyoucanmake$200- +friends! +friends. +friends0 +friends01 +friends06 +friends07 +friends08 +friends09 +friends1 +friends10 +friends101 +friends11 +friends12 +friends123 +friends13 +friends14 +friends15 +friends16 +friends2 +friends21 +friends22 +friends23 +friends3 +friends33 +friends4 +friends4ev +friends4ever +friends4li +friends4me +friends5 +friends6 +friends7 +friends8 +friends9 +friendsfor +friendsforever +friendship +friendship1 +friendss +friendster +friendster1 +friendz1 +frighten +frijolito +frimousse +fripouille +frisbee1 +frisco415 +fritz123 +frodo123 +frog1234 +frogfrog +frogger1 +frogger2 +froggie1 +froggies +froggies1 +froggy01 +froggy101 +froggy11 +froggy12 +froggy123 +froggy13 +froggy22 +froggy69 +froglegs +froglegs1 +frogman1 +frogs123 +front242 +frontech +frontera +frontier +frontier1 +frontline +frontline1 +frostbite +frosty12 +frosty123 +frqnj0zf5p +fruitbat +fruitcake +fruitcake1 +fruitloop +fruitloop1 +fruitloops +frusciante +fsd9shtyut +ftbfrvlg17 +ftrcvh5732 +fu7u4a#$$$ +fuchurli +fuck-off +fuck-you +fuck.you +fuck1234 +fuck12345 +fuck123456 +fuck1you +fuck_off +fuck_you +fuckabitch +fuckaduck +fuckaduck1 +fuckall1 +fuckass1 +fuckbitch1 +fuckbitche +fuckbitches +fuckbuddy +fuckedup +fuckedup1 +fuckemall +fucker01 +fucker11 +fucker12 +fucker123 +fucker13 +fucker21 +fucker22 +fucker23 +fucker666 +fucker69 +fuckers! +fuckers1 +fuckevery1 +fuckface +fuckface1 +fuckface2 +fuckfuck +fuckfuck1 +fuckfuckfuck +fuckhaters +fuckhead +fuckhead1 +fuckher1 +fuckher2 +fuckhim1 +fuckhoes1 +fucking1 +fucking123 +fucking2 +fucking69 +fuckingshit +fuckit11 +fuckit12 +fuckit123 +fuckit13 +fuckit420 +fuckit69 +fuckitall +fuckitall1 +fuckl0v3 +fuckl0ve +fucklife +fucklife1 +fucklov3 +fucklove +fucklove! +fucklove09 +fucklove1 +fucklove10 +fucklove12 +fucklove13 +fucklove14 +fucklove2 +fucklove21 +fucklove23 +fucklove3 +fucklove4 +fucklove69 +fucklove7 +fuckme11 +fuckme12 +fuckme123 +fuckme13 +fuckme21 +fuckme22 +fuckme23 +fuckme420 +fuckme666 +fuckme69 +fuckmehard +fuckmenow +fuckmyass +fuckmylife +fuckmyspac +fucknut1 +fuckoff! +fuckoff. +fuckoff0 +fuckoff01 +fuckoff09 +fuckoff1 +fuckoff11 +fuckoff12 +fuckoff123 +fuckoff13 +fuckoff2 +fuckoff21 +fuckoff22 +fuckoff23 +fuckoff3 +fuckoff4 +fuckoff420 +fuckoff5 +fuckoff6 +fuckoff666 +fuckoff69 +fuckoff7 +fuckoff8 +fuckoff88 +fuckoff9 +fuckshit +fuckshit1 +fuckstick +fuckstick1 +fucktard +fucktard1 +fuckth1s +fuckthat +fuckthat1 +fuckthemall +fuckthewor +fucktheworld +fuckthis +fuckthis! +fuckthis1 +fuckthis12 +fuckthis2 +fuckthissh +fuckthisshit +fucktop8 +fucku123 +fucku666 +fuckuall +fuckuall1 +fuckubitch +fuckyeah +fuckyeah1 +fuckyou! +fuckyou!! +fuckyou. +fuckyou0 +fuckyou00 +fuckyou01 +fuckyou02 +fuckyou06 +fuckyou07 +fuckyou08 +fuckyou09 +fuckyou1 +fuckyou10 +fuckyou100 +fuckyou101 +fuckyou11 +fuckyou111 +fuckyou12 +fuckyou123 +fuckyou13 +fuckyou14 +fuckyou15 +fuckyou16 +fuckyou17 +fuckyou18 +fuckyou187 +fuckyou19 +fuckyou2 +fuckyou20 +fuckyou21 +fuckyou22 +fuckyou23 +fuckyou24 +fuckyou25 +fuckyou26 +fuckyou27 +fuckyou3 +fuckyou32 +fuckyou321 +fuckyou33 +fuckyou4 +fuckyou420 +fuckyou44 +fuckyou45 +fuckyou5 +fuckyou55 +fuckyou6 +fuckyou66 +fuckyou666 +fuckyou69 +fuckyou7 +fuckyou77 +fuckyou78 +fuckyou8 +fuckyou86 +fuckyou87 +fuckyou88 +fuckyou89 +fuckyou9 +fuckyou90 +fuckyou92 +fuckyou99 +fuckyouall +fuckyouass +fuckyoubit +fuckyoubitch +fuckyoutoo +fudge123 +fujifilm +fujitsu1 +fujitvpass +fuk19600 +fuku00198 +fullaccess +fullback +fullerton +fullerton1 +fullhouse +fullhouse1 +fullmetal +fullmetal1 +fullmoon +fullmoon1 +fumanchu +function +funeral1 +funfunfun +fungible +funhouse +funky123 +funkymonkey +funkytown +funkytown1 +funmilayo +funmilola +funny123 +funnybunny +funnyface +funnygirl +funnygirl1 +funnyguy +funnyman +funnyman1 +funstuff +funtime1 +funtimes +funtimes1 +fupyuxta66 +fupyuxtb66 +furball1 +furious1 +furniture +furniture1 +fusion12 +fussball +fussball1 +futbol10 +futurama +futurama1 +future12 +future123 +futyn007 +fuzzball +fuzzball1 +fuzzy123 +fvcnthlfv +fxnocp14 +fxzz75$yer +fxzz75yer +fy.njxrf +fybcbvjdf +fyfcnfcbz +fyfnjkbq +fyfnjkbq777 +fyfnjkmtdyf +fyfrjylf +fylh.irf +fylhtq12 +fylhtqrf +fylhttdf +fylhttdyf +fynjybyf +fynjyjdf +fysihz5g +fyujk.fyukf.87 +fyutkbyf +fyutkjxtr +g00dluck +g00dpa$$w0rd +g0ldfish +g1234567 +g12345678 +g123456789 +g13916055158 +g76t94prm4 +g76u94prm4 +g86u94psn5 +g86ua5qsn5 +g9l2d1fzpy +g_alisa1502 +gaar_vitalik73 +gaara123 +gabbiano +gabby123 +gabriel. +gabriel01 +gabriel05 +gabriel06 +gabriel07 +gabriel08 +gabriel09 +gabriel1 +gabriel10 +gabriel11 +gabriel12 +gabriel123 +gabriel13 +gabriel14 +gabriel15 +gabriel17 +gabriel2 +gabriel21 +gabriel22 +gabriel23 +gabriel3 +gabriel4 +gabriel5 +gabriel6 +gabriel7 +gabriel8 +gabriel9 +gabriela +gabriela1 +gabriela12 +gabriela2 +gabriela7 +gabriele +gabriele1 +gabrielito +gabriell +gabriella +gabriella1 +gabrielle +gabrielle1 +gabrielle2 +gadjieva.gulmira +gagagaga +galactica +galadriel +galaktika +galapagos +galatasara +galatasaray +galatasaray1905 +galaxy123 +galileo1 +galina-davidyuk +galina9181 +galinka_korneeva +galinkaru +gallagher +gallagher1 +gallardo +gallardo1 +gallegos +gallery1 +galloway +gamaliel +gambion32 +gambler1 +game1234 +gameboy1 +gameboy2 +gamecock +gamecock1 +gamecocks +gamecocks1 +gamecube +gamecube1 +gamefreak +gamefreak1 +gamegame +gamemaster +gameover +gameover1 +gameplay +gamer123 +gamer4life +games123 +gamestar +gamestop +gamestop1 +gametime +gametime1 +gammaray +ganapathi +ganapathy +ganapati +gandaako +gandako1 +gandakoh +gandalf1 +ganesh123 +ganesha1 +ganeshji +gangbang +gangbang1 +ganggang +gangsta! +gangsta. +gangsta01 +gangsta1 +gangsta10 +gangsta101 +gangsta11 +gangsta12 +gangsta123 +gangsta13 +gangsta14 +gangsta15 +gangsta2 +gangsta21 +gangsta22 +gangsta23 +gangsta3 +gangsta4 +gangsta5 +gangsta6 +gangsta69 +gangsta7 +gangsta74 +gangsta8 +gangsta9 +gangstah +gangstar +gangstar1 +gangster +gangster! +gangster1 +gangster10 +gangster11 +gangster12 +gangster13 +gangster14 +gangster2 +gangster23 +gangster3 +gangster4 +gangster5 +gangster6 +gangster7 +gangsters +ganja123 +ganja420 +ganjaman +ganjubas +ganondorf +ganster1 +ganteng1 +garbage1 +garcia10 +garcia12 +garcia123 +garcia13 +gardener +gardenia +gardening +gardner1 +garfield +garfield1 +garfield12 +garfield2 +garfield7 +gargamel +gargoyle +garibaldi +garland1 +garnett21 +garnett5 +garrett1 +garrett12 +garrett123 +garrett2 +garrett3 +garrison +garrison1 +gary1234 +gasolina +gasoline +gasparin +gatekeeper +gateway1 +gateway11 +gateway12 +gateway123 +gateway2 +gateway200 +gateway2000 +gateway3 +gateway5 +gateway7 +gathering +gatina_albina +gatogato +gatonegro +gator123 +gatorade +gatorade1 +gators01 +gators11 +gators12 +gators123 +gators15 +gatubela +gauloises +gaurav123 +gauthier +gavin123 +gavroche +gay4life +gayassfagpastebinleaks +gayathri +gaygaygay +gaylord1 +gayness1 +gaypride +gaypride1 +gb15kv99 +gbemisola +gbgbcmrf +gbhfvblf +gblfhfcs +gbljhfcs +gbolahan +gcheckout +gdcc9921 +gearhead +gearsofwar +gearsofwar2 +geelong1 +geetanjali +gefccgag +geheim123 +geibcnbr +gemini01 +gemini06 +gemini11 +gemini12 +gemini123 +gemini13 +gemini17 +gemini18 +gemini21 +gemini22 +gemini23 +gemini69 +gemini77 +gemini88 +gemma123 +gemstone +gendarme +general01 +general1 +general123 +general2 +generale +generallee +generals +generals1 +generation +generator +generic1 +genesis01 +genesis1 +genesis11 +genesis12 +genesis123 +genesis2 +genesis3 +genesis7 +genetics +genevieve +genevieve1 +genius12 +genius123 +geniusnet +gennadiy +genoa1893 +genocide +genoveva +gentleman +genuine1 +geoffrey +geoffrey1 +geografia +geography +geometra +geometry +geordie1 +george01 +george06 +george07 +george08 +george09 +george10 +george11 +george12 +george123 +george1234 +george13 +george14 +george15 +george16 +george17 +george18 +george21 +george22 +george23 +george24 +george25 +george27 +george69 +george77 +george99 +georgetown +georgette +georgia01 +georgia1 +georgia11 +georgia12 +georgia123 +georgia2 +georgia3 +georgia7 +georgiana +georgie1 +georgina +georgina1 +geppetto +gerald123 +geraldine +geraldine1 +geranium +gerard12 +gerard123 +gerardo1 +gerardway +gerardway1 +gerlinde +germaine +german123 +germania +germany1 +germany123 +germany2 +geronimo +geronimo1 +gerrard08 +gerrard1 +gerrard8 +gershwin +gertrude +gertrude1 +gesundheit +get2work +getalife +getalife1 +getatme1 +getcrunk1 +getfucked +getfucked1 +gethigh1 +gethigh420 +getlikeme1 +getlost1 +getmoney +getmoney! +getmoney$ +getmoney07 +getmoney08 +getmoney09 +getmoney1 +getmoney10 +getmoney11 +getmoney12 +getmoney2 +getmoney21 +getmoney22 +getmoney23 +getmoney24 +getmoney3 +getmoney4 +getmoney5 +getmoney6 +getmoney7 +getpaid1 +getrdone +getrdone1 +getrich1 +getsilly1 +getsmart +getsome1 +gettherefast +gettysburg +gewinner +gfccdjhl +gfgfgfgf +gfgfvfvf +gfhfljrc +gfhjk123 +gfhjkm11 +gfhjkm12 +gfhjkm123 +gfhjkm12345 +gfhjkm13 +gfhjkm1998 +gfhjkm777 +gfhjkmgfhjkm +gfhjkmrf +gfhjkmxbr +gfhjkzytn +gfhkfvtyn +gfhnbpfy +gfs2z6wb +gfyfcjybr +gfyt63gd +gg123456 +gggggggg +ggggggggg +gggggggggg +ghalina_1971 +ghana123 +ghbdtn12 +ghbdtn123 +ghbdtnbr +ghbdtnbrb +ghbdtndctv +ghbdtnekmrb +ghbdtnghbdtn +ghbdtngjrf +ghbdtnrfrltkf +ghbjhbntn +ghblehjr +ghblehrb +ghbrjkbcn +ghbrjkmyj +ghbywtccf +gheniagabb +gheorghe +ghetto12 +ghetto123 +ghfplybr +ghghghgh +ghhh47hj7649 +ghislain +ghislaine +ghjcgtrn +ghjcnbnenrf +ghjcnbvtyz +ghjcnj123 +ghjcnjgfhjkm +ghjcnjghjcnj +ghjcnjkjk +ghjcnjnfr +ghjcnjqgfhjkm +ghjcnjrdfibyj +ghjcnjrdfif +ghjdthrf +ghjghjghj +ghjnjnbg +ghjnjrjk +ghjrehfnehf +ghjrehjh +ghjuhfvvbcn +ghjuhfvvf +ghjuhtcc +gholovach75 +ghost123 +ghost666 +ghostdog +ghostface +ghostface1 +ghostman +ghostrecon +ghostrider +ghrimachiova64 +ghtdtl123 +ghtktcnm +ghtpbltyn +ghusieva1958 +giacomino +giacomo1 +giancarlo +gianfranco +gianluca +gianmarco +giants08 +giants10 +giants11 +giants12 +giants123 +giants21 +giants25 +giants56 +gibraltar +gibson01 +gibson12 +gibson123 +gibsonsg +gibsonsg1 +gidrometeoburo +gigabyte +gigaman8891 +giggity1 +giggles1 +giggles12 +giggles123 +giggles13 +giggles2 +gigglez1 +gigigigi +gilbert1 +gilbert2 +gilberto +gilberto1 +gilgamesh +gilipollas +gillespie +gillette +gillian1 +gilligan +gilligan1 +gillingham +gilmore1 +ginagina +ginger00 +ginger01 +ginger02 +ginger06 +ginger07 +ginger08 +ginger09 +ginger10 +ginger101 +ginger11 +ginger12 +ginger123 +ginger1234 +ginger13 +ginger14 +ginger15 +ginger16 +ginger17 +ginger18 +ginger21 +ginger22 +ginger23 +ginger24 +ginger33 +ginger69 +ginger77 +ginger88 +ginger99 +gingerale +gingerbread +gingersnap +gingging +ginogino +gintonic +ginuwine +ginuwine1 +gioconda +giordano +giorgina +giorgio1 +giovanna +giovanna1 +giovanni +giovanni1 +giovanni123 +giovanny +giraffe1 +girasole +girassol +giratina +giresun28 +girl1234 +girlfriend +girlgirl +girlpower +girlpower1 +girls101 +girls123 +girlsrock +girlsrock1 +girlsrule +girlsrule1 +girly123 +girlygirl +girlygirl1 +giselle1 +gisselle +gitrdone +gitrdone1 +giuditta +giuliana +giuliano +giulietta +giuseppe +giuseppe1 +giuseppina +giveit2me +givenchy +gizmo123 +gjcaixxx +gjhjctyjr +gjikbdctyf +gjkbyjxrf +gjkzrjdf +gjlcnfdf +glacier1 +gladbach +gladiador +gladiator +gladiator1 +gladiatore +gladiolus +gladstone +glafira110169 +glamorous +glamorous1 +glamour1 +glasgow1 +glass123 +glasses1 +glassjaw +glassman +gleiser4 +glendale +glendale1 +glenn123 +glenwood +glenwood1 +glitter1 +glitter2 +global123 +gloria12 +gloria123 +glorioso +glorious +glorious1 +glory123 +glory2god +glorytogod +gloucester +gluxov70 +gmail.com +gmail123 +gn9gu44s +go4itnow +goalkeeper +gobears1 +gobigred +gobucks1 +gocards1 +god12345 +god4ever +god4life +godawgs1 +godbless +godbless1 +godblessme +godblessu +godblessus +godblessyou +godchild +goddamn1 +goddess1 +goderdzikarxjxv +godfather +godfather1 +godfather2 +godfirst +godfirst1 +godfrey1 +godgrace +godhelpme +godhelpme1 +godim001 +godisable +godisgood +godisgood! +godisgood1 +godisgood2 +godisgood7 +godisgr8 +godisgreat +godislove +godislove1 +godislove2 +godislove7 +godisone +godjesus +godknows +godlike1 +godlove1 +godloveme +godloves +godloves1 +godlovesme +godofwar +godofwar1 +godofwar2 +godofwar3 +godrocks +godrocks1 +godrules +godrules1 +godschild +godschild1 +godsfavor +godsgift +godsgift1 +godsgirl +godsgrace +godslove +godslove1 +godsmack +godsmack1 +godspeed +godspeed1 +godsson1 +godswill +godswill1 +goducks1 +godzilla +godzilla1 +godzilla2 +goeagles +gofman_osk +goforit1 +gofuckyour +gofuckyourself +gogators +gogators1 +gogetta1 +gogetter +gogiants +gogogogo +gogreen1 +gohabsgo +goirish1 +gokussj4 +golaso64 +gold1234 +goldberg +goldberg1 +goldcoast +golddigger +golden01 +golden11 +golden12 +golden123 +golden22 +goldenboy +goldenboy1 +goldeneye +goldeneye1 +goldengate +goldengirl +goldensun +goldfinger +goldfish +goldfish1 +goldfish12 +goldfish2 +goldflake +goldgold +goldie12 +goldie123 +goldilocks +goldleaf +goldmember +goldmine +goldorak +goldrush +goldsmith +goldstar +goldstar1 +goldwing +goldwing1 +goleafsgo +golf1234 +golf4fun +golfball +golfball1 +golfclub +golfcourse +golfer01 +golfer11 +golfer12 +golfer123 +golfer69 +golfgolf +golfing1 +golfinho +golfpro1 +golga.70 +goliath1 +golosa69 +golovizina_elena +golubinskij.87 +goluboglazka08 +goman1985 +gomez123 +goncalves +gonefishin +gonefishing +gonoles1 +gonzaga1 +gonzales +gonzales1 +gonzalez +gonzalez1 +gonzalez12 +gonzalo1 +gonzo123 +goober12 +goober123 +good1234 +good12345 +good123456 +good123654 +good4now +good4you +goodboy1 +goodboy123 +goodbullet +goodbye1 +goodbye2 +goodcharlotte +goodday1 +goodfella1 +goodfellas +goodfood +goodfriend +goodgame +goodgirl +goodgirl1 +goodgod1 +goodgood +goodgood1 +goodguy1 +goodies1 +goodison +goodlife +goodlife1 +goodlooking +goodlord +goodlove +goodluck +goodluck1 +goodluck123 +goodman1 +goodmorning +goodmother +goodness +goodness1 +goodnews +goodnight +goodnight1 +goodpussy +goodpussy1 +goodrich +goodstuff +goodtime +goodtime1 +goodtimes +goodtimes1 +goodtogo +goodwife +goodwill +goodwill1 +goodwin1 +goodwoman +goodwood +goody2shoe +goodyear +goodyear1 +goofball +goofball1 +goofy123 +google.com +google01 +google10 +google11 +google12 +google123 +google1234 +google13 +google21 +google22 +google23 +google69 +googlecheckout +googletester +goon4life +goonies1 +goonsquad1 +goose123 +goosebumps +gopher12 +gopinath +gordita1 +gordito1 +gordo123 +gordon12 +gordon123 +gordon24 +gorgeous +gorgeous1 +gorilla1 +gorillas +gorillaz +gorillaz1 +gorlonis +gosiaczek +gossipgirl +gotenks1 +gothic12 +gothic123 +gothic13 +gothic666 +gotigers +gotigers1 +gotmilk1 +gotmilk2 +gotmilk? +gotmoney1 +gotohell +gotohell1 +gouranga +government +governor +goxyboib +goyj2010 +gr33nday +grace123 +grace4me +grace777 +graceful +graceland +graceland1 +gracie01 +gracie03 +gracie05 +gracie06 +gracie07 +gracie08 +gracie09 +gracie10 +gracie11 +gracie12 +gracie123 +gracie13 +gracie22 +graciela +graciela1 +gracious +grad2006 +grad2007 +grad2008 +grad2009 +grad2010 +graduate +graduate08 +graduate1 +graduation +graffiti +graffiti1 +granada1 +grandad1 +grandam1 +grandchase +grandchildren +grandkids +grandkids1 +grandkids2 +grandkids3 +grandkids4 +grandkids5 +grandkids6 +grandkids7 +grandma! +grandma01 +grandma1 +grandma11 +grandma12 +grandma123 +grandma2 +grandma3 +grandma4 +grandma5 +grandma6 +grandma7 +grandma8 +grandmaster +grandmom +grandmom1 +grandmother +grandpa1 +grandpa2 +grandprix +grandprix1 +grandslam +grandson +grandson1 +grandtheft +granger1 +granite1 +granny12 +grant123 +granville +grapeape +grapefruit +grapevine +graphics +graphics1 +grasshoppe +grasshopper +grateful +grateful1 +gratis123 +gratitude +gravedigger +graveyard +gravity1 +grayson1 +graywolf +graziano +graziella +great123 +greatdane +greatday +greatday1 +greater1 +greatest +greatest1 +greatgod +greatman +greatness +greatness1 +greatone +greatone1 +greatwhite +greedisgood +green100 +green101 +green111 +green123 +green1234 +green12345 +green321 +green420 +green777 +greenapple +greenbay +greenbay1 +greenbay4 +greenbean +greenbean1 +greenday +greenday! +greenday. +greenday1 +greenday10 +greenday11 +greenday12 +greenday123 +greenday13 +greenday14 +greenday2 +greenday21 +greenday3 +greenday4 +greenday5 +greenday6 +greenday7 +greenday9 +greendog +greeneggs +greeneyes +greeneyes1 +greeneyes2 +greenfield +greenfrog +greenfrog1 +greengirl +greengrass +greengreen +greenhouse +greenland +greenlantern +greenleaf +greenlight +greenman +greenman1 +greenpeace +greentea +greentea1 +greentree +greentree1 +greenville +greenway +greenwich +greenwood +greenwood1 +greetings +greg1234 +gregoire +gregorio +gregory1 +gregory123 +gregory2 +gregory3 +gregory7 +gremlin1 +gremlins +grendel1 +grenoble +grenouille +greshnik +gretchen +gretchen1 +gretzky99 +greygoose +greygoose1 +greyhound +greyhound1 +greywolf +gribouille +griffey1 +griffey24 +griffin1 +griffith +grih-rom +grimreaper +grindcore +grinder1 +grinding +grinface +griselda +griselda1 +grisette +grishin0308 +grizzly1 +groceries +groningen +groucho1 +grounded +grounded1 +groundhog +groupd2013 +grumpy13 +gryffindor +grzegorz +grzesiek +gsxr1000 +gsxr1100 +gsxr1300 +gtasanandreas +gtavicecity +gthtcnhjqrf +gtkmvtyb +gtkmvtym +gtnheirf +gtnhjczy +gtnhjdbx +gtnhjdyf +gtxtymrf +guacamole +guadalajar +guadalajara +guadalupe +guadalupe1 +guadalupe2 +guadeloupe +gualapmi +guanajuato +guardian +guardian1 +guardian101 +guardians +guatemala +guatemala1 +guatemala2 +guayaquil +gucci123 +guccimane +guccimane1 +guerreiro +guerrero +guerrero1 +guess123 +guessit1 +guessit22 +guessthis1 +guesswhat +guesswhat1 +guesswho +guesswho1 +guevara1 +guevarra +guildwars +guildwars1 +guilherme +guilherme1 +guillaume +guillaume1 +guillermo +guillermo1 +guimaraes +guineapig +guiness1 +guinness +guinness1 +guitar01 +guitar10 +guitar101 +guitar11 +guitar12 +guitar123 +guitar13 +guitar14 +guitar15 +guitar21 +guitar22 +guitar23 +guitar666 +guitar69 +guitar77 +guitare1 +guitarhero +guitarist +guitarist1 +guitarman +guitarman1 +guitarra +guitarra1 +guitars1 +gujunpyo +guldaniya.galina +gulliver +gumball1 +gumdrop1 +gummybear +gummybear1 +gummybears +gumption +gunblade +gunbound +gundam00 +gundam01 +gundam123 +gundamseed +gundamwing +gungrave +gunit123 +gunner01 +gunner11 +gunner12 +gunner123 +gunners1 +gunslinger +gunsmoke +gunsnroses +gunther1 +gurpreet +guru1234 +guruguru +gurunanak +gusanito +gustavo1 +gustavo12 +gustavo123 +gutentag +gutierrez +gutierrez1 +gutschein +guwahati +guyg56fghf +guyssuck +guyssuck1 +guzel.t.f +gv5235523532 +gvinpinka123 +gvqjvxvb76 +gvqzvxub76 +gwada971 +gwapings +gwapo123 +gwapoako +gwarmonster +gwendoline +gwendolyn +gwendolyn1 +gwerty123 +gy3yt2rgls +gygypyfyyyposhy +gymnast1 +gymnastics +gypsy123 +gznybwf13 +h0llyw00d +h1234567 +h12345678 +h123456789 +h1992iding +h1xp2z2duk +h2vwdubjx4 +h36js3ggof +h3llokitty +h4hgaipgzu +h4t3cr3w +h87va5rtp6 +h97e7ijwwb +ha123456 +habbo123 +habitat1 +hacienda +hacked123 +hacker12 +hacker123 +hackers1 +hackthis1 +hadassah +hadouken +hagakure +haggard1 +haha1234 +haha12345 +hahabitch1 +hahaha11 +hahaha12 +hahaha123 +hahahaha +hahahaha1 +hahahahaha +hahahehe +hahalol1 +hailey01 +hailey03 +hailey04 +hailey05 +hailey06 +hailey07 +hailey08 +hailey11 +hailey12 +hailey123 +hailey13 +hailmary +hairball +hairball1 +haircut1 +hairdresser +hairspray +hairspray1 +haitian1 +hakkinen +hakunamatata +halamadrid +haleigh1 +haleluya +haley123 +halflife +halflife1 +halflife2 +halfmoon +halfpint +halfpint1 +halifax1 +hallelujah +hallihallo +halliwell +halliwell1 +hallmark +hallo123 +hallo1234 +hallo12345 +hallodu1 +halloduda +hallohallo +hallombn001 +halloween +halloween1 +halloween2 +halloween3 +hallucinationse +halo1234 +halo12345 +halo3odst +halo3rocks +halo3rules +halohalo +halohalo007 +haloreach +halowars +halowars1 +hamasaki +hambone1 +hamburg1 +hamburg15 +hamburger +hamburger1 +hamilton +hamilton1 +hammarby +hammer01 +hammer11 +hammer12 +hammer123 +hammer69 +hammerfall +hammerhead +hammers1 +hammertime +hammond1 +hammy123 +hampshire +hampster +hampster1 +hampton1 +hamradio +hamster1 +hamster12 +hamster123 +hamster2 +hamster3 +hamsters +hamsters1 +hamtaro1 +hamulakvitaly +hamza123 +hanahana +hanakimi +hancock1 +handball +handball1 +handicap +handsome +handsome1 +handyman +handyman1 +hangar18 +hanger18 +hangman1 +hangover +hanhphuc +hanihani +hanna123 +hannah00 +hannah01 +hannah02 +hannah03 +hannah04 +hannah05 +hannah06 +hannah07 +hannah08 +hannah09 +hannah10 +hannah101 +hannah11 +hannah12 +hannah123 +hannah1234 +hannah13 +hannah14 +hannah15 +hannah16 +hannah17 +hannah18 +hannah19 +hannah20 +hannah21 +hannah22 +hannah23 +hannah24 +hannah25 +hannah69 +hannah77 +hannah88 +hannah95 +hannah96 +hannah97 +hannah98 +hannah99 +hannahmont +hannahmontana +hannelore +hannibal +hannibal1 +hannover +hannover96 +hanover1 +hans4queck +hanshans +hansolo1 +hanspeter +hanswurst +hantu123 +hanuman1 +hanumanji +hao123456 +hapiness +happening +happines +happiness +happiness! +happiness1 +happiness2 +happiness7 +happy100 +happy101 +happy111 +happy123 +happy1234 +happy12345 +happy2007 +happy2008 +happy2009 +happy2010 +happy2011 +happy2be +happy2bme +happy2day +happy321 +happy420 +happy4ever +happy4me +happy777 +happybirth +happybirthday +happyboy +happybunny +happycat +happyday +happyday1 +happydays +happydays1 +happydog +happyface +happyface1 +happyfamily +happyfeet +happyfeet1 +happyfeet2 +happygirl +happygirl1 +happyhappy +happyhour +happylife +happylove +happyman +happyman1 +happyme1 +happyness +happyness1 +happynewyear +happyone +happytime +harajuku +harakiri +hardaway +hardball +hardbody1 +hardc0re +hardcock +hardcore +hardcore! +hardcore. +hardcore1 +hardcore12 +hardcore13 +hardcore2 +hardcore3 +hardcore4 +hardcore69 +hardcore7 +hardcore88 +harddick +hardhead +hardhead1 +harding1 +hardrock +hardrock1 +hardstyle +hardstyle1 +hardware +hardware1 +hardwood +hardwork +hardwork1 +hardy123 +harekrishna +harekrsna +harerama +hariharan +harlequin +harley00 +harley01 +harley02 +harley03 +harley04 +harley05 +harley06 +harley07 +harley08 +harley09 +harley10 +harley101 +harley11 +harley12 +harley123 +harley13 +harley14 +harley15 +harley17 +harley21 +harley22 +harley23 +harley24 +harley33 +harley55 +harley66 +harley69 +harley77 +harley88 +harley883 +harley95 +harley96 +harley97 +harley98 +harley99 +harleyd1 +harleydavidson +harleydog +harmonia +harmonica +harmonie +harmony1 +harmony2 +harmony7 +harold123 +harpreet +harriet1 +harrington +harris123 +harrison +harrison1 +harrison12 +harrison2 +harry123 +harry1234 +harrydog +harrypotte +harrypotter +harrypotter1 +harrystyles +harsh123 +harshini +harshita +hartford +hartford1 +hartmann +hartnett +harvard1 +harvest1 +harvey01 +harvey12 +harvey123 +harvick29 +has202020 +hasan123 +haslo123 +hassan12 +hassan123 +hastalavista +hastings +hastings1 +hatchet1 +hate2love +hatebreed +hatebreed1 +hatelife +hatelove +hatelove1 +hater123 +haters12 +haters123 +hateyou1 +hateyou2 +hatfield +hatteras +hattrick +haunted1 +haveaniceday +havefaith +havefaith1 +havefun1 +havingfun +hawaii01 +hawaii05 +hawaii06 +hawaii07 +hawaii08 +hawaii09 +hawaii11 +hawaii12 +hawaii123 +hawaii50 +hawaii808 +hawaii99 +hawaiian +hawaiian1 +hawk1020 +hawkesbury93 +hawkeye1 +hawkeyes +hawkeyes1 +hawkins1 +hawkwind +hawthorn +hawthorn1 +hawthorne +hawthorne1 +hayabusa +hayabusa1 +hayastan +hayden01 +hayden05 +hayden06 +hayden07 +hayden08 +hayden09 +hayden11 +hayden12 +hayden123 +hayleigh +hayley12 +hayley123 +hayward1 +hayward510 +hazel123 +hazeleyes +hazelnut +hbhc8290826 +hd764nw5d7e1vb1 +hdfcbank +he635789 +headache +headbanger +headhunter +headphones +headshot +headshot1 +headstrong +healing1 +healthcare +healthy1 +heart123 +heartagram +heartbeat +heartbeat1 +heartbreak +heartbreaker +heartbroke +heartbroken +heartland +heartless +heartless1 +hearts11 +hearts12 +hearts123 +hearts13 +heather! +heather. +heather01 +heather07 +heather08 +heather09 +heather1 +heather10 +heather11 +heather12 +heather123 +heather13 +heather14 +heather15 +heather16 +heather17 +heather18 +heather2 +heather21 +heather22 +heather23 +heather3 +heather4 +heather5 +heather6 +heather69 +heather7 +heather8 +heather9 +heatwave +heaven01 +heaven07 +heaven08 +heaven09 +heaven10 +heaven11 +heaven12 +heaven123 +heaven13 +heaven17 +heaven22 +heaven77 +heaven777 +heavenly +heavenly1 +heavensent +heavymetal +hebrides +heckfyxbr +hector12 +hector123 +hector13 +hedgehog +hedgehog1 +hedimaptfcorp +heeren981a +hehehaha +hehehe123 +hehehehe +heidelberg +heidi123 +heineken +heineken1 +heinlein +heinrich +heitor250493 +hejhej123 +hejhejhej +hejmeddig +hejsan123 +helen123 +helena123 +helga_557634 +helicopter +helikopter +hell0kitty +hellbound +hellboy1 +hellboy123 +hellboy2 +hellboy666 +hellfire +hellfire1 +hellgate +hellhell +hellhound +hello007 +hello100 +hello101 +hello111 +hello123 +hello1234 +hello12345 +hello2me +hello2u2 +hello2you +hello321 +hello456 +hello666 +hello777 +hello999 +helloall +hellobaby +hellodolly +hellogoodbye +hellohello +hellohi1 +hellokitty +hellokitty1 +hellokitty123 +helloman +hellomate +hellome1 +hellomoto +hellomoto1 +hellosimon +hellothere +helloween +helloworld +helloyou +helloyou1 +hellraiser +hellsbells +hellsing +hellsing1 +hellspawn +hellyea1 +hellyeah +hellyeah1 +help1234 +helpdesk +helphelp +helpme11 +helpme12 +helpme123 +helpmegod +helpmelord +helsinki +hemalatha +hemicuda +hemingway +hemmelig +henderson +henderson1 +hendrix1 +hendrix2 +hendrix69 +hennessy +hennessy1 +henni1907 +henrietta +henriette +henrique +henry123 +herbalife +herbalife1 +herbert1 +herbie53 +hercules +hercules1 +hereford +herewego +heriberto +heritage +heritage1 +herkules +hermann1 +hermanos +hermina617berno1990f6i +herminia +hermione +hermione1 +hermitage +hermosa1 +hernandez +hernandez1 +hernandez2 +hernando +herobrine +herohero +herohonda +herpderp +herrera1 +hershey1 +hershey12 +hershey123 +hershey2 +hershey3 +hershey7 +hersheys +heslo123 +hesloheslo +hesoyam1 +hesoyam123 +hester23 +heterosexual +hetfield +hevhk43n9j +hewlett1 +hey12345 +heybabe1 +heybaby1 +heydude1 +heygirl1 +heyhey11 +heyhey12 +heyhey123 +heyheyhey +heyheyhey1 +heyjude1 +heythere +heythere1 +hezekiah +hfcgbplzq +hfvd3425f +hgf4h3fhf +hgrfqg4577 +hgxnewx11 +hh123456 +hhhhhhhh +hhhhhhhhh +hhhhhhhhhh +hi123456 +hiawatha +hibernia +hibernian +hibiscus +hickory1 +hidalgo1 +higgins1 +highbury +highbury1 +highfive +highheel +highheels +highland +highland1 +highlander +highlands +highlife +highlife1 +highschool +highspeed +hightimes +hightimes1 +highway1 +highway61 +highwind +hihihi12 +hihihi123 +hihihihi +hihihihi1 +hijodeputa +hijoputa +hilaryduff +hildegard +hilfiger +hillary1 +hillbilly +hillbilly1 +hillcrest +hillcrest1 +hillside +hillside1 +hillsong +hilltop1 +hillview +himalaya +himanshu +himawari +hindustan +hindustani +hiphop01 +hiphop10 +hiphop101 +hiphop11 +hiphop12 +hiphop123 +hiphop13 +hiphop23 +hipolito +hipopotamo +hippo123 +hirondelle +hiroshima +hiroyuki +hisgrace +hismatdan +histoire +historia +history1 +history278 +hitachi1 +hitchcock +hithere1 +hitler123 +hitler666 +hitler88 +hitman11 +hitman12 +hitman123 +hitman23 +hitman47 +hitokiri +hitsugaya +hiuyt75f +hjcnbckfd +hjlbntkb +hjvfyjdf +hjvfynbrf +hlubkoj1 +hm9958123 +hoang123 +hoanganh +hobiecat +hochzeit +hockey00 +hockey01 +hockey07 +hockey08 +hockey09 +hockey10 +hockey101 +hockey11 +hockey12 +hockey123 +hockey13 +hockey14 +hockey15 +hockey16 +hockey17 +hockey18 +hockey19 +hockey20 +hockey21 +hockey22 +hockey23 +hockey24 +hockey25 +hockey26 +hockey27 +hockey28 +hockey29 +hockey30 +hockey31 +hockey33 +hockey35 +hockey44 +hockey55 +hockey66 +hockey69 +hockey77 +hockey87 +hockey88 +hockey89 +hockey91 +hockey97 +hockey99 +hocuspocus +hoffman1 +hoffmann +hoffnung +hogehoge +hogwarts +hogwarts1 +hohohoho +hoilamgi +hola1234 +hola12345 +hola123456 +holahola +holahola1 +holaquetal +holden01 +holden05 +holden123 +holdenv8 +holeinone +holiday1 +holiday123 +holiday2 +holidays +holidays1 +holidaysecure123 +holidaysecure123$ +holiness +holla123 +hollaback +hollaback1 +holland1 +holliday +hollie99 +hollister +hollister! +hollister. +hollister0 +hollister1 +hollister2 +hollister3 +hollister4 +hollister5 +hollister6 +hollister7 +hollister8 +hollister9 +holloway +hollowman +holly123 +hollydog +hollydog1 +hollywood +hollywood! +hollywood0 +hollywood1 +hollywood2 +hollywood3 +hollywood4 +hollywood5 +hollywood6 +hollywood7 +hollywood8 +hollywood9 +holstein +holuha00 +holybible +holybible1 +holycow1 +holycrap +holycrap1 +holycross +holyghost +holyghost1 +holyholy +holymoly +holysh!t +holyshit +holyshit! +holyshit1 +holyspirit +home0401 +home1234 +home12345 +homealone +homebase +homeboy1 +homebrew +homedepot +homedepot1 +homegirl +homegirl1 +homegrown +homehome +homeland +homeless +homeless1 +homelesspa +homepage +homer123 +homersimpson +homerun1 +homeschool +homeslice1 +homestar +homestar1 +homestead +homestead1 +homesweethome +hometown +hometown1 +homework +homework1 +homeworld +homie123 +homies13 +homosexual +honda100 +honda123 +honda1234 +honda125 +honda150 +honda2000 +honda250 +honda300 +honda400 +honda400ex +honda450 +honda450r +honda500 +honda600 +honda750 +hondaaccord +hondacbr +hondacity +hondacivic +hondacr125 +hondacr250 +hondacrv +hondacrx +hondas2000 +honduras +honduras1 +honduras12 +honesty1 +honey101 +honey123 +honey1234 +honey143 +honey215 +honeybabe +honeybaby +honeybear +honeybear1 +honeybee +honeybee1 +honeybun +honeybun1 +honeybunch +honeybunny +honeycoh +honeycomb +honeydew +honeydip1 +honeydog +honeygirl +honeygirl1 +honeyhoney +honeykoh +honeylove +honeymoon +honeypie +honeypot +honeywell +hongkong +hongkong1 +honolulu +honolulu1 +hoobastank +hoochie1 +hoodnigga1 +hoodrat1 +hoodrich1 +hoodstar1 +hooker69 +hooligan +hooligan1 +hooligans +hoosier1 +hoosiers +hoosiers1 +hooters1 +hooters2 +hooters69 +hoover74 +hope1234 +hopeful1 +hopefull +hopehope +hopeless +hopeless1 +hopewell +hopkins1 +hopscotch +horizon1 +horizons +hornet01 +hornet600 +hornets1 +horny123 +horse123 +horselover +horseman +horsepower +horses01 +horses10 +horses101 +horses11 +horses12 +horses123 +horses13 +horses22 +horseshit +horseshoe +horseshoe1 +hortense +hospital +hospital1 +hostmaster +hot2trot +hot97hot +hotbabe1 +hotbabes +hotbaby1 +hotbitch +hotbitch1 +hotboy12 +hotboy123 +hotboy23 +hotboys1 +hotboyz1 +hotcakes +hotchick +hotchick1 +hotchick12 +hotchicks +hotchicks1 +hotdog01 +hotdog11 +hotdog12 +hotdog123 +hotdog22 +hotdog23 +hotdog69 +hotdogs1 +hotgirl1 +hotgirl12 +hotgirl123 +hotgirl2 +hotgirls +hotgirls1 +hotgurl1 +hothothot +hotline1 +hotlips1 +hotmail. +hotmail.co +hotmail.com +hotmail1 +hotmail11 +hotmail12 +hotmail123 +hotmail2 +hotmail3 +hotmail5 +hotmail7 +hotmails +hotmama1 +hotmama12 +hotmama123 +hotmama2 +hotmamma +hotmamma1 +hotmomma +hotmomma1 +hotness1 +hotpants +hotpants1 +hotpink1 +hotpink2 +hotpocket1 +hotpussy +hotrod12 +hotrod123 +hotrod69 +hotsauce +hotsauce1 +hotsex69 +hotshit1 +hotshot1 +hotshots +hotstuff +hotstuff! +hotstuff1 +hotstuff10 +hotstuff12 +hotstuff2 +hotstuff69 +hottest1 +hottie#1 +hottie00 +hottie01 +hottie05 +hottie06 +hottie07 +hottie08 +hottie09 +hottie10 +hottie101 +hottie11 +hottie12 +hottie123 +hottie1234 +hottie13 +hottie14 +hottie15 +hottie16 +hottie17 +hottie18 +hottie19 +hottie20 +hottie21 +hottie22 +hottie23 +hottie24 +hottie25 +hottie27 +hottie33 +hottie34 +hottie44 +hottie45 +hottie4u +hottie55 +hottie69 +hottie88 +hottie911 +hottie92 +hottie93 +hottie94 +hottie95 +hottie99 +hotties1 +hottness +hottness1 +hottopic +hottopic1 +hottstuff +hottstuff1 +hotty101 +hotty123 +hotwater +hotwheels +hotwheels1 +hotwings +houdini1 +houghton +hounddog +hounddog1 +house123 +housemusic +housewife +houston1 +houston12 +houston123 +houston13 +houston2 +houston23 +houston281 +houston3 +houston5 +houston7 +houston713 +howard12 +howard123 +howareyou +howareyou1 +howareyou123 +howdy123 +hpg2n89qif +hph2n89qif +hppavilion +hrenota1 +hrustem65 +hrvatska +hs16andi3z +hshn7669 +htown713 +htt//members.cumfiesta.com/ +http://www +htubcnhfwbz +huang123 +huangfeisuny +huangjin1987 +huanhuan +hubbabubba +hubbard1 +hubertus +huckleberry +huf7dkgd +huggies1 +huggybear +hugo1234 +hugo854lataille1988 +hugoboss +hugoboss1 +hugohugo +huguette +huhbbhzu78 +hulaanmo +hulagirl +hulkhogan +hulkhogan1 +hulkster +hulkster1 +hullcity +hullcity1 +humanity +humanoid +humberto +humberto1 +humboldt +humility +hummer12 +hummer123 +hummer69 +hummerh1 +hummerh2 +hummerh3 +hummingbir +hummingbird +humphrey +humphrey1 +hunnybunny +hunter00 +hunter01 +hunter02 +hunter03 +hunter04 +hunter05 +hunter06 +hunter07 +hunter08 +hunter09 +hunter10 +hunter101 +hunter11 +hunter12 +hunter123 +hunter1234 +hunter13 +hunter14 +hunter15 +hunter16 +hunter17 +hunter18 +hunter19 +hunter20 +hunter21 +hunter22 +hunter23 +hunter24 +hunter25 +hunter26 +hunter27 +hunter28 +hunter33 +hunter44 +hunter45 +hunter55 +hunter66 +hunter666 +hunter69 +hunter77 +hunter88 +hunter89 +hunter94 +hunter95 +hunter96 +hunter97 +hunter98 +hunter99 +hunters1 +hunting1 +hunting101 +hunting12 +hunting123 +hunting2 +huntington +huntress +hurensohn +hurensohn1 +hurricane +hurricane1 +hurricane2 +hurricanes +husan0890 +husband1 +huskers1 +huskies1 +husqvarna +hussain1 +hustler1 +hustlin1 +hutchins +hutchinson +hvqjvxvb76 +hwriwxwc76 +hx28o9e646 +hyacinth +hyderabad +hydro420 +hydrogen +hyperion +hyperlite +hyperlite1 +hyphy101 +hysteria +hyundai1 +i<:3you +i.love.you +i1234567 +i123456789 +i18bzbk3ay8 +i234i234i234 +i4ifbinfyu +i5stwf1rcx +i84avh9lti +i97wb6sxq7 +i98xb7sxr7 +i_love_you +iam2cool +iamalone +iamawesome +iamblessed +iamcool! +iamcool1 +iamcool123 +iamcool2 +iamcrazy +iamgreat +iamhappy +iaminlove +iamlegend +iamlegend1 +iamlucky +iamnumber1 +iamsexy1 +iamsocool +iamsocool1 +iamthebest +iamthebest1 +iamtheking +iamtheman +iamtheman1 +iamtheone +iamtheone1 +iamwhatiam +ianuarie +ibanezjs +ibelieve +ibicguwjic +ibrahim1 +ibrahim123 +ibrahima +ibrahimovic +icandoit +icare123 +ice-cream +iceberg1 +icecold1 +icecream +icecream! +icecream. +icecream1 +icecream10 +icecream11 +icecream12 +icecream123 +icecream13 +icecream2 +icecream22 +icecream23 +icecream3 +icecream4 +icecream5 +icecream6 +icecream7 +icecream8 +icecream9 +icecube1 +icehockey +icehouse +icehouse1 +iceicebaby +iceland1 +iceman01 +iceman11 +iceman12 +iceman123 +iceman13 +iceman21 +iceman22 +iceman23 +iceman69 +icequeen +icewater +ichbincool +ichiro51 +ichliebedi +ichliebedich +ichunddu +icthus01 +icxkyb7972 +id6c3wr6un +iddqdidkfa +identity +idinahui +idiot123 +idlewild +idon'tknow +idontcare +idontcare1 +idonthave1 +idontknow +idontknow! +idontknow. +idontknow1 +idontknow2 +idontknow3 +idontno1 +idspispopd +ifeoluwa +iforget1 +iforgot! +iforgot1 +iforgot2 +iforgotit +ifuckyou1987 +ifycjyhekbn +ig4abox4 +igetmoney +igetmoney1 +igetmoney2 +iglesias +ignacio1 +ignatius +ignatova_1978_09 +ignition +ignoranto +igorek-filatov +igorigor +igot5onit +igromania +ihateboys +ihateboys1 +ihateher1 +ihatehim +ihatehim1 +ihatelife +ihatelife1 +ihatelove +ihatemen +ihatemen1 +ihatemylif +ihatemylife +ihatemyself +ihateschool +ihatethis +ihatethis1 +ihatethisgame +ihateu12 +ihateu123 +ihatey0u +ihateyou +ihateyou! +ihateyou. +ihateyou1 +ihateyou11 +ihateyou12 +ihateyou2 +ihateyou22 +ihateyou3 +ihateyou4 +ihateyou5 +ihateyou6 +ihateyou7 +ihateyou9 +ihave2kids +ihave3kids +ihave4kids +iheartu2 +iheartyou +iheartyou1 +iheartyou2 +iiiiiiii +iiiiiiiiii +ijfrnhf7yhcy54bhy0cd +ijrjkflrf +ikaa4kr257 +ikbengek +ike02banaa +ikechukwu +ikickass +ikillyou +il0v3y0u +il0vehim +il0vey0u +il0veyou +ilcerchio +ilds4edad +ilia16739 +ilikecheese +ilikeeggs +ilikegirls +ilikepie +ilikepie! +ilikepie1 +ilikepie12 +ilikepie123 +ilikepie2 +ilikesex +ilikeu123 +ilikeyou +ilikeyou1 +illinois +illinois1 +illmatic +illmatic1 +illuminati +illusion +illusion1 +illusions +ilmiocane +ilov3you +ilove... +ilove123 +ilove1234 +ilove143 +ilove420 +iloveaaron +iloveadam +iloveadam1 +ilovealex +ilovealex! +ilovealex1 +ilovealex2 +iloveallah +iloveallman +iloveamber +iloveamy +iloveamy1 +iloveandre +iloveandy +iloveandy1 +iloveangel +iloveanime +iloveanna +iloveanna1 +iloveash1 +iloveashle +iloveausti +ilovebeer +ilovebeer1 +iloveben +iloveben1 +ilovebill +ilovebilly +iloveblue +ilovebob +ilovebobby +iloveboobi +iloveboobs +iloveboys +iloveboys! +iloveboys1 +iloveboys2 +ilovebrad1 +ilovebrand +ilovebrian +ilovebritt +ilovebryan +ilovecake +ilovecandy +ilovecats +ilovecats1 +ilovechad +ilovechad1 +ilovecheese +ilovechris +ilovecock +ilovecock1 +ilovecody +ilovecody1 +ilovedad +ilovedad1 +ilovedaddy +ilovedan +ilovedan1 +ilovedance +ilovedanie +ilovedanny +ilovedave +ilovedave1 +ilovedavid +ilovedick +ilovedick1 +ilovedogs +ilovedogs1 +ilovedogs2 +ilovedylan +iloveemily +iloveemma +iloveeric +iloveeric1 +ilovefood +ilovefood1 +ilovegirls +ilovegod +ilovegod! +ilovegod1 +ilovegod12 +ilovegod2 +ilovegod7 +ilovegreen +ilovegreg +iloveher +iloveher! +iloveher1 +iloveher12 +iloveher2 +ilovehim +ilovehim! +ilovehim. +ilovehim08 +ilovehim09 +ilovehim1 +ilovehim10 +ilovehim11 +ilovehim12 +ilovehim13 +ilovehim14 +ilovehim2 +ilovehim22 +ilovehim23 +ilovehim3 +ilovehim4 +ilovehim5 +ilovehim7 +ilovehorses +iloveian +iloveindia +iloveit1 +ilovejack +ilovejack1 +ilovejacob +ilovejake +ilovejake1 +ilovejames +ilovejamie +ilovejason +ilovejay +ilovejay1 +ilovejeff +ilovejeff1 +ilovejen +ilovejen1 +ilovejenny +ilovejess +ilovejess1 +ilovejesse +ilovejessi +ilovejesus +ilovejim +ilovejimmy +ilovejoe +ilovejoe1 +ilovejoey +ilovejoey1 +ilovejohn +ilovejohn1 +ilovejon +ilovejon1 +ilovejorda +ilovejose +ilovejose1 +ilovejosh +ilovejosh! +ilovejosh1 +ilovejosh2 +ilovejuan1 +ilovejusti +ilovejustin +ilovekate +ilovekatie +ilovekayla +ilovekelly +ilovekevin +ilovekim +ilovekim1 +ilovekiss +ilovekyle +ilovekyle1 +ilovelaura +ilovelee +ilovelife +ilovelife1 +ilovelisa +ilovelisa1 +iloveliz1 +ilovelove +ilovelucy +ilovelucy1 +iloveluis +iloveluis1 +iloveluke +iloveluke1 +ilovemama +ilovemaria +ilovemark +ilovemark1 +ilovemary +ilovemary1 +ilovematt +ilovematt! +ilovematt1 +ilovematt2 +ilovemax +ilovemax1 +iloveme! +iloveme. +iloveme01 +iloveme08 +iloveme09 +iloveme1 +iloveme10 +iloveme101 +iloveme11 +iloveme12 +iloveme123 +iloveme13 +iloveme14 +iloveme15 +iloveme16 +iloveme18 +iloveme2 +iloveme21 +iloveme22 +iloveme23 +iloveme3 +iloveme4 +iloveme5 +iloveme6 +iloveme69 +iloveme7 +iloveme8 +iloveme9 +ilovemegan +ilovemen +ilovemen1 +ilovemicha +ilovemike +ilovemike! +ilovemike1 +ilovemike2 +ilovemom +ilovemom! +ilovemom1 +ilovemom12 +ilovemom2 +ilovemommy +ilovemoney +ilovemum +ilovemusic +ilovemybab +ilovemybaby +ilovemyboo +ilovemyboy +ilovemycat +ilovemydad +ilovemydog +ilovemyfam +ilovemyfamily +ilovemyindia +ilovemykid +ilovemykids +ilovemylif +ilovemylife +ilovemymom +ilovemymother +ilovemymum +ilovemysel +ilovemyself +ilovemysis +ilovemyson +ilovemyspa +ilovemywif +ilovemywife +ilovenick +ilovenick! +ilovenick1 +ilovenick2 +ilovenikki +iloveno1 +iloveny1 +ilovepat +ilovepaul +ilovepaul1 +ilovepie +ilovepie1 +ilovepink +ilovepink1 +ilovepizza +iloveporn +ilovepussy +ilovericky +iloverob +iloverob1 +iloverock +iloveryan +iloveryan! +iloveryan1 +ilovesam +ilovesam! +ilovesam1 +ilovesara +ilovesara1 +ilovesarah +ilovescott +ilovesean +ilovesean1 +ilovesex +ilovesex1 +ilovesex2 +ilovesex69 +iloveshane +iloveshawn +iloveshoes +ilovesocce +ilovesoccer +ilovesome1 +ilovesos +ilovesos1 +ilovesteph +ilovesteve +ilovetaylo +ilovethisgame +ilovetim +ilovetim1 +ilovetom +ilovetom1 +ilovetony +ilovetony1 +ilovetyler +iloveu01 +iloveu07 +iloveu08 +iloveu09 +iloveu10 +iloveu101 +iloveu11 +iloveu12 +iloveu123 +iloveu1234 +iloveu13 +iloveu14 +iloveu143 +iloveu15 +iloveu16 +iloveu17 +iloveu18 +iloveu21 +iloveu22 +iloveu23 +iloveu24 +iloveu4eva +iloveu4eve +iloveu69 +iloveu88 +iloveubaby +iloveumummy +iloveweed +iloveweed1 +ilovewill +ilovewill1 +ilovey0u +iloveyew +iloveyou +iloveyou! +iloveyou!! +iloveyou* +iloveyou. +iloveyou.. +iloveyou0 +iloveyou00 +iloveyou01 +iloveyou02 +iloveyou03 +iloveyou04 +iloveyou05 +iloveyou06 +iloveyou07 +iloveyou08 +iloveyou09 +iloveyou1 +iloveyou10 +iloveyou11 +iloveyou12 +iloveyou123 +iloveyou1234 +iloveyou13 +iloveyou14 +iloveyou143 +iloveyou15 +iloveyou16 +iloveyou17 +iloveyou18 +iloveyou19 +iloveyou2 +iloveyou20 +iloveyou21 +iloveyou22 +iloveyou23 +iloveyou24 +iloveyou25 +iloveyou26 +iloveyou27 +iloveyou28 +iloveyou29 +iloveyou3 +iloveyou30 +iloveyou31 +iloveyou32 +iloveyou33 +iloveyou34 +iloveyou4 +iloveyou42 +iloveyou44 +iloveyou45 +iloveyou4e +iloveyou4ever +iloveyou5 +iloveyou55 +iloveyou56 +iloveyou6 +iloveyou66 +iloveyou69 +iloveyou7 +iloveyou77 +iloveyou78 +iloveyou8 +iloveyou87 +iloveyou88 +iloveyou89 +iloveyou9 +iloveyou90 +iloveyou91 +iloveyou92 +iloveyou93 +iloveyou94 +iloveyou95 +iloveyou96 +iloveyou97 +iloveyou98 +iloveyou99 +iloveyou<3 +iloveyoual +iloveyouba +iloveyoubaby +iloveyouda +iloveyouf +iloveyoufo +iloveyouja +iloveyoujo +iloveyouma +iloveyoumo +iloveyouso +iloveyousomuch +iloveyouto +iloveyoutoo +iloveyouu +iloveyouu1 +iloveyoux3 +ilovezac1 +ilovezach +ilovezach1 +ilovezack1 +iluvchris1 +iluvgod1 +iluvher1 +iluvhim! +iluvhim1 +iluvhim2 +iluvjesus +iluvjesus1 +iluvme123 +iluvmlml +iluvmom1 +iluvmymom1 +iluvmyself +iluvsum1 +iluvu123 +iluvu4eva +iluvu4ever +iluvyou! +iluvyou1 +iluvyou2 +ily4ever +ilya_al_80 +imabeast +imabeast1 +imabitch +imabitch1 +imagination +imagine1 +imaloser +imaloser1 +imapimp1 +imaslut1 +imation1 +imawesome +imawesome1 +imbored1 +imcool12 +imcool123 +imgay123 +iminlove +iminlove1 +iminlove2 +imissyou +imissyou! +imissyou1 +imissyou2 +immaculate +immanuel +immortal +immortal1 +imnumber1 +impala64 +impalass +imperator +imperial +imperial1 +imperium +important +important1 +imposible +impossible +impression +impretty +impreza1 +impulse1 +impulse101 +imran123 +imrankhan +imsingle +imsocool +imsocool1 +imsofly1 +imsohood1 +imsohot1 +imsosexy +imthebest +imthebest1 +imtheman +imtheman1 +imtheone +imtheshit1 +imyaimyaimya +in2806rbk +inactive1996aug +incase322 +inception +inchallah +incognito +incognito1 +incoming +incomplete +incorrect +incorrect1 +increase +incredible +incubus1 +independen +independence +independent +independiente +index0088 +india123 +india1234 +india1947 +india321 +india@123 +indian12 +indian123 +indiana1 +indianajones +indianalib +indianer +indians1 +indochine +indonesia +indonesia1 +industrial +industry +indya123 +indya123d +ineedajob +ineedlove +ineedmoney +ineedyou +infamous +infamous1 +infantry +infantry1 +infected +infernal +inferno1 +inferno666 +infierno +infinite +infinite1 +infiniti +infiniti1 +infinito +infinity +infinity1 +infinity8 +infirmiere +inflames +inflames1 +infoinfo +informatica +informatika +informatio +information +informatique +infotech +ingeborg +ingegnere +ingenieria +ingeniero +ingenieur +inglaterra +inglewood +ingo10477 +ingoditrust +ingodwetrust +inibif47 +initiald +initiald09 +inkognito +inlinked +inlove07 +inlove08 +inlove09 +inlove12 +inlove123 +inlove13 +inlovewith +inmaculada +inmortal +innainna +innamorata +innocence +innocent +innocent1 +innocuous +innov8510 +innovation +innovision +innuendo +insanity +insanity1 +insecure +inshallah +insight1 +insignia +insomnia +insomnia1 +insomniac +inspector +inspector1 +inspiration +inspire1 +inspired +inspiron +inspiron1 +instant1 +instinct +institute +instructor +instrument +insurance +insurance1 +integra1 +integral +integrity +integrity1 +intel123 +inteligente +intelinside +intelligent +intense1 +inter123 +inter1908 +interdit +interest +interesting +interests +interface +interior +interiors +interista +intermilan +internacional +internal +internatio +international +internazionale +internet +internet! +internet. +internet01 +internet1 +internet11 +internet12 +internet123 +internet2 +internet3 +internet5 +internet7 +interpol +interpol1 +intheend +intimate +intranet +intrepid +intrepid1 +intrigue +intruder +intruder1 +intuition +inuyasha +inuyasha! +inuyasha. +inuyasha1 +inuyasha10 +inuyasha11 +inuyasha12 +inuyasha123 +inuyasha13 +inuyasha15 +inuyasha2 +inuyasha3 +inuyasha5 +inuyasha6 +inuyasha7 +invader1 +invaderzim +invasion +inventor +inverness +investment +investor +invictus +invincible +invisible +invisible1 +invu4uraqt +iopjkl12 +iphone123 +iphone3g +iphone3gs +iphone4s +ipodnano +ipodnano1 +ipodtouch +ipodtouch1 +ipswich1 +ira.klopot +ira202909 +ireland1 +ireland2 +ireland3 +ireland7 +irene123 +irfan123 +irina123 +irina280374 +irinabrig +irish123 +irishman +irochka-ova +irock101 +irock123 +ironfist +ironhead +ironhorse +ironmaiden +ironman1 +ironman12 +ironman123 +ironman2 +ironman3 +irule123 +isaac123 +isabel01 +isabel11 +isabel12 +isabel123 +isabel13 +isabel972 +isabela1 +isabelita +isabell1 +isabella +isabella01 +isabella07 +isabella08 +isabella09 +isabella1 +isabella10 +isabella11 +isabella12 +isabella13 +isabella2 +isabella3 +isabella4 +isabella5 +isabella7 +isabelle +isabelle1 +isaiah01 +isaiah05 +isaiah06 +isaiah07 +isaiah08 +isaiah11 +isaiah12 +isaiah123 +isaulov.a +iseedeadpeople +iseeyou2 +iskandar +iskander +islam123 +islamabad +islander +islander1 +islanders +islandgirl +islcollective +ismail123 +israel12 +israel123 +istanbul +istanbul1 +istanbul34 +isuckdick1 +itachi123 +italia06 +italia10 +italia2006 +italia90 +italian1 +italiana +italiano +italiano1 +italy123 +itdxtyrj +itiswell +itsallgood +itsasecret +itsme123 +itsmylife +itsover1 +ittybitty +ittybitty1 +iubireamea +iurkeawov +iuytrewq +ivan1234 +ivan1980 +ivan1989 +ivan1990 +ivan1991 +ivan1992 +ivan1993 +ivan1994 +ivan1995 +ivan1996 +ivan2010 +ivancito +ivanivan +ivankaterinchenko +ivanov2305 +ivanovamotya +ivanovich +iverson03 +iverson1 +iverson23 +iverson3 +ivor631996 +iw14fi9j +iw14fi9jwqa +iw14fi9jxl +iwantsex +iwantyou +iwantyou1 +iwashere +iwillwin +ixrhx2xc87 +izabella +izabella1 +j0nathan +j1234567 +j12345678 +j123456789 +j1v1fp2bxm +j38ifubn +j3nn1f3r +j3nnif3r +j3nnifer +j3qq4h7h2v +j4n4jel4 +j5644574 +j7777777 +j8675309 +ja123456 +ja8xb7txr8 +ja8yc7txs8 +ja8yc8uxsx +jabalpur +jabberwocky +jabroni1 +jabulani +jacaranda +jacinta1 +jack1234 +jack12345 +jack2000 +jack2005 +jack2006 +jack2007 +jack2008 +jack2009 +jack2010 +jack5225 +jackandjill +jackaroo +jackass! +jackass. +jackass01 +jackass1 +jackass101 +jackass11 +jackass12 +jackass123 +jackass13 +jackass2 +jackass22 +jackass23 +jackass3 +jackass4 +jackass5 +jackass69 +jackass7 +jackass9 +jackbauer +jackblack +jackblack1 +jackdaniel +jackdaniels +jackdog1 +jacket025 +jackets1 +jackfrost +jackhammer +jackie01 +jackie08 +jackie09 +jackie10 +jackie11 +jackie12 +jackie123 +jackie13 +jackie14 +jackie15 +jackie16 +jackie17 +jackie18 +jackie21 +jackie22 +jackie23 +jackie69 +jackiechan +jackjack +jackjack1 +jackjill +jackman1 +jackmore1 +jackoff1 +jackpot1 +jackrabbit +jackryan +jackson! +jackson. +jackson01 +jackson05 +jackson06 +jackson07 +jackson08 +jackson09 +jackson1 +jackson10 +jackson11 +jackson12 +jackson123 +jackson13 +jackson14 +jackson2 +jackson21 +jackson22 +jackson23 +jackson24 +jackson3 +jackson4 +jackson5 +jackson6 +jackson7 +jackson8 +jackson9 +jacksonville +jacksparrow +jackster +jacky123 +jacob101 +jacob123 +jacob1234 +jacobblack +jacqueline +jacques1 +jadakiss +jadakiss1 +jadawera +jade1234 +jadebibou +jadejade +jaden123 +jadensmith +jaejoong +jafjkshf7y6w34rjd +jagannath +jaguar12 +jaguar123 +jaguares +jaguars1 +jahbless +jaiganesh +jaigurudev +jaihanuman +jailbird +jailbird1 +jaimatadi +jaimatadi1 +jaimataki +jaime123 +jaisairam +jaishreeram +jaishriram +jaisriram +jajajaja +jakarta1 +jakarta10 +jake1234 +jake2000 +jake2006 +jake2008 +jake5253 +jakedog1 +jakejake +jakejake1 +jakester +jakester1 +jakeyboy +jalapeno +jalisco1 +jalisco13 +jamaica1 +jamaica12 +jamaica123 +jamaica2 +jamaica7 +jamaican +jamaican1 +jamal123 +jamboree +james007 +james101 +james111 +james123 +james1234 +james12345 +james143 +james2007 +james2008 +james2009 +james2010 +james420 +james666 +jamesbond +jamesbond0 +jamesbond007 +jamesbond1 +jamesbond7 +jamesbrown +jamesdean +jamesdean1 +jamesjames +jameslee +jameson1 +jamestown +jamezerazz +jamie123 +jamielee +jamielynn +jamieson +jamiroquai +jamison1 +jamrock1 +jamshedpur +janajana +jandikkz +jandre007 +jane1234 +janejane +janelle1 +janessa1 +janet123 +janette1 +janganlupa +janice123 +janiyah1 +janjanjan +jannaarhipova +jansport +jansport1 +january01 +january08 +january09 +january1 +january10 +january11 +january12 +january13 +january14 +january15 +january16 +january17 +january18 +january19 +january2 +january20 +january21 +january22 +january23 +january24 +january25 +january26 +january27 +january28 +january29 +january3 +january30 +january31 +january4 +january5 +january6 +january7 +january8 +january9 +japan123 +japanese +japanese1 +japanese92 +japierdole +jaqueline +jaqueline1 +jaramillo +jared123 +jaredleto +jaredleto1 +jarhead1 +jaroslav +jarox1301! +jarrett1 +jarrett88 +jasmin-ris +jasmin01 +jasmin11 +jasmin12 +jasmin123 +jasmin13 +jasmina1 +jasmine! +jasmine. +jasmine01 +jasmine02 +jasmine03 +jasmine04 +jasmine05 +jasmine06 +jasmine07 +jasmine08 +jasmine09 +jasmine1 +jasmine10 +jasmine101 +jasmine11 +jasmine12 +jasmine123 +jasmine13 +jasmine14 +jasmine15 +jasmine16 +jasmine17 +jasmine18 +jasmine19 +jasmine2 +jasmine20 +jasmine21 +jasmine22 +jasmine23 +jasmine24 +jasmine29 +jasmine3 +jasmine4 +jasmine5 +jasmine6 +jasmine69 +jasmine7 +jasmine8 +jasmine9 +jasmine99 +jason101 +jason123 +jason1234 +jason143 +jason420 +jasonjason +jasonlee +jasper01 +jasper08 +jasper09 +jasper10 +jasper11 +jasper12 +jasper123 +jasper13 +jasper21 +jasper22 +jasper23 +jasper99 +jaspreet +jaspyb1990 +javajava +javier01 +javier10 +javier11 +javier12 +javier123 +javier13 +javier15 +javier23 +jaw138whet330 +jawbreaker +jay12345 +jayanthi +jayashree +jayasree +jaybird1 +jayden01 +jayden02 +jayden03 +jayden04 +jayden05 +jayden06 +jayden07 +jayden08 +jayden09 +jayden10 +jayden11 +jayden12 +jayden123 +jayden13 +jayden21 +jayden22 +jayden23 +jayhawk1 +jayhawks +jayhawks1 +jayjay01 +jayjay10 +jayjay11 +jayjay12 +jayjay123 +jayjay13 +jayjay14 +jayjay22 +jayjay23 +jaylynn1 +jaymataji +jayshree +jazmin12 +jazmin123 +jazmine1 +jazmine2 +jazz1234 +jazzbass +jazzjazz +jazzman1 +jazzmin1 +jazzmine +jazzmine1 +jazzy101 +jazzy123 +jb123456 +jbgr3v7n3b +jbond007 +jc123456 +jcdenis1 +jcfs32014 +jd123456 +jdd04257 +jdnazp972x +jdq4j8lu3a +jealous1 +jean1234 +jeancarlos +jeanclaude +jeanette +jeanette1 +jeanine1 +jeanjean +jeanlouis +jeanmarc +jeanmarie +jeannette +jeannette1 +jeannie1 +jeannine +jeanpaul +jeanpierre +jedidiah +jediknight +jedimaster +jeepers1 +jeepjeep +jeepster +jeetkunedo +jeferson +jeff1234 +jefferson +jefferson1 +jefferson2 +jeffery1 +jeffgordon +jeffhardy +jeffhardy1 +jeffhardy2 +jeffjeff +jeffrey1 +jeffrey12 +jeffrey123 +jeffrey2 +jeffrey3 +jeffrey7 +jehovah1 +jehovah7 +jeka-ka85 +jekan860803 +jello123 +jelly123 +jellybaby +jellybean +jellybean! +jellybean1 +jellybean2 +jellybean3 +jellybean7 +jellybeans +jellybelly +jellyfish +jellyfish1 +jellytots +jemoeder +jemoeder1 +jenifer1 +jeniffer +jenkins1 +jenn1fer +jenn5366 +jenna123 +jenni123 +jennifer +jennifer! +jennifer. +jennifer01 +jennifer07 +jennifer08 +jennifer09 +jennifer1 +jennifer10 +jennifer11 +jennifer12 +jennifer123 +jennifer13 +jennifer14 +jennifer15 +jennifer16 +jennifer17 +jennifer18 +jennifer19 +jennifer2 +jennifer20 +jennifer21 +jennifer22 +jennifer23 +jennifer24 +jennifer25 +jennifer3 +jennifer4 +jennifer5 +jennifer6 +jennifer69 +jennifer7 +jennifer8 +jennifer88 +jennifer9 +jennings +jennings1 +jennjenn +jenny101 +jenny123 +jenny1234 +jennyfer +jennylyn +jeopardy +jeremiah +jeremiah1 +jeremiah12 +jeremiah2 +jeremiah29 +jeremiah2911 +jeremiah3 +jeremiah7 +jeremias +jeremy01 +jeremy06 +jeremy07 +jeremy08 +jeremy09 +jeremy10 +jeremy11 +jeremy12 +jeremy123 +jeremy13 +jeremy14 +jeremy15 +jeremy16 +jeremy17 +jeremy18 +jeremy21 +jeremy22 +jeremy23 +jeremy24 +jeremy69 +jericho1 +jerkface +jerkface1 +jerkoff1 +jermaine +jermaine1 +jerome12 +jerome123 +jeronimo +jerrey232x +jerry123 +jerrylee +jersey12 +jerseygirl +jerusalem +jerusalem1 +jesaispas +jess1234 +jess5377 +jesse101 +jesse123 +jesse1234 +jessejames +jessi123 +jessica! +jessica. +jessica0 +jessica00 +jessica01 +jessica02 +jessica03 +jessica04 +jessica05 +jessica06 +jessica07 +jessica08 +jessica09 +jessica1 +jessica10 +jessica101 +jessica11 +jessica12 +jessica123 +jessica13 +jessica14 +jessica15 +jessica16 +jessica17 +jessica18 +jessica19 +jessica2 +jessica20 +jessica21 +jessica22 +jessica23 +jessica24 +jessica25 +jessica26 +jessica27 +jessica28 +jessica3 +jessica33 +jessica4 +jessica5 +jessica6 +jessica69 +jessica7 +jessica77 +jessica8 +jessica87 +jessica88 +jessica89 +jessica9 +jessica90 +jessica91 +jessica92 +jessica93 +jessica94 +jessica95 +jessica99 +jessie01 +jessie07 +jessie08 +jessie09 +jessie10 +jessie11 +jessie12 +jessie123 +jessie13 +jessie14 +jessie15 +jessie16 +jessie21 +jessie22 +jessie23 +jessie69 +jessika1 +jessjess +jessy123 +jesucristo +jesuisla +jesus001 +jesus007 +jesus100 +jesus101 +jesus111 +jesus123 +jesus1234 +jesus12345 +jesus143 +jesus1st +jesus2000 +jesus2006 +jesus2007 +jesus2008 +jesus2009 +jesus2010 +jesus2011 +jesus247 +jesus316 +jesus333 +jesus4ever +jesus4life +jesus4me +jesus666 +jesus777 +jesuschris +jesuschrist +jesuschrist1 +jesuscrist +jesuscristo +jesusfreak +jesusgod +jesusis#1 +jesusis1 +jesusislor +jesusislord +jesusislove +jesusito +jesusjesus +jesuslives +jesuslord +jesuslove +jesuslove1 +jesusloveme +jesusloves +jesuslovesme +jesusmary +jesusmeama +jesusrocks +jesusrules +jesussaves +jesusteama +jesusteamo +jet'aime +jetaime1 +jetbalance +jetsmets +jettavr6 +jewel123 +jewelry1 +jezebel1 +jfgvcqbuzug +jg3h4hfn +jgordon24 +jgthfnjh +jh5thrwgefsdfs +jhonatan +jhoncena +jhonjhon +ji394su3 +jianfei000 +jiang520 +jiang8kevin +jianjian +jibopogie +jiefang007 +jiefang998 +jiggaman +jiggaman1 +jigglypuff +jilipollas +jillian1 +jillybean +jimbeam1 +jimbo123 +jimboy123 +jimenez1 +jimihendrix +jimjones +jimjones1 +jimmie48 +jimmorrison +jimmy123 +jimmy1234 +jimmyboy +jimmyjimmy +jimmypage +jingjing +jingles1 +jinkazama +jitendra +jitterbug +jitterbug1 +jiujitsu +jiujitsu1 +jiushiaini +jj123456 +jjcg16dj5k +jjjjjjjj +jjjjjjjjj +jjjjjjjjjj +jk123456 +jkiuztdftl57 +jktctymrf +jlbyjxrf +jlbyjxtcndj +jledfyxbr +jm123456 +jmfxl78nhe +jmfxl78phe +jnkwear1 +joaninha +joanna12 +joanna123 +joanne123 +joaopaulo +joaopedro +joaovitor +joaquin1 +jobsearch +jobsearch1 +jobseeker +jobshop2002 +jocelyn1 +jocelyne +jodie123 +joe12345 +joeblack +joeboxer +joecool1 +joedirt1 +joejoe12 +joejoe123 +joejoejoe +joejonas +joejonas! +joejonas1 +joejonas12 +joejonas2 +joel1234 +joelmadden +joemalyn15 +joemama1 +joey1234 +joeyjoey +jogabonito +johan123 +johanna1 +johannes +johannes1 +john!20130605at1753 +john0316 +john1010 +john1234 +john12345 +john123456 +john2567 +john3:16 +john5646 +john7502gee +johnathan +johnathan1 +johnathon +johnathon1 +johnboy1 +johncarlo +johncena +johncena! +johncena01 +johncena1 +johncena10 +johncena11 +johncena12 +johncena13 +johncena2 +johncena23 +johncena3 +johncena5 +johncena54 +johncena7 +johncena8 +johncena9 +johndavid +johndeer +johndeer1 +johndeere +johndeere1 +johndeere2 +johndoe1 +johngalt +johnjohn +johnjohn1 +johnlennon +johnlock +johnmark +johnmayer +johnnie1 +johnny01 +johnny07 +johnny08 +johnny10 +johnny11 +johnny12 +johnny123 +johnny13 +johnny14 +johnny15 +johnny16 +johnny18 +johnny1959 +johnny21 +johnny22 +johnny23 +johnny55 +johnny69 +johnny77 +johnny99 +johnnyboy +johnnyboy1 +johnnycash +johnnydepp +johnpaul +johnpaul1 +johnsmith +johnson1 +johnson11 +johnson12 +johnson123 +johnson2 +johnson3 +johnson4 +johnson48 +johnson5 +johnson7 +johnston +johnston1 +johnwayne +johnwayne1 +jojo1234 +jojojojo +joker007 +joker101 +joker123 +joker1234 +joker420 +joker666 +joker777 +jokerjoker +jokerman +jolinek33 +jollibee +jolly123 +jollyroger +jomacapa +jonas101 +jonas123 +jonasbros1 +jonasbroth +jonasbrothers +jonathan +jonathan! +jonathan. +jonathan01 +jonathan07 +jonathan08 +jonathan09 +jonathan1 +jonathan10 +jonathan11 +jonathan12 +jonathan123 +jonathan13 +jonathan14 +jonathan15 +jonathan16 +jonathan17 +jonathan18 +jonathan19 +jonathan2 +jonathan20 +jonathan21 +jonathan22 +jonathan23 +jonathan3 +jonathan4 +jonathan5 +jonathan6 +jonathan69 +jonathan7 +jonathan8 +jonathan9 +jonathon +jonathon1 +jonbonjovi +jones123 +jongjong +jonny123 +jonnyboy +jopajopa +jor23dan +jordan00 +jordan01 +jordan02 +jordan03 +jordan04 +jordan05 +jordan06 +jordan07 +jordan08 +jordan09 +jordan10 +jordan101 +jordan11 +jordan12 +jordan123 +jordan1234 +jordan13 +jordan14 +jordan15 +jordan16 +jordan17 +jordan18 +jordan19 +jordan20 +jordan21 +jordan22 +jordan23 +jordan2323 +jordan2345 +jordan24 +jordan25 +jordan26 +jordan27 +jordan28 +jordan29 +jordan32 +jordan33 +jordan34 +jordan44 +jordan45 +jordan55 +jordan69 +jordan77 +jordan88 +jordan89 +jordan90 +jordan91 +jordan92 +jordan93 +jordan94 +jordan95 +jordan96 +jordan97 +jordan98 +jordan99 +jordans1 +jordans23 +jorden23 +jordon23 +jorge123 +jorgeluis +jorgito1 +jose1234 +jose12345 +jose123456 +jose1995 +joseangel +joseantonio +josecarlos +josefina +josefina1 +josefine +josejose +joselito +joselito1 +joseluis +joseluis1 +joselyn1 +josemanuel +josemaria +josemiguel +joseph00 +joseph01 +joseph02 +joseph03 +joseph04 +joseph05 +joseph06 +joseph07 +joseph08 +joseph09 +joseph10 +joseph11 +joseph12 +joseph123 +joseph1234 +joseph13 +joseph14 +joseph15 +joseph16 +joseph17 +joseph18 +joseph19 +joseph20 +joseph21 +joseph22 +joseph23 +joseph24 +joseph25 +joseph69 +joseph77 +joseph88 +joseph89 +joseph99 +josephine +josephine1 +josesito +josette1 +josh1234 +joshjosh +joshua00 +joshua01 +joshua02 +joshua03 +joshua04 +joshua05 +joshua06 +joshua07 +joshua08 +joshua09 +joshua10 +joshua11 +joshua12 +joshua123 +joshua1234 +joshua13 +joshua14 +joshua15 +joshua16 +joshua17 +joshua18 +joshua19 +joshua20 +joshua21 +joshua22 +joshua23 +joshua24 +joshua25 +joshua26 +joshua27 +joshua28 +joshua69 +joshua77 +joshua88 +joshua89 +joshua95 +joshua96 +joshua97 +joshua98 +joshua99 +josie123 +josue123 +journalist +journey1 +joyce123 +joystick +jp123456 +jp72l05w +jr123456 +jr1234567 +jrcfyjxrf +js123456 +juan1234 +juancamilo +juancarlos +juancito +juandavid +juandiego +juanita1 +juanito1 +juanjose +juanjuan +juanluis +juanmanuel +juanmiguel +juanpablo +juanpablo1 +jubilee1 +judaspriest +judgement +juggalette +juggalo1 +juggalo123 +juggalo13 +juggalo17 +juggalo2 +juggalo420 +juggalo6 +juggalo666 +juggalo69 +juggernaut +jughead1 +juice123 +juicebox +juicebox1 +juicy123 +juicyfruit +juju1987 +jujubean +jujubee1 +jujujuju +jujuvivi +jukebox1 +julia.olga +julia123 +julia_eduardovna +juliadronina1996 +juliajulia +julian01 +julian05 +julian06 +julian07 +julian08 +julian09 +julian10 +julian11 +julian12 +julian123 +julian13 +julian14 +julian15 +julian1705 +julian22 +julian23 +juliana1 +juliana123 +julianna +julianna1 +julianne +julianne1 +julie123 +julie2811 +julieann +julieanne +julienne +juliet123 +julieta1 +julietta +juliette +juliette1 +julija2010x +julio123 +juliocesar +julissa1 +julius123 +july0788 +july1980 +july1982 +july1983 +july1984 +july1985 +july1986 +july1987 +july1988 +july1989 +july1990 +july1991 +july1992 +july1993 +july1994 +july1995 +july1996 +july1997 +july2004 +july2005 +july2006 +july2007 +july2008 +july2009 +july2801! +jumanji1 +jump4joy +jumping1 +jumpjump +jumpman1 +jumpman23 +jumpoff1 +jumpstart +jumpstyle +junction +jundian2011xr +june1979 +june1980 +june1981 +june1982 +june1983 +june1984 +june1985 +june1986 +june1987 +june1988 +june1989 +june1990 +june1991 +june1992 +june1993 +june1994 +june1995 +june1996 +june1997 +june1998 +june1999 +june2000 +june2002 +june2003 +june2004 +june2005 +june2006 +june2007 +june2008 +june2009 +june2010 +junebug1 +junebug2 +junejune +jungfrau +junglist +junior00 +junior01 +junior02 +junior03 +junior04 +junior05 +junior06 +junior07 +junior08 +junior09 +junior10 +junior11 +junior12 +junior123 +junior1234 +junior13 +junior14 +junior15 +junior16 +junior17 +junior18 +junior19 +junior20 +junior21 +junior22 +junior23 +junior24 +junior25 +junior26 +junior27 +junior28 +junior33 +junior420 +junior69 +junior77 +junior88 +junior99 +juniper1 +junkfood +junkjunk +junkmail +junkmail1 +junkyard +junkyard1 +jupiter1 +jupiter2 +jupiter5 +jupiter7 +jurassic +jurassic5 +just4fun +just4now +just4you +justblaze1 +justdance +justdoit +justdoit1 +justforfun +justforme +justforyou +justice01 +justice1 +justice11 +justice12 +justice123 +justice2 +justice3 +justice4 +justice7 +justicia +justin00 +justin01 +justin02 +justin03 +justin04 +justin05 +justin06 +justin07 +justin08 +justin09 +justin10 +justin101 +justin11 +justin12 +justin123 +justin1234 +justin13 +justin14 +justin15 +justin16 +justin17 +justin18 +justin19 +justin20 +justin21 +justin22 +justin23 +justin24 +justin25 +justin26 +justin27 +justin28 +justin31 +justin33 +justin69 +justin77 +justin87 +justin88 +justin89 +justin91 +justin92 +justin94 +justin95 +justin96 +justin97 +justin98 +justin99 +justina1 +justinbeib +justinbibe +justinbieb +justinbieber +justincase +justindrew +justine1 +justine123 +justinlove +justintime +justlooking +justlove +justme12 +justme123 +justyna1 +justynka +juvenile +juvenile1 +juventini +juventino +juventus +juventus1 +juventus10 +jxsgx2yd87 +jysgy2yd87 +jza90supra +k.,k.nt,z +k1234567 +k12345678 +k123456789 +k1k2k3k4 +k1mberly +k2010302 +k25061405u +k3zechmext +k3zedhmexs +k43a5vztox +k47rizxt2g +k7777777 +k9g2xpce1e +ka_djkhjsy6 +kabouter +kacper123 +kacperek +kadence1 +kafedra_oisp +kagandahan +kahitano +kahraman +kaibigan +kaifer124 +kaitlin1 +kaitlyn1 +kaitlyn12 +kaitlyn123 +kaitlyn2 +kaitlyn3 +kaitlyn7 +kaitlynn +kaitlynn1 +kaka1234 +kakakaka +kakaroto +kakashi1 +kakashi12 +kakashi123 +kakashi21 +kakashka +kakka123 +kalafior +kalamata +kalamazoo +kalambur +kalashnikov +kaleb123 +kaleigh1 +kalender +kalhonaho +kaliber44 +kalifornia +kaligula +kalimantan +kalimera +kalimero +kalinina +kaliningrad +kalle123 +kalleanka +kamal123 +kamasutra +kamasutra1 +kamazist.tsobenko +kambing1 +kamehameha +kameleon +kamenrider +kameron1 +kamikadze +kamikaze +kamikaze1 +kamikazee +kamil123 +kamil555 +kamilek1 +kamiloza +kamisama +kamogelo +kanchana +kandice1 +kangar00 +kangaroo +kangaroo1 +kangaroo2 +kangaroos +kangkang +kangourou +kanishka +kansascity +kantutan +kanyewest +kanyewest1 +kapej111 +kappa1911 +kara2711 +karachi1 +karachi123 +karadeniz +karaganda +karakartal +karamelka +karan123 +karandash +karaoke1 +karappinha +karate12 +karate123 +karatedo +karateka +karatekid +karatekid1 +kardelen +karebear +karebear1 +karen123 +karencita +karenina +karim123 +karina01 +karina10 +karina11 +karina12 +karina123 +karina13 +karina14 +karina15 +karine73 +karishma +karissa1 +karla123 +karlita1 +karlitos +karlmarx +karma123 +karnataka +karol123 +karolcia +karolina +karolina1 +karoline +karolinka +karolinka1 +karpenko +kartal1903 +karthick +karthika +kartoffel +kartoffelpuffer +kartoshka +karukera +karusev_spb +kasabian +kasablanka +kasandra +kasandra1 +kasey123 +kashmir1 +kashmoney1 +kasia123 +kasiunia +kasparov +kasper123 +kaspersky +kassandra +kassandra1 +kassidy1 +katalina +katarina +katarina1 +katarzyna +katarzyna1 +katasandi +katastrofa +kate1234 +katekate +katelyn1 +katelyn12 +katelyn2 +katelynn +katelynn1 +katerina +katerina1 +katerine +katerinka +katharina +katharina1 +katharine +katherin +katherine +katherine0 +katherine1 +katherine2 +katherine3 +katherine7 +kathleen +kathleen1 +kathleen12 +kathmandu +kathmandu1 +kathrina +kathrine +kathryn1 +kathy123 +kati-leva +katie101 +katie123 +katie1234 +katiebug +katiebug1 +katmandu +katrina1 +katrina12 +katrina123 +katrina2 +katrinka +katushka +katya123 +katyakatya +katyperry +katyusha +kaulitz1 +kaulitz89 +kawasaki +kawasaki1 +kawasaki12 +kawasaki7 +kayaking +kaydence +kaydence1 +kaydenlee +kaykay12 +kaykay123 +kayla101 +kayla123 +kayla1234 +kaylee01 +kaylee06 +kaylee07 +kaylee08 +kaylee11 +kaylee12 +kaylee123 +kayleigh +kayleigh1 +kaylynn1 +kayseri38 +kazakhstan +kazakova +kazanova +kazantip +kb9zc8uxtx +kbnthfnehf +kbpfdtnf +kcchiefs +kdwcnpa362 +keebler1 +keepit100 +keepitreal +keepout1 +keepout8 +keepsmiling +keerthana +kehinde1 +keineahnung +keith123 +kelantan +kelly101 +kelly123 +kelly1234 +kellyann +kellykelly +kelsey01 +kelsey10 +kelsey11 +kelsey12 +kelsey123 +kelsey13 +kelsey14 +keluarga +kelvin123 +kendall1 +kendall2 +kendra12 +kendra123 +kendrick +kendrick1 +kennedi1 +kennedy1 +kennedy12 +kennedy123 +kennedy2 +kenneth1 +kenneth12 +kenneth123 +kenneth2 +kenneth3 +kenneth7 +kennwort +kennwort1 +kenny123 +kenseth17 +kenshi21 +kenshin1 +kenshiro +kensington +kentucky +kentucky1 +kenwood1 +kenworth +kenworth1 +kenyatta +kenyatta1 +kenzie11 +kenzie12 +kenzie123 +kenzie14 +kepompong +kerberos +kerrigan +kerry123 +kerstin1 +keshawn1 +ketchup1 +kevin101 +kevin123 +kevin1234 +kevin12345 +kevinbg01 +kevnwo128 +keyblade +keyblade1 +keyboard +keyboard1 +keyshawn +keystone +keystone1 +keywest1 +kfcnjxrf +kfvgjxrf +khadija1 +khadijah +khalid123 +khan1234 +khankhan +khongbiet +khongnho +khuljasimsim +khushboo +kiara123 +kibbles1 +kickass! +kickass1 +kickass123 +kickass2 +kickball +kickboxer +kickboxing +kickflip +kickflip1 +kidrock1 +kids1234 +kidskids +kiekeboe +kieran123 +kiersten +kiersten1 +kifj9n7bfu +kikakika +kikelomo +kikeunyw +kiki1234 +kikikiki +kikimora +kikiriki +kikokiko +kikugalanetroot +kikumaru +kilimanjaro +kilkenny +kill1234 +killa123 +killa187 +killacam +killacam1 +killall1 +killbill +killbill1 +killbill2 +killemall +killemall1 +killer00 +killer007 +killer01 +killer07 +killer08 +killer09 +killer10 +killer100 +killer101 +killer11 +killer12 +killer123 +killer1234 +killer12345 +killer13 +killer14 +killer15 +killer16 +killer17 +killer18 +killer187 +killer19 +killer20 +killer21 +killer22 +killer23 +killer24 +killer25 +killer27 +killer321 +killer33 +killer34 +killer420 +killer44 +killer45 +killer55 +killer56 +killer66 +killer666 +killer69 +killer77 +killer777 +killer78 +killer87 +killer88 +killer89 +killer90 +killer91 +killer911 +killer92 +killer93 +killer94 +killer95 +killer96 +killer98 +killer99 +killerbee +killerbee1 +killerboy +killerin66 +killerman +killerman1 +killers1 +killers123 +killers2 +killian1 +killing1 +killjoy1 +killkill +killkill1 +killme123 +killme666 +killmenow +killswitch +killyou1 +killzone +killzone1 +killzone2 +kilokilo +kim12345 +kimber45 +kimberley +kimberley1 +kimberly +kimberly01 +kimberly1 +kimberly10 +kimberly11 +kimberly12 +kimberly13 +kimberly2 +kimberly3 +kimberly5 +kimberly7 +kimerald +kimikimi +kimmy123 +kinderen +kindergarten +kindness +king1234 +king12345 +king123456 +king4life +kingarthur +kingcobra +kingdavid +kingdom1 +kingdom12 +kingdom123 +kingdom2 +kingdom7 +kingdomhea +kingdomhearts +kingdomhearts2 +kingfish +kingfish1 +kingfish11 +kingfisher +kingjames +kingjames1 +kingjames2 +kingjames23 +kingkhan +kingking +kingking1 +kingkong +kingkong1 +kingkong12 +kingkong2 +kinglove +kinglove1 +kinglove5 +kingmaker +kingman1 +kingofking +kingofkings +kingofpop +kingpin1 +kings123 +kingsize +kingsley +kingsley1 +kingston +kingston1 +kingston12 +kingsway +kingswood +kingtut1 +kinomoto89 +kinshasa +kinyabuzova.eleonora +kir-ettk +kirakira +kiran123 +kirankumar +kirby123 +kirienko_svetlana +kirik26trimyasov +kirill.kirillov.2013 +kirill123 +kirill1990 +kirill1998 +kirill999_97 +kirkland +kirkland1 +kirkwood +kirsten1 +kirstie1 +kirstin1 +kisakisa +kiska123 +kiss1234 +kiss1947 +kissa123 +kissable +kissarmy +kissass1 +kisses01 +kisses11 +kisses12 +kisses123 +kisses13 +kisses22 +kisses23 +kisses4u +kisses69 +kissing1 +kisskiss +kisskiss1 +kisskiss12 +kisskiss2 +kisslove +kissme11 +kissme12 +kissme123 +kissme13 +kissme22 +kissme23 +kissme69 +kissmebaby +kissmoko +kissmyass +kissmyass! +kissmyass1 +kissmyass2 +kissthis +kissthis1 +kitchen1 +kitesurf +kitkat11 +kitkat12 +kitkat123 +kitkat13 +kitsune1 +kitten01 +kitten10 +kitten11 +kitten12 +kitten123 +kitten13 +kitten22 +kitten69 +kittens1 +kittens12 +kittens123 +kittens2 +kittens3 +kitties1 +kitties2 +kittiwake +kitty101 +kitty123 +kitty1234 +kitty666 +kittycat +kittycat! +kittycat1 +kittycat12 +kittycat2 +kittycat3 +kittygirl +kittykat +kittykat1 +kittykat12 +kittykat2 +kittykitty +kittylove +kiwikiwi +kjhgfdsa +kjkszpj1 +kjrjvjnbd +kk123456 +kkkkkkkk +kkkkkkkkk +kkkkkkkkkk +kl098709 +kl123456 +klaipeda +klapaucius +klaudia01 +klaudia1 +kleenex1 +kleopatra +klimenko +klinger1 +klingon1 +klondike +klondike1 +klootzak +klopklop +klubnichka +klubnika +kluivert +kmzwa8awaa +kmzway87aa +knackwurst8853 +knickers +knicks33 +knight01 +knight11 +knight12 +knight123 +knightrider +knights1 +knitting +knockers +knockknock +knockout +knockout1 +knopo4ka +knopochka +knowledge +knowledge1 +knoxville +knoxville1 +knuckles +knuckles1 +koala123 +koala_1995 +koalabear +kobayashi +kobebryant +kobebryant24 +kochamcie +kochamcie1 +kochanie +kochanie1 +kodabear +kodaira523 +kohinoor +kokakola +koko1234 +kokokoko +kokoloko +kokopelli +kokowawa +kolakola +kolawole +kolejorz +kolesnik +kolkol90 +kolokolo +kolovrat +komarova +komltptfcorp +komnatnyy88 +kompages4u +komputer +komputer1 +komputer12 +konakona +konfetina-kis +konfetka +kongkong +konichiwa +konnichiwa +konstantin +kontol123 +kool-aid +kool1234 +koolaid1 +koolaid2 +kooldude +koolkat1 +koolkid1 +koolkool +koolsavas +kopa1961 +kopernik +kopretina +korn1234 +kornelia +kornkorn +korokozabr +koroleva +korostelev_3333 +koshechka +kosova123 +kostroma +koteczek +kotikova_n_m +kotkova37 +kotmichanik +kotopes_o +kotova.69 +kotova_74 +kotovam85 +kotovas-70 +kotovichvalentina +kottayam +kotya_bagdan +koupelna +kourtney +kourtney1 +kovalenko +kovaleva +kovalevagn2057 +kovalienko63 +kovalskaya-t +kovrnatasha +kovshikova1981 +kowalski +kp9v1ro7lh +kpkp1ee9w +kr6sjhs412 +kraftwerk +krasavchik +krasavica +krasnodar +krasotka +kravchenko +kretsaha53 +krick.bk +kris1234 +krish123 +krishana +krishna1 +krishna123 +krishnaa +krishnan +kristal1 +kristall +kristen1 +kristen12 +kristen123 +kristen2 +kristen3 +kristen7 +kristian +kristian1 +kristie1 +kristin1 +kristina +kristina1 +kristina12 +kristina2 +kristine +kristine1 +kristinka +kristofer +kristoffer +kristopher +krokodil +krokodyl +krypton1 +kryptonite +krystal1 +krystal2 +krystian +krystian1 +krystle1 +krystyna +krystyna56 +krzysiek +krzysiek1 +krzysztof +ks120473 +ksushapanda +ksyukha1990 +ksyusha.kulagina.91 +ksyuta76 +kthfkthf +ktitymrf +ktnj2010 +ktvt6tn9 +ktybyuhfl +ktyecmrf +ktyfktyf +kuana230345 +kuchelaeva +kuchierova1994 +kuchinovao +kucing123 +kucingku +kudakova.83 +kudielia.anna +kudrina1962 +kudrjashova62 +kudryavcevavalya +kujawka98 +kukareku +kukatov86 +kukuruku +kukuruza +kukushka +kulangot +kuliiev.79 +kulikova +kulkarni +kumar123 +kumar1989 +kundalini +kunimi92 +kuningan +kunkle70 +kuponatora +kupukupu +kurakura +kurapika +kurdistan +kurdistan1 +kurmangazieva_gulmira +kurniawan +kuroneko +kurosaki +kurtcobain +kurwa123 +kurwamac +kurwamac1 +kusanagi +kuznecovviktorr +kuzya-ser +kvartira +kwiatek1 +kwiatuszek +kxdw0980 +kyle1234 +kyleigh1 +kylekyle +kylie123 +kyokushin +kytfy2xd97 +kytfy2xd98 +l0llip0p +l0vel0ve +l1234567 +l12345678 +l123456789 +l1nk3d1n +l1nked1n +l1o2v3e4 +l1qoh9wq2u +l1v3rp00l +l1verp00l +l1verpool +l33tsupah4x0r +l58jkdjp!m +l6ho3tg7wb +la123456 +labas123 +labirint +laboratorio +labrador +labrador1 +labyrinth +lacey123 +lachlan1 +lachula1 +lacoste1 +lacrimosa +lacrimosa1 +lacrosse +lacrosse1 +lacrosse11 +lacrosse12 +lacrosse13 +lacrosse2 +lacrosse21 +lacrosse22 +lacrosse3 +lacrosse4 +lacrosse5 +lacrosse7 +lacrosse9 +ladder49 +ladiesman +ladiesman1 +ladiesman2 +lady.procenko71 +lady1234 +ladybird +ladybird1 +ladyblue +ladybug! +ladybug01 +ladybug08 +ladybug1 +ladybug10 +ladybug11 +ladybug12 +ladybug123 +ladybug13 +ladybug2 +ladybug22 +ladybug3 +ladybug4 +ladybug5 +ladybug6 +ladybug7 +ladybug8 +ladybug9 +ladybugs +ladybugs1 +ladydog1 +ladygaga +ladygaga1 +ladygaga12 +ladygirl +ladyinred +ladyjane +ladykiller +ladylady +ladylove +ladylove1 +ladyluck +ladyluck1 +ladysman1 +laetitia +lafamilia +lafamilia1 +lafayette +lafayette1 +laffytaffy +lafouine +lafrance +lagartija +lagrange +lagwagon +lahore123 +lahoumti +laila123 +lakehouse +lakeland +lakeland1 +lakers#1 +lakers01 +lakers08 +lakers09 +lakers10 +lakers11 +lakers12 +lakers123 +lakers13 +lakers15 +lakers21 +lakers22 +lakers23 +lakers24 +lakers32 +lakers33 +lakers34 +lakers88 +lakeshore +lakeside +lakeside1 +laketahoe +lakeview +lakeview1 +lakewood +lakewood1 +lakilaki +lakshmi1 +lala1234 +lalakers +lalakers1 +lalakers24 +lalala11 +lalala12 +lalala123 +lalala13 +lalala22 +lalala99 +lalalala +lalalala1 +lalalalala +lalaland +lalaland1 +lamalama +lamar123 +lambchop +lambchop1 +lambert1 +lambofgod +lambofgod1 +lamborghin +lamborghini +lamborgini +lambretta +lambretta1 +lamejor1 +lamination +lampard08 +lampard1 +lampard123 +lampard8 +lampshade +lampshade1 +lanalana +lancaster +lancaster1 +lance123 +lancelot +lancelot1 +lancers1 +lancia037 +landcruiser +landlord +landmark +landon01 +landon05 +landon06 +landon07 +landon08 +landon09 +landon12 +landon123 +landrover +landrover1 +landscape +landscape1 +langka04 +langlang +langston +language +lanlan1234 +lansing1 +lanzarote +laobidenko +lapierre +lapochka +laptop12 +laptop123 +lara1308 +laracroft +laracroft1 +laralara +larissa1 +larissa123 +larousse +larry123 +larrybird +larryboy +larsson7 +lasalle1 +laser123 +laserjet +lashawn1 +laspalmas +lastborn +lastchance +lastchaos +lastfm123 +lastfmpass +lastname +lastochka +lastpass +lasttime +lasvegas +lasvegas1 +lasvegas12 +lasvegas2 +lasvegas7 +latasha1 +lateralus +lateralus1 +latina12 +latina123 +latina13 +latinking1 +latinking5 +latinlover +latinoheat +latisha1 +latitude +latitude1 +latrell1 +latrice1 +laughing +laughing1 +laughter +laughter1 +laura123 +laura1234 +laurel12creek +lauren00 +lauren01 +lauren02 +lauren05 +lauren06 +lauren07 +lauren08 +lauren09 +lauren10 +lauren11 +lauren12 +lauren123 +lauren13 +lauren14 +lauren15 +lauren16 +lauren17 +lauren18 +lauren19 +lauren21 +lauren22 +lauren23 +lauren24 +lauren69 +lauren88 +lauren99 +laurence +laurence1 +laurent1 +laurentiu +lauretta +laurette +lauriane +laurinha +laurita1 +lausanne +lavalamp +lavalamp1 +lavander +lavender +lavender1 +laverne1 +lavidaesbella +lavidaloca +lavieestbelle +lavigne1 +lawless1 +lawnmower +lawnmower1 +lawrence +lawrence1 +lawrence2 +lax4life +layla123 +layouts! +layouts. +layouts1 +layouts123 +lazareva +lazarus1 +lazio1900 +lazyboy1 +lbfyjxrf +lbhtrnjh +lbvekmrf +lbvflbvf +lbyjpfdh +lc519qlpuu +lctstens +lcv7bry1cf +le_den_ec +leadership +leandra1 +leandro1 +leandro123 +leapfrog +learning +learning1 +leather1 +leavemealo +leavemealone +lebanon1 +lebedeva +lebesgue +lebowski +lebron23 +lebronjame +lebronjames +lebronjames23 +leckmich +lecturer +lectures +ledzeppeli +ledzeppelin +lee12345 +leeds123 +leedsunited +leedsutd +leedsutd1 +leelee12 +leelee123 +leeminho +leet1337 +left4dead +left4dead2 +lefthand +legalize +legend01 +legend12 +legend123 +legend22 +legenda1 +legendary +legendary1 +legends1 +legia1916 +legioner +legoland +legolas1 +legolas2 +legolego +legoman1 +leicester +leicester1 +leigh123 +leighann +leighann1 +leighton +leighton1 +leilani1 +lekkerding +lelewa123 +leliane50934 +lemieux66 +lemmings +lemon123 +lemonade +lemonade1 +lemondrop +lemondrop1 +lemonhead +lemonhead1 +lemonlime +lemonlime1 +lemons123 +lemontree +len4ik31 +len_nik44 +len_rin_kagamine_02 +lena1234 +lena2010 +lena5stars +lenalena +leningrad +lenny123 +lenochka +leo12345 +leo123456 +leoleoleo +leolong1985 +leomessi +leomessi10 +leon1234 +leonard1 +leonardo +leonardo1 +leonardo10 +leonardo12 +leonardo123 +leonardo2 +leoncino +leoncito +leonessa +leonhart +leonidas +leonidas1 +leonleon +leopard1 +leopard2 +leopardo +leopards +leopold1 +leopoldo +leothelion +leprechaun +leralera +lerochka +lerolero +leroy123 +lesbian1 +lesbian2 +lesbian69 +lesbiana +lesbians +lesbians1 +leslie01 +leslie11 +leslie12 +leslie123 +leslie13 +lespaul1 +lessthan3 +lester123 +leticia1 +leticia123 +letmein! +letmein. +letmein0 +letmein01 +letmein1 +letmein11 +letmein12 +letmein123 +letmein2 +letmein22 +letmein3 +letmein69 +letmein7 +letmein9 +letmein99 +letmeinnow +letmeout +letmesee +leto-nataly +leto2010 +letsdoit +letsfuck +letsgetit1 +letsplay +letsrock +letters1 +lettuce1 +levana928 +levenyatko2007 +leverkusen +leviathan +levis501 +levski1914 +lewis123 +lexa-let4ik +lexa.maxus +lexa290195 +lexaafanasiev84 +lexie123 +lexington +lexington1 +lexir777 +lexmark1 +lexor123 +lexus123 +lexus300 +lexusis300 +lfc4life +lfiekmrf +lfiflfif +lfitymrf +lfplhfgthvf +lfybkjdf +lh6209lh +lh6rjx44qb +lhbjkjubz2957704 +li123456 +liaisons +liarliar +liarliar1 +libby123 +libellula +libellule +libelula +liberate +liberation +liberdade +libertad +libertad1 +libertas +libertine +liberty1 +liberty123 +liberty2 +liberty7 +libra123 +librarian +library1 +lichking +lickme69 +licorice +licorice1 +liebling +life1234 +lifeboat +lifegoeson +lifeguard +lifeguard1 +lifehouse +lifehouse1 +lifeisgood +lifeislife +lifeless +lifelife +lifeline +liferocks +lifesgood +lifestyle +lifestyle1 +lifesucks +lifesucks! +lifesucks1 +lifesucks2 +lifesux1 +lifetime +lifetime1 +light123 +lightblue +lightbulb +lightbulb1 +lighter1 +lightfoot +lighthouse +lightimes +lighting +lighting1 +lightning +lightning1 +lightning2 +lightpower12345 +lightsaber +lightyear +likeaboss +likehouse +likemike +lilangel +lilangel1 +lilbaby1 +lilbear1 +lilbitch +lilbitch1 +lilboosie +lilboosie1 +lilchris +lilchris1 +lilcutie1 +lildaddy1 +lildevil +lildevil1 +lildude1 +lilfizz1 +lilflip1 +lilgirl1 +lili1234 +liliana1 +lilibeth +lililili +liljohn1 +lilli2006 +lillian1 +lillian2 +lilliana +lilliput +lilly123 +lillypad +lilmama01 +lilmama07 +lilmama08 +lilmama09 +lilmama1 +lilmama10 +lilmama11 +lilmama12 +lilmama123 +lilmama13 +lilmama14 +lilmama15 +lilmama2 +lilmama23 +lilmama3 +lilmama4 +lilmama5 +lilmama7 +lilmamma1 +lilman07 +lilman08 +lilman11 +lilman12 +lilman123 +lilman13 +lilman23 +lilmike1 +lilmomma +lilmomma1 +lilmoney1 +lilnigga1 +lilolilo +lilone13 +lilpimp1 +lilromeo +lilsaint +lilsexy1 +lilshorty1 +lilwayne +lilwayne09 +lilwayne1 +lilwayne10 +lilwayne11 +lilwayne12 +lilwayne13 +lilwayne2 +lilwayne23 +lilwayne3 +lilwayne4 +lilwayne5 +lilwayne7 +lilweezy1 +lily1234 +lilylily +lilypad1 +lilyrose +limabean +limanlly +limaperu +limegreen +limegreen1 +limegreen2 +limelight +limerick +limestone +limewire +limewire1 +limited1 +limited2 +limonada +limonade +limpbizkit +linalina +lincogo1 +lincoln1 +lincoln2 +lincoln8187 +linda123 +lindalinda +lindinha +lindros88 +lindsay1 +lindsay12 +lindsay123 +lindsay2 +lindsay7 +lindsey! +lindsey1 +lindsey12 +lindsey123 +lindsey2 +lindsey3 +lindsey7 +lineage2 +linebacker +lineman1 +lingerie +lingling +lingling1 +link1234 +link123456 +link2011 +linkbuild +linked01 +linked11 +linked123 +linked1n +linked2011 +linked4me +linkedin +linkedin.com +linkedin01 +linkedin1 +linkedin10 +linkedin11 +linkedin12 +linkedin123 +linkedin1234 +linkedin13 +linkedin2 +linkedin2010 +linkedin2011 +linkedin2012 +linkedin22 +linkedin23 +linkedin4me +linkedin69 +linkedin7 +linkedin77 +linkedin8 +linkedin99 +linkedinlinkedin +linkedinpass +linkedinpassword +linkedinpw +linkedln +linkedout +linkedpass +linkin12 +linkin123 +linkinpark +linkinpark1 +linklink +linkmein +linkpass +links123 +links234 +linksys1 +linux123 +linwood1 +lion1234 +lionelmessi +lioness1 +lionheart +lionheart1 +lionking +lionking1 +lionking2 +lionlion +lions123 +lipgloss +lipgloss1 +lipgloss12 +lipgloss2 +lipovv70 +lipstick +lipstick1 +lipy110593 +lisa1234 +lisalisa +lisalisa1 +lisamarie +lisamarie1 +lisandro +lisbon67 +lisenkogv +lisette1 +lisichka +lisicyna704 +lissette +lissette1 +listopad +listopad.iuliia +literatura +literature +lithium1 +lithuania +little11 +little12 +little123 +littleangel +littlebear +littlebit +littlebit1 +littlebit2 +littleboy +littleboy1 +littled1 +littledog +littlefoot +littlegirl +littleguy +littlelady +littleman +littleman1 +littleman2 +littleman3 +littlemiss +littleone +littleone1 +littlered +littlered1 +littlestar +liu123456 +liuchang +live2die +live2love +live2ride +live4ever +live4god +live4him +live4life +live4love +livefree +livelaughl +livelaughlove +livelife +livelife1 +livelife2 +livelove +livelove1 +liverp00l +liverpoo +liverpool +liverpool! +liverpool. +liverpool0 +liverpool01 +liverpool05 +liverpool08 +liverpool09 +liverpool1 +liverpool10 +liverpool11 +liverpool12 +liverpool123 +liverpool1892 +liverpool2 +liverpool3 +liverpool4 +liverpool5 +liverpool6 +liverpool7 +liverpool8 +liverpool9 +liverpoolf +liverpoolfc +livestrong +livewire +livewire1 +livinglife +livingston +lizaliza +lizard12 +lizard123 +lizardking +lizasp07 +lizaveta +lizbeth1 +lizette1 +lizottes +lizzard1 +lizzie01 +lizzie12 +lizzie123 +lizzy123 +lj352d1ib31 +ljames23 +ljxtymrf +lk123456 +lkj65b6666 +lkjhgfds +lkjhgfdsa +lkjhgfdsa1 +ll123456 +llama123 +llcoolj1 +llewellyn +llllllll +llllllllll +lloyd123 +lm292979 +lmapacey +lmfao123 +lmnop123 +lobkova.1979 +lobster1 +localoca +location +lochness +lockdown +lockdown1 +lockhart +lockheed +locksmith +lockwood +loco1234 +locoloco +locomotive +logan123 +logcabin +logical1 +login123 +logistics +logitech +logitech1 +logitech12 +logitech123 +logitech2 +loirinha +loislane +lokaloka +lokiloki +lokita13 +lokoloko +lokomoko +lokomotiv +lokomotiva +lokoporti +lokote13 +lol123123 +lol12345 +lol123456 +lol123456789 +lol123lol +lola1234 +lolalola +lolalola1 +lolek123 +lolipop0 +lolipop1 +lolipop12 +lolipop123 +lolipop2 +lolita12 +lolita123 +lolliepop +lolliepop1 +lollies1 +lollip0p +lollipop +lollipop! +lollipop. +lollipop0 +lollipop00 +lollipop1 +lollipop10 +lollipop11 +lollipop12 +lollipop123 +lollipop13 +lollipop2 +lollipop3 +lollipop5 +lollipop69 +lollipop7 +lollipop8 +lollipop9 +lollipops +lollol11 +lollol12 +lollol123 +lollollol +lollollol1 +lolly123 +lollypop +lollypop! +lollypop1 +lollypop12 +lollypop2 +lolman123 +lolo1234 +lolol123 +lololol1 +lolololo +lolsmileyf +lombardi +lombardo +london00 +london01 +london05 +london06 +london07 +london08 +london09 +london10 +london11 +london12 +london123 +london1234 +london13 +london20 +london2008 +london2009 +london2010 +london2011 +london2012 +london21 +london22 +london23 +london24 +london44 +london55 +london66 +london77 +london88 +london99 +londonboy +londoner +loneliness +lonelygirl +lonesome +lonestar +lonestar1 +lonewolf +lonewolf1 +longbeach +longbeach1 +longboard +longboard1 +longdick +longdong +longfellow +longhair +longhair1 +longhorn +longhorn1 +longhorns +longhorns1 +longhorns2 +longhorns3 +longhorns7 +longisland +longjohn +longlegs +longlife +longlive +longlong +longshot +longtime +longview +longview1 +longwood +lonsdale +lonsdale1 +looby123 +lookatme +lookatme1 +looking1 +looking123 +looking2 +looking4 +looking4u +lookingforlove +looklook +lookout1 +loop1206ssdsff +looploop +looser123 +lop1346781 +lopas123 +lopez123 +loquesea +loquillo +lord1234 +lordjesus +lordjesus1 +lordlord +lordoftherings +lordshiva +lordvader +loredana +lorena12 +lorena123 +lorenita +lorenzo1 +lorenzo123 +lorenzo2 +loretta1 +lorik197110 +lorikeet +lorraine +lorraine1 +losangeles +losenord +loser101 +loser123 +loser1234 +loser12345 +loser4life +loserface +loserface1 +lost4815162342 +lost4ever +lostlove +lostlove1 +lostsoul +lostsoul1 +lothlorien +lottery1 +lotus123 +lotusnotes +louie123 +louis123 +louis12345 +louise01 +louise11 +louise12 +louise123 +louise13 +louise14 +louise21 +louise22 +louise23 +louisiana +louisiana1 +louisville +louisvuitton +loulou12 +loulou123 +loulou22 +louloute +louloutte +lourdes1 +lovable1 +love&hate +love<:3 +love1004 +love1010 +love1111 +love1212 +love1234 +love12345 +love123456 +love123456789 +love1313 +love1314 +love1980 +love1981 +love1982 +love1983 +love1984 +love1985 +love1986 +love1987 +love1988 +love1989 +love1990 +love1991 +love1992 +love1993 +love1994 +love1995 +love1996 +love1997 +love1998 +love1999 +love1god +love1love +love2000 +love2001 +love2002 +love2003 +love2004 +love2005 +love2006 +love2007 +love2008 +love2009 +love2010 +love2011 +love2012 +love2013 +love2dance +love2fuck +love2hate +love2live +love2love +love2shop +love2sing +love2you +love4all +love4eva +love4ever +love4ever1 +love4god +love4him +love4life +love4love +love4real +love4you +love5683 +love6969 +love777321777 +love7777 +love_you +loveable +loveable1 +loveable2 +lovealways +loveandhate +loveandpeace +loveangel +loveangel1 +lovebaby +lovebaby1 +lovebird +lovebird1 +lovebirds +lovebirds1 +lovebites +loveboat +lovebug! +lovebug1 +lovebug10 +lovebug101 +lovebug11 +lovebug12 +lovebug123 +lovebug13 +lovebug2 +lovebug22 +lovebug3 +lovebug4 +lovebug5 +lovebug69 +lovebug7 +lovebugs +lovebunny +lovecats +lovechild +lovechild1 +lovecraft +lovedetoi +lovedove +lovefamily +loveforeve +loveforever +lovegame +lovegirl +lovegirl1 +lovegod1 +loveguru +lovehate +lovehate1 +loveheart +loveher1 +lovehim1 +lovehim2 +lovehina +lovehina1 +lovehurt +lovehurts +lovehurts! +lovehurts1 +lovehurts2 +lovehurts3 +loveindia +loveisall +loveisblin +loveisblind +loveisgod +loveisgood +loveislife +loveislove +loveispain +loveisreal +lovejesus +lovejesus1 +lovejones +lovejoy1 +lovekids +lovekills +lovekills1 +lovekiss +lovekita +lovekoto +lovelace +loveland +loveless +loveless1 +lovelife +lovelife! +lovelife1 +lovelife12 +lovelife2 +lovelife3 +lovelife7 +loveline +lovelost +lovelove +lovelove! +lovelove1 +lovelove12 +lovelove123 +lovelove2 +lovelove3 +lovelove7 +lovelovelo +lovelovelove +lovely01 +lovely07 +lovely08 +lovely09 +lovely10 +lovely101 +lovely11 +lovely12 +lovely123 +lovely1234 +lovely13 +lovely14 +lovely15 +lovely16 +lovely17 +lovely18 +lovely19 +lovely20 +lovely21 +lovely22 +lovely23 +lovely24 +lovely25 +lovely69 +lovely77 +lovely88 +lovelyboy +lovelyday +lovelygirl +lovelylady +lovelyme +lovemama +loveme01 +loveme07 +loveme08 +loveme09 +loveme10 +loveme101 +loveme11 +loveme12 +loveme123 +loveme1234 +loveme13 +loveme14 +loveme143 +loveme15 +loveme16 +loveme17 +loveme18 +loveme19 +loveme20 +loveme21 +loveme22 +loveme23 +loveme24 +loveme25 +loveme33 +loveme4eva +loveme4eve +loveme4ever +loveme4me +loveme69 +loveme77 +loveme88 +loveme89 +loveme99 +lovemebaby +lovemedo +lovemenot +lovemenow +lovemom1 +lovemoney +lovemonkey +lovemusic +lovemusic1 +lovemybaby +lovemykids +lovemylife +lovemyself +loveone1 +lovepeace +lovepeace1 +lovepink +lovepink1 +lovepussy +lovepussy1 +lover101 +lover123 +lover1234 +lover12345 +lover4ever +lover4life +loverboy +loverboy1 +loverboy12 +loverboy2 +loverboy3 +loverboy69 +loverboy7 +lovergirl +lovergirl1 +lovergirl2 +lovergurl +lovergurl1 +loverlover +loverman +loverman1 +lovers01 +lovers07 +lovers08 +lovers09 +lovers10 +lovers101 +lovers11 +lovers12 +lovers123 +lovers13 +lovers14 +lovers21 +lovers22 +lovers23 +lovers4eve +lovers69 +loves123 +lovesex1 +lovesex69 +lovesexy +lovesick +lovesick1 +lovesit1 +lovesloves +lovesong +lovespell +lovespell1 +lovestar +lovestinks +lovestory +lovestory1 +lovestruck +lovesucks +lovesucks! +lovesucks1 +lovesucks2 +lovesux1 +lovesyou +loveu123 +loveu4ever +loveumom +loveworld +loveya12 +loveya123 +loveydovey +loveyou! +loveyou. +loveyou01 +loveyou08 +loveyou09 +loveyou1 +loveyou10 +loveyou11 +loveyou12 +loveyou123 +loveyou13 +loveyou14 +loveyou143 +loveyou15 +loveyou2 +loveyou21 +loveyou22 +loveyou23 +loveyou3 +loveyou4 +loveyou5 +loveyou6 +loveyou69 +loveyou7 +loveyou8 +loveyou9 +loving12 +loving123 +lovinglife +lovingme +lovingyou +lovingyou1 +lovinlife +lovinlife1 +lowlife1 +lowrider +lowrider1 +lowrider13 +loxpider +loyalty1 +lozinka1 +lp123456 +lppnldtzx +lpz93ssskqw8q +lqfg4hwt +lsutigers +lsutigers1 +lthgfhjkm +ltybcrj1992 +luansantana +lubimaya +lucaluca +lucas123 +lucas1234 +lucatoni +lucerito +lucia123 +luciana1 +luciano1 +lucienne +lucifer1 +lucifer6 +lucifer666 +lucifero +lucille1 +lucinda1 +lucious1 +lucky007 +lucky100 +lucky101 +lucky111 +lucky123 +lucky1234 +lucky4me +lucky777 +lucky888 +luckyboy +luckyboy1 +luckycat +luckycharm +luckydog +luckydog1 +luckyduck +luckygirl +luckygirl1 +luckylady +luckylucky +luckyluke +luckyman +luckyme1 +luckyone +luckyone1 +luckystar +luckystar1 +luckystrike +lucozade +lucrecia +lucretia +lucrezia +lucy1234 +lucydog1 +lucygirl +lucylou1 +lucylucy +ludacris +ludacris1 +ludhiana +ludi1234 +ludivine +ludmilla +ludovica +ludovico +lufthansa +luigi123 +luis1234 +luis123456 +luisa123 +luisalberto +luisangel +luiscarlos +luisfigo +luisito1 +luisluis +luismiguel +luisteamo +lukaluka +lukas123 +lukasz12 +lukaszek +luke1234 +lukeluke +lukinhas +lulu1234 +lulu889jdddd +lulubell +lulubelle +lulululu +luluzinha +lumberjack +luminita +luna1234 +lunallena +lunaluna +lunanueva +lunarossa +lunatic1 +lunatica +lunchbox +lunchbox1 +lupashku89 +lupita12 +lupita123 +lupita13 +luscious +luscious1 +lutheran +lutscher +luv2dance +luv2fish +luv2shop +luv2sing +luv4ever +luv4life +luvu4eva +luvu4ever +luzmaria +lvbnhbtdf +lwf1681688 +lydcc20091314 +lydia123 +lyndsey1 +lynette1 +lynn1234 +lynnette +lynnette1 +lynnlynn +lynwood1 +lyonnais +lyrical1 +lytwa813ib +lyudmila +lz110110 +lzhan16889 +lztez2xe98 +lzudz2xe98 +m00nlight +m01759766727 +m0t0r0la +m1234567 +m12345678 +m123456789 +m123456m +m1am1b3ach +m1ch3ll3 +m1chelle +m1chp00h +m1dn1ght +m1garand +m1i2k3e4 +m1m2m3m4 +m1m2m3m4m5 +m1ul9x9i20 +m2g7u6o397 +m2ydegkdws +m3tallica +m7777777 +m8a8vhr6 +m987654321 +ma123123123 +ma123456 +maadurga +macarena +macaroni +macaroni1 +macbeth1 +macbook1 +macbookpro +macchina +macdaddy +macdaddy1 +macdonald +macedonia +macegorova.mariya +macgyver +macherie +machine1 +machines +machines1 +macho123 +machoman +machoman1 +machukreeva +machupichu +maciek06 +maciek123 +macintosh +macintosh1 +mackdaddy +mackdaddy1 +mackenzie +mackenzie1 +mackenzie2 +madafaka +madagascar +madagaskar +madalena +madalina +madarchod +maddalena +madden06 +madden07 +madden08 +madden09 +madden10 +madden11 +madden12 +maddie01 +maddie05 +maddie06 +maddie07 +maddie08 +maddie09 +maddie10 +maddie11 +maddie12 +maddie123 +maddie13 +maddie22 +maddison +maddison1 +maddog11 +maddog12 +maddog123 +maddog2020 +maddog69 +maddux31 +maddy123 +madeinchina +madelaine +madeleine +madeleine1 +madeline +madeline1 +madelyn1 +madhatter +madhatter1 +madhavan +madhouse +madhouse1 +madhu123 +madhukar +madhumita +madinina +madinina972 +madison! +madison. +madison01 +madison02 +madison03 +madison04 +madison05 +madison06 +madison07 +madison08 +madison09 +madison1 +madison10 +madison11 +madison12 +madison123 +madison13 +madison14 +madison2 +madison200 +madison21 +madison22 +madison23 +madison3 +madison4 +madison5 +madison6 +madison7 +madison8 +madison9 +madison99 +madisyn1 +madman123 +madness1 +madness7 +madonna1 +madonna12 +madonna2 +madremia +madrid10 +madrigal +madtubes +madyson1 +maella1311 +maestro1 +maeteamo +mafalda1 +mafia123 +mafiawars +mafiawars1 +magallanes +maganda1 +magandaako +magazine +magazine1 +magda123 +magdalena +magdalena1 +magdalene +magdeburg +magelang +magellan +magenta1 +maggie00 +maggie01 +maggie02 +maggie03 +maggie04 +maggie05 +maggie06 +maggie07 +maggie08 +maggie09 +maggie10 +maggie101 +maggie11 +maggie12 +maggie123 +maggie1234 +maggie13 +maggie14 +maggie15 +maggie16 +maggie17 +maggie18 +maggie21 +maggie22 +maggie23 +maggie24 +maggie25 +maggie33 +maggie55 +maggie69 +maggie77 +maggie88 +maggie99 +maggiedog +maggiemae +maggiemae1 +maggiemay +maggiemay1 +maggot666 +magic-n12 +magic101 +magic123 +magical1 +magicaroma +magician +magician1 +magicman +magicman1 +magister +magma9824660 +magnavox +magnetic +magnifico +magno456 +magnolia +magnolia1 +magnum357 +magnum44 +magodeoz +magodeoz1 +magpies1 +mahalakshmi +mahalaxmi +mahalcoh +mahalkita +mahalkita1 +mahalkita2 +mahalko1 +mahalkoh +mahalqoh +maharaja +maharani +maharashtra +mahaveer +mahendra +mahesh123 +mahimahi +mahindra +mahmoud1 +mahmudali1987 +mahogany +maianbinh +maiden666 +maik1996 +maika2006 +mailbox1 +mailkuliev +mailmail +mailman1 +maimaiyeuem +maimouna +mainstream +mainstreet +maintain +maintenance +maitland571ka1994 +maiyeuem +majeczka +majestic +majestic1 +majestic12 +majesty1 +majiajun +majiajun8888 +major123 +mak301988 +makarena +makarenko +makaroni +makarova +makassar +makaveli +makaveli1 +makaveli7 +makavelli +makayla1 +makayla2 +makayla3 +makayla5 +makedonija +makeitso +makelove +makemoney +makemoney1 +makemyday +makenna1 +makenzie +makenzie1 +makimaki +maks.abramov.99.99 +maksim.bychkov.1986 +maksim123 +maksim2425 +maksimilian_nasirov +maksimka +maksimka876 +maksimov +maksimus +maksmaks +maksus_2003 +malachi1 +malachi2 +malaguti +malaikat +malakai1 +malakas1 +malamute +malatya44 +malayalam +malaysia +malaysia1 +malboro1 +malcolm1 +malcolmx +maldini3 +maldita1 +malditah +maldives +maldonado +maldonado1 +malgorzata +malgosia +malhotra +malhotra493ozzy1991282151 +malik123 +malina_bratsk +malishka +malkin71 +mallard1 +mallorca +mallorca1 +mallory1 +mallrats +malmsteen +maltese1 +malyshka +mama1234 +mama12345 +mama123456 +mama1960 +mama1961 +mama1963 +mama1964 +mama1970 +mama1995 +mama1997 +mama2000 +mama2008 +mama2009 +mama2010 +mama2011 +mamababa +mamabear +mamabear1 +mamacita +mamacita1 +mamaliga +mamalove +mamamama +mamamama1 +mamamary +mamamia1 +maman123 +mamanjetaime +mamanjtm +mamanpapa +mamapapa +mamapapa1 +mamapapa123 +mamasboy +mamasboy1 +mamasgirl1 +mamasita +mamasita1 +mamatata +mamateamo +mamaypapa +mamichula1 +mamika10 +mamikawada +mamimami +mamipapi +mamma123 +mammamia +mammamia1 +mammoth1 +mamochka +mamounette +mamusia1 +man12345 +man123456 +man55580 +management +manager1 +manamana +manatee1 +manchester +manchester1 +manchester123 +manchesterunited +manchita +manchitas +mancity1 +manda123 +mandalay +mandarin +mandarina +mandarine +mandarinka +mandarino +mandds1mg6bv8re +mandingo +mandingo1 +mandolin +mandragora +mandrake +mandy123 +maneater +maneater1 +manfred1 +manga123 +mangalore +mango123 +mangusta +manhater +manhattan +manhattan1 +manifest +manikandan +manimani +manish123 +manitoba +manju123 +manjunath +manjusha +manka198707 +mankind1 +manman11 +manman12 +manman123 +manmanman +manmohan +mannheim +manning1 +manning10 +manning18 +manny123 +manofgod +manofsteel +manoj123 +manojkumar +manolete +manolito +manomano +manorama +manouche +manovitskaya +manowar1 +manpower +manpreet +mansfield +mansfield1 +manson666 +manson69 +manu1234 +manu4eva +manu4life +manuel01 +manuel10 +manuel11 +manuel12 +manuel123 +manuel13 +manuel14 +manuel15 +manuel18 +manuel21 +manuel22 +manuel23 +manuela1 +manuelita +manuelito +manuelito1 +manuella +manuliktatyana +manumanu +manunited +manunited1 +manunited7 +manutd01 +manutd07 +manutd10 +manutd11 +manutd12 +manutd123 +manutd99 +manwhore +manwhore1 +manzana1 +manzanita +mapamapa7 +maple123 +mapleleaf +mapleleafs +maplestory +maplewood +maprchem56458 +mar_prod +maracaibo +maracuja +maradona +maradona1 +maradona10 +marajade +maramara +maranata +maranatha +maranda1 +maranello +marathon +marathon1 +marauder +maravilha +maravilhosa +maravilla +maravilla1 +marbella +marbles1 +marcel12 +marcel123 +marcela1 +marcelina +marcelino +marcelita +marcell1 +marcella +marcella1 +marcelle +marcello +marcello1 +marcelo1 +marcelo123 +march123 +march1993 +march2007 +march2008 +march2009 +marchelle27 +marciano +marcin123 +marcinek +marco123 +marcoantonio +marcolino +marcopolo +marcopolo1 +marcos10 +marcos12 +marcos123 +marcos13 +marcus01 +marcus06 +marcus07 +marcus08 +marcus09 +marcus10 +marcus11 +marcus12 +marcus123 +marcus13 +marcus14 +marcus15 +marcus21 +marcus22 +marcus23 +marcus99 +mardigras +marduk666 +marek123 +marek14michal +maremare +margaret +margaret1 +margareta +margareth +margarette +margarida +margarita +margarita1 +margarita2 +margaritka +margera1 +margherita +margo.emi +margosha +marguerite +mari1234 +maria-demidchik +maria-fam +maria123 +maria1234 +maria12345 +maria2010 +maria666 +mariachi +mariaclara +mariaeduarda +mariaelena +mariafernanda +mariagoncharenko +mariagrazia +mariah01 +mariah10 +mariah11 +mariah12 +mariah123 +mariah13 +mariahcarey +mariaisabel +mariajose +mariajose1 +marialuisa +marialuiza +mariamaria +mariana1 +mariana12 +mariana123 +mariana2 +marianela +mariangela +marianita +marianna +marianna1 +mariannaz2 +marianne +marianne1 +mariano1 +mariapaula +mariapia +mariarita +mariarosa +mariateresa +maribel1 +maribeth +maricarmen +maricela +maricela1 +maricon1 +maricris +marie101 +marie123 +marie1234 +mariela1 +mariella +marielle +marielwfledlow +marietta +marietta1 +mariette +marigold +mariguana +marihuana +marihuana1 +marijana +marijuana +marijuana1 +marijuana2 +marijuana4 +marijuana420 +marilena +marillion +marilyn1 +marilyn59 +marilynmanson +marimari +marimax.85 +marina.shapovalo +marina.ushakovaznuv +marina01 +marina10 +marina11 +marina12 +marina123 +marina13 +marina2010 +marina22 +marina23 +marina88 +marina_stryazhkova +marinadeduxinaa +marinamarina +marinaorlova1991 +marinara +marine01 +marine11 +marine12 +marine123 +marine13 +marinela +marinella +mariner1 +marinero +mariners +mariners1 +marines1 +marines12 +marines2 +marinette +marininys +marino13 +marino4ka +marinochka +marinochka.zhelannaya +mario123 +mario1234 +mario140773 +mariobros +mariokart +mariomario +mariposa +mariposa1 +mariposa11 +mariposa12 +mariposa2 +mariposa7 +mariposas +mariposita +mariquita +marisela +marisela1 +marishka +marisol1 +marissa1 +marissa12 +marissa123 +marissa13 +marissa2 +marissa3 +marissa5 +marissa7 +maritime +maritza1 +marius123 +mariusz1 +marjorie +marjorie1 +mark1234 +mark12345 +mark_963 +markanthon +marketing +marketing1 +markjohn +markjoseph +markmark +marko123 +markovka +markus123 +markymark +marlboro +marlboro1 +marlboro12 +marlboro2 +marlboro20 +marlena1 +marlene1 +marley01 +marley08 +marley09 +marley10 +marley11 +marley12 +marley123 +marley13 +marley22 +marley420 +marlins1 +marlon123 +marmaduke +marmalade +marmalade1 +marmaris +marmelad +marmelade +marmeladka +marmite1 +marmotte +marocain +marques1 +marquette +marquette1 +marquez1 +marquis1 +marquise +marquise1 +marrakech +marriage +marriage1 +married06 +married07 +married08 +married1 +married2 +marriott +marriott1 +marruecos +marseille +marseille1 +marseille13 +marsha11 +marshal1 +marshall +marshall1 +marshall12 +marshall2 +marshall3 +marshmallow +marshmello +marshmellow +marsmars +marsupilami +marta123 +martello +martha12 +martha123 +martin01 +martin06 +martin07 +martin08 +martin09 +martin10 +martin11 +martin12 +martin123 +martin1234 +martin13 +martin14 +martin15 +martin16 +martin17 +martin18 +martin20 +martin21 +martin22 +martin23 +martin24 +martin25 +martin69 +martin77 +martin88 +martin99 +martina1 +martina123 +martine1 +martinek +martinez +martinez1 +martinez12 +martinez13 +martinez2 +martinha +martini1 +martinique +martinka +martinko +martins1 +martusia +marty123 +martyna1 +martynka +marvel5454 +marvellous +marvelous +marvelous1 +marvin01 +marvin11 +marvin12 +marvin123 +marvin13 +mary1234 +maryann1 +maryanne +maryanne1 +marybeth +marybeth1 +maryellen +marygrace +maryj420 +maryjan3 +maryjane +maryjane! +maryjane. +maryjane1 +maryjane12 +maryjane13 +maryjane2 +maryjane3 +maryjane4 +maryjane42 +maryjane420 +maryjane69 +maryjane7 +maryjean +marykate +marykate1 +marykay1 +maryland +maryland1 +maryline +marylou1 +marymary +marymary1 +marypoppins +maryrose +marysia1 +marzipan +masahiro +masamasa +masamune +masamune1 +mascotte +mase4ever +maserati +mash4077 +masha123 +masha1998 +mashamasha +mashenka +mashimaro +masjnj67 +maslo123 +masloboinikova1987 +mason123 +masquerade +massacre +massacre1 +massage1 +masseffect +massena00 +massilia +massimiliano +massimo1 +massive1 +master00 +master007 +master01 +master07 +master08 +master09 +master10 +master101 +master11 +master12 +master123 +master1234 +master12345 +master13 +master14 +master15 +master16 +master17 +master18 +master20 +master2006 +master21 +master22 +master23 +master24 +master25 +master33 +master45 +master55 +master66 +master666 +master69 +master77 +master777 +master88 +master89 +master99 +masterblaster +mastercard +masterchief +masterkey +masterman +mastermind +masterone +masterp1 +masterpiece +masterplan +masters1 +masyanya +matador1 +matahari +matamata +matarani +matchbox +matchbox20 +mate1.com +matematica +matematicas +matematik +matematika +mateo123 +materazzi +material +mateus123 +mateusz1 +mateusz12 +mateusz123 +mateuszek +mathematic +mathematics +matheus1 +matheus123 +mathew12 +mathew123 +mathews1 +mathias1 +mathieu1 +mathilda +mathilde +matias123 +matilda1 +matilde1 +matisse1 +matrassesotk +matrimonio +matrix00 +matrix007 +matrix01 +matrix10 +matrix11 +matrix12 +matrix123 +matrix13 +matrix21 +matrix22 +matrix23 +matrix69 +matrix99 +matt1234 +matt1988 +matt6288 +matthardy +matthardy1 +matthew! +matthew. +matthew0 +matthew01 +matthew02 +matthew03 +matthew04 +matthew05 +matthew06 +matthew07 +matthew08 +matthew09 +matthew1 +matthew10 +matthew11 +matthew12 +matthew123 +matthew13 +matthew14 +matthew15 +matthew16 +matthew17 +matthew18 +matthew19 +matthew2 +matthew20 +matthew21 +matthew22 +matthew23 +matthew24 +matthew25 +matthew26 +matthew3 +matthew4 +matthew5 +matthew6 +matthew69 +matthew7 +matthew77 +matthew8 +matthew88 +matthew9 +matthew95 +matthew98 +matthew99 +matthews +matthews1 +matthias +matthias1 +matthieu +mattingly +mattman1 +mattmatt +mattmatt1 +matty123 +matveev792010 +matveeva +matyas2001 +maulwurf +maureen1 +maurice1 +maurice2 +maurice3 +maurice4 +mauricio +mauricio1 +mauritius +maurizio +mautauaja +maver1ck +maverick +maverick1 +maverick12 +maverick2 +maverick7 +mavericks +mavericks1 +mavipies +mavriciy +mavrick1 +max.kirilov.90 +max12345 +max123456 +max_masha +maxamillion +maxchislov +maxie123 +maxim123 +maxim1935 +maxim3999 +maximilian +maximiliano +maximius +maximova.60 +maximova_elena77 +maximovie +maximum1 +maximus1 +maximus123 +maximus1393 +maximus2 +maxine123 +maxix565656 +maxmax123 +maxmaxmax +maxmotives +maxonina22 +maxpayne +maxpower +maxpower1 +maxpredator +maxthedog +maxwell01 +maxwell1 +maxwell11 +maxwell12 +maxwell123 +maxwell2 +maxwell3 +maxwell5 +maxwell7 +maya1234 +mayamaya +mayberry +mayfair1 +mayfield +mayfield1 +mayflower +mayflower1 +mayhem666 +maynard1 +mayquinn2 +mayra123 +mayrik67 +mazafaka +mazahaka +mazatlan +mazda123 +mazda323 +mazda323f +mazda626 +mazdamx3 +mazdamx5 +mazdamx6 +mazdarx7 +mazdarx8 +mazinger +mb123456 +mbahurip +mbtvibranike +mc123456 +mc9ad9w2ux +mcabdaw2vx +mccarthy +mccartney +mccormick +mcdonald +mcdonald1 +mcdonalds +mcdonalds1 +mcflurry! +mcfly123 +mcgrady1 +mcgregor +mchammer +mcintosh +mckayla1 +mckenna1 +mckenzie +mckenzie1 +mckinley +mckinley1 +mckinney +mclaren1 +mclarenf1 +mclovin1 +md1998pb +me123456 +meadows1 +meaghan1 +meandyou +meandyou1 +meandyou2 +meangirls1 +meatball +meatball1 +meatball99 +meatballs +meathead +meathead1 +meatloaf +meatloaf1 +meatwad1 +mecanica +mecanico +mechanic +mechanic1 +mechanical +mechelle +mede_voda +medecine +medeiros +medellin +medellin1 +media123 +mediawire +medical1 +medicina +medicine +medicine1 +medieval +medion123 +meditation +mediterraneo +medvedev +medvedeva +medvidek +meenakshi +megabyte +megadeath +megadeth +megadeth1 +megaman1 +megaman12 +megaman123 +megaman2 +megaman3 +megamanx +megamega +megan123 +meganfox +megaparol +megaparol12345 +megapolis +megasecret +megastar +megatron +megatron1 +meghan12 +mehmet123 +meinschatz +meister1 +meiyoumima +melancia +melanie! +melanie01 +melanie1 +melanie11 +melanie12 +melanie123 +melanie13 +melanie2 +melanie3 +melanie7 +melbourne +melbourne1 +melchior +melendez +melimelo +melinda1 +melissa! +melissa. +melissa01 +melissa07 +melissa08 +melissa09 +melissa1 +melissa10 +melissa11 +melissa12 +melissa123 +melissa13 +melissa14 +melissa15 +melissa16 +melissa17 +melissa18 +melissa19 +melissa2 +melissa21 +melissa22 +melissa23 +melissa24 +melissa25 +melissa3 +melissa4 +melissa5 +melissa6 +melissa69 +melissa7 +melissa8 +melissa9 +mellissa +melnikova +melocoton +melodie1 +melody12 +melody123 +melon123 +melrose1 +meltdown +melusine +melville +melvin12 +melvin123 +membership +meme1234 +mememe12 +mememe123 +memememe +memememe1 +mementomori +memorex1 +memorial +memorial1 +memories +memories1 +memphis1 +memphis10 +memphis2 +memphis901 +memyself +memyself&i +memyself1 +memyselfan +memyselfandi +memyselfi +mendoza1 +mengmeng +meninblack +menmenmen +mensuck1 +menthol1 +mentira1 +mentiras +mentiroso +meow1234 +meowmeow +meowmeow1 +meowmix1 +mephisto +mercado1 +merced209 +mercedes +mercedes01 +mercedes1 +mercedes11 +mercedes12 +mercedes123 +mercedes2 +mercedes3 +mercedes7 +mercedesbenz +mercedez +mercedez1 +merchant +mercredi +mercurial +mercurio +mercury1 +mercury7 +mercy123 +merda123 +merdaccia +meredith +meredith1 +merengue +merganser +meridian +meridian1 +merijaan +merlin01 +merlin11 +merlin12 +merlin123 +merlin13 +merlin69 +mermaid1 +mermaid2 +mermaids +merrick1 +merrill1 +mersedes +merveille +meshmesh +message1 +messages +messenger +messenger1 +messi123 +messiah1 +messier11 +metal123 +metal4ever +metal4life +metal666 +metalcore +metalgear +metalgear1 +metalhead +metalhead1 +metalica +metalica1 +metalika +metall1ca +metallic +metallica +metallica! +metallica. +metallica0 +metallica1 +metallica123 +metallica2 +metallica3 +metallica4 +metallica5 +metallica6 +metallica666 +metallica7 +metallica8 +metallica9 +metalman +metatron +meteora1 +methodist +methodman +methodman1 +metro123 +metro2033 +metroid1 +metropol +metropolis +mets1986 +mexicali +mexicali1 +mexican1 +mexican10 +mexican12 +mexican123 +mexican13 +mexican14 +mexican15 +mexican2 +mexican3 +mexican4li +mexican5 +mexican7 +mexicana +mexicana1 +mexicano +mexicano1 +mexicano13 +mexico#1 +mexico00 +mexico01 +mexico06 +mexico07 +mexico08 +mexico09 +mexico10 +mexico100 +mexico101 +mexico11 +mexico12 +mexico123 +mexico1234 +mexico13 +mexico14 +mexico15 +mexico16 +mexico17 +mexico18 +mexico19 +mexico20 +mexico2009 +mexico2010 +mexico21 +mexico22 +mexico23 +mexico24 +mexico25 +mexico619 +mexico69 +mexico77 +mexico86 +mexico88 +mexico90 +mexico99 +mgreen39 +mhaldita +mhinekoh +miahamm9 +miami123 +miami305 +miamibeach +miamiheat +miamiheat1 +miamiheat3 +miaomiao +miaumiau +micaela1 +mich3ll3 +michael! +michael. +michael0 +michael00 +michael01 +michael02 +michael03 +michael04 +michael05 +michael06 +michael07 +michael08 +michael09 +michael1 +michael10 +michael101 +michael11 +michael12 +michael123 +michael13 +michael14 +michael15 +michael16 +michael17 +michael18 +michael19 +michael2 +michael20 +michael200 +michael21 +michael22 +michael23 +michael24 +michael25 +michael26 +michael27 +michael28 +michael29 +michael3 +michael30 +michael31 +michael32 +michael33 +michael34 +michael4 +michael44 +michael5 +michael50 +michael55 +michael6 +michael69 +michael7 +michael77 +michael8 +michael84 +michael85 +michael86 +michael87 +michael88 +michael89 +michael9 +michael90 +michael91 +michael92 +michael93 +michael94 +michael95 +michael96 +michael97 +michael98 +michael99 +michaela +michaela1 +michaelj +michaeljac +michaeljackson +michaels +michaels1 +michal12 +michal123 +michalek +miche11e +micheal1 +micheal12 +micheal123 +micheal2 +micheal23 +micheal3 +micheal7 +michel123 +michel69.69 +michelangelo +michele1 +michele2 +michelin +micheline +michelino +michell1 +michelle +michelle! +michelle. +michelle0 +michelle00 +michelle01 +michelle02 +michelle03 +michelle05 +michelle06 +michelle07 +michelle08 +michelle09 +michelle1 +michelle10 +michelle11 +michelle12 +michelle123 +michelle13 +michelle14 +michelle15 +michelle16 +michelle17 +michelle18 +michelle19 +michelle2 +michelle20 +michelle21 +michelle22 +michelle23 +michelle24 +michelle25 +michelle26 +michelle27 +michelle28 +michelle29 +michelle3 +michelle30 +michelle33 +michelle4 +michelle5 +michelle6 +michelle69 +michelle7 +michelle77 +michelle8 +michelle88 +michelle89 +michelle9 +michelle99 +michi123 +michigan +michigan1 +michigan12 +michigan2 +michoacan +michoacan1 +mickey00 +mickey01 +mickey02 +mickey05 +mickey06 +mickey07 +mickey08 +mickey09 +mickey10 +mickey101 +mickey11 +mickey12 +mickey123 +mickey1234 +mickey13 +mickey14 +mickey15 +mickey16 +mickey17 +mickey18 +mickey19 +mickey20 +mickey21 +mickey22 +mickey23 +mickey24 +mickey25 +mickey27 +mickey28 +mickey33 +mickey69 +mickey77 +mickey88 +mickey99 +mickeymous +mickeymouse +micky123 +mickymouse +micorazon +micro123 +microbiology +microlab +microlad +microphone +microsoft +microsoft1 +microsoft2 +microwave +microwave1 +middleton +midland1 +midnight +midnight! +midnight01 +midnight1 +midnight10 +midnight11 +midnight12 +midnight13 +midnight2 +midnight22 +midnight3 +midnight4 +midnight5 +midnight6 +midnight69 +midnight7 +midnight8 +midnight9 +midnite1 +midwest1 +miercoles +mierda123 +miespacio1 +mifamilia +mifamilia1 +mightymouse +migrationsandeep +migrationschool +miguel01 +miguel10 +miguel11 +miguel12 +miguel123 +miguel13 +miguel14 +miguel15 +miguel17 +miguel18 +miguel21 +miguel22 +miguel23 +miguelange +miguelangel +miguelito +miguelito1 +miha-nov +mihail-saratov +mihail_alekseevskiy406 +mihailpezhemskii +mikael412 +mikaela1 +mikaella +mikalyalia +mikamika +mikayla1 +mike1234 +mike12345 +mike123456 +mike1985 +mike2000 +mike2006 +mike2007 +mike2008 +mike2009 +mike2010 +mike4ever +mike6453 +mikejones +mikejones1 +mikejones2 +mikemike +mikemike1 +miketyson +mikevick7 +mikey123 +mikhailova-w +mikhayildopy +mikimaus +mikimiki +mikolaj1 +mikomiko +mila90974 +milagros +milagros1 +milamber +milamila +milan123 +milan1899 +milan4ever +milanello +milanista +milanisti +milankasanakoeva +milanova-kira +milashka +milay-ven2011 +mildred1 +mildseven +milena699803 +milenium +miles123 +milesdavis +milestone +miley101 +miley123 +mileycyrus +milford1 +milhouse +militaire +military +military1 +milkbone +milkdud1 +milkman1 +milkmilk +milkshake +milkshake1 +milkshake2 +milkyway +milkyway1 +millencolin +millenium +millenium1 +millennium +miller01 +miller10 +miller11 +miller12 +miller123 +miller13 +miller21 +miller22 +miller23 +miller30 +miller31 +miller69 +millerlite +millertime +millhouse +millicent +millie01 +millie11 +millie12 +millie123 +milligan +million1 +million2 +millionair +millionaire +millioner +millions +millions1 +millonario +millonarios +millos13 +millsberry +millwall +millwall1 +milly123 +milo1234 +milomilo +milwaukee +milwaukee1 +mimamamemima +mimamima +mimi1234 +mimimimi +minakshi +minamina +mindanao +mindfreak +mindfreak1 +mindgame +mindless +mindless1 +mindy123 +mine1234 +mine4ever +minecraft +minecraft1 +minecraft12 +minecraft123 +minemine +minemine1 +mineonly +minerva1 +mingming +minhamae +minhasenha +minhavida +mini1234 +minicalibra +miniclip +miniclip1 +minicooper +minidisc +minimal1 +miniman1 +minime123 +minimini +minimoto +minimum1 +minister +minister1 +ministry +ministry1 +minkova_i +minnesota +minnesota1 +minnette +minnie01 +minnie10 +minnie11 +minnie12 +minnie123 +minnie13 +minnie22 +minniemous +minniemouse +minombre +minority +minotaur +minotauro +minoucha +minouche +minstrel +mintal24 +mir-180991 +miraa_84 +mirabella +mirabelle +miracle1 +miracle2 +miracle7 +miracles +miraflores +miramira +miranda1 +miranda11 +miranda12 +miranda123 +miranda13 +miranda2 +miranda3 +miranda5 +miranda7 +miranda9 +mirantte +mireille +mirellabroersma1987570 +miriam123 +mirlan_o +mironova +miroslav +miroslava +mirtillo +mis3amores +misamisa +misamores +misbebes +misch.sosnin +mischief +mischief1 +misericordia +misfits1 +misfits138 +misha123 +mishaghbdtn +mishanna1936 +mishanya +mishas001 +mishijos +mishmish +mishutka +misiaczek +misiaczek1 +misiek123 +miss-evgeniya-93 +miss.marina.nikolaeva.2013 +missbitch1 +missing1 +missingu +missingyou +mission1 +mission123 +mission2 +missionary +missions +mississipp +mississippi +mississippi1 +misskitty +misskitty1 +missmolly +missouri +missouri1 +misspiggy +misspiggy1 +misspriss +misspriss1 +missthang +missthang1 +missy101 +missy123 +missy1234 +missydog +missymoo +missyou1 +missyou2 +mistake1 +mister12 +mister123 +misterio +mistigri +mistress +mistress1 +misty123 +mistyblue +mistycat +mistydog +mitch123 +mitchel1 +mitchell +mitchell1 +mitchell12 +mitchell2 +mithrandir +mitia159 +mitsubishi +mittens1 +mittens2 +mityukova.anya +miuaybecv +mividaloca +mixaxa2003 +mixmaster +mixtape1 +miyamoto +miyvarxar +mizio970 +mj123456 +mjordan23 +mjuan5ogm +mk123456 +mkal2707 +mkalancea +mkjhgf1996 +mklmkl22 +mknaxhxeh8yp3tf +mko09ijn +mko0nji9 +mkolendzyan +mlqdakf8yt +mm123123 +mm123456 +mm170667 +mmakssimka +mmedinaa +mmmmmmm1 +mmmmmmmm +mmmmmmmmm +mmmmmmmmmm +mmo110110 +mnbmnbmnb +mnbvcxz1 +mnbvcxz12 +mnbvcxz123 +mnenrad6983616 +mo123456 +mob4life +mobbdeep +mobile123 +mobiline_b +mobster1 +mobsters1 +mobydick +moc.oohay +mocha123 +mockingbird +mod7tygrysow +model123 +modeling +modeling1 +moderncombat +modernwarf +modernwarfare +modernwarfare2 +modesto1 +modesto209 +modified +mogychajagopa +mohamed1 +mohamed12 +mohamed123 +mohammad +mohammad1 +mohammed +mohammed1 +mohammed123 +mohan123 +mohanlal +mohitb123 +moiettoi +moimoimoi +moinmoin +mojehaslo +mojisola +mojojojo +mojojojo1 +mojomojo +mojurus5575566 +molchanova_tlt +molko24bog +mollie01 +mollie12 +mollie123 +molly101 +molly123 +molly1234 +mollycat +mollydog +mollydog1 +mollygirl +mollygirl1 +mollymolly +mollymoo +mollymoo1 +mom12345 +mom4life +momanddad +momanddad1 +momanddad2 +momdad12 +momdad123 +momentum +momma123 +mommasboy1 +mommy101 +mommy123 +mommy1234 +mommy143 +mommy2be +mommydaddy +mommygirl1 +mommyof2 +mommyof3 +mommyof4 +mommysgirl +momndad1 +momo1234 +momomomo +momoney1 +momsgirl1 +mona1234 +monaghan +monalisa +monalisa1 +monaliza +monaliza2786 +monamona +monamour +monarch1 +moncheri +moncoeur +monday01 +monday11 +monday12 +monday123 +mondragon +money007 +money100 +money1000 +money101 +money111 +money123 +money1234 +money12345 +money2007 +money2008 +money2009 +money2010 +money2011 +money247 +money321 +money420 +money4940 +money4life +money4me +money666 +money777 +money888 +moneybag +moneybags +moneybags1 +moneyboy +moneyboy1 +moneymaker +moneyman +moneyman1 +moneyman12 +moneyman2 +moneyman87 +moneyme56 +moneymike1 +moneymoney +moneytalks +mongolia +mongoose +mongoose1 +monica01 +monica10 +monica11 +monica12 +monica123 +monica13 +monica14 +monica15 +monica21 +monica22 +monica23 +monica69 +monika11 +monika12 +monika123 +monimoni +monique01 +monique1 +monique11 +monique12 +monique123 +monique13 +monique2 +monique21 +monique23 +monique3 +monique4 +monique5 +monique7 +monitor1 +monkey00 +monkey007 +monkey01 +monkey02 +monkey03 +monkey04 +monkey05 +monkey06 +monkey07 +monkey08 +monkey09 +monkey10 +monkey100 +monkey101 +monkey11 +monkey111 +monkey12 +monkey123 +monkey1234 +monkey12345 +monkey13 +monkey14 +monkey15 +monkey16 +monkey17 +monkey18 +monkey19 +monkey20 +monkey21 +monkey22 +monkey23 +monkey24 +monkey25 +monkey26 +monkey27 +monkey28 +monkey29 +monkey30 +monkey31 +monkey32 +monkey321 +monkey33 +monkey34 +monkey42 +monkey420 +monkey44 +monkey45 +monkey55 +monkey56 +monkey66 +monkey666 +monkey67 +monkey68 +monkey69 +monkey76 +monkey77 +monkey777 +monkey78 +monkey79 +monkey80 +monkey81 +monkey82 +monkey83 +monkey84 +monkey85 +monkey86 +monkey87 +monkey88 +monkey89 +monkey90 +monkey91 +monkey911 +monkey92 +monkey93 +monkey94 +monkey95 +monkey96 +monkey97 +monkey98 +monkey99 +monkeyass1 +monkeyball +monkeyballs +monkeyboy +monkeyboy1 +monkeybut1 +monkeybutt +monkeyface +monkeygirl +monkeylove +monkeyman +monkeyman1 +monkeyman2 +monkeynuts +monkeypoo +monkeys! +monkeys1 +monkeys101 +monkeys11 +monkeys12 +monkeys123 +monkeys13 +monkeys2 +monkeys3 +monkeys4 +monkeys5 +monkeys7 +monkfish +monkies1 +monkmonk +monmouth +monolith +monomono +mononoke +monopoli +monopoly +monopoly1 +monoxide17 +monp5haynes +monserrat +monsieur +monsoon1 +monster! +monster. +monster0 +monster01 +monster08 +monster09 +monster1 +monster10 +monster101 +monster11 +monster12 +monster123 +monster13 +monster14 +monster15 +monster16 +monster17 +monster18 +monster2 +monster21 +monster22 +monster23 +monster24 +monster3 +monster33 +monster4 +monster5 +monster6 +monster666 +monster69 +monster7 +monster77 +monster8 +monster88 +monster9 +monster99 +monstercha +monsters +monsters1 +montagna +montagne +montague +montana1 +montana12 +montana123 +montana16 +montana2 +montana3 +montana7 +montblanc +montecarlo +montecristo +monteiro +montella +montenegro +monterey +monterey1 +montero1 +monterrey +monterrey1 +montessori +montevideo +montgom2409 +montgomery +monthy25 +montoya1 +montpellier +montreal +montreal1 +montrose +montserrat +monty123 +montydog +monument +moochie1 +moocow123 +mookie12 +mookie123 +moomoo11 +moomoo12 +moomoo123 +moomoo22 +moon1234 +moonbeam +moonbeam1 +moonchild +moondance +moondog1 +moonflower +moonlight +moonlight1 +moonlight2 +moonlight7 +moonlite +moonman1 +moonmoon +moonpie1 +moonraker +moonriver +moonshadow +moonshine +moonshine1 +moonspell +moonstar +moonstar1 +moonstone +moonwalk +moonwalker +moose123 +moosehead +mooseman +morales1 +morangos +mordva1783 +morelia1 +morelle45 +moremoney +moremoney1 +moremore +morena13 +morenaza +morenike +morenita +morenita1 +morenito +morgan00 +morgan01 +morgan02 +morgan03 +morgan04 +morgan05 +morgan06 +morgan07 +morgan08 +morgan09 +morgan10 +morgan11 +morgan12 +morgan123 +morgan13 +morgan14 +morgan15 +morgan16 +morgan17 +morgan18 +morgan21 +morgan22 +morgan23 +morgan24 +morgan69 +morgan98 +morgan99 +morgana1 +moriarty +morientes +morkovka +morning1 +morning21 +morningstar +morocco1 +morozova +morozovavalya28 +morpheus +morpheus1 +morphine +morrigan +morris12 +morris123 +morrison +morrison1 +morrissey +morrissey1 +morrowind +morrowind1 +mortadelo +mortalkombat +mortgage +mortgage1 +morticia +mortimer +mortimer1 +moschino +moscowcallin +moses123 +moshkin1998 +mosima11 +mosquito +mossberg +mossyoak +mossyoak1 +mostaganem +mostwanted +mot2passe +motdepasse +motdepasse1 +mother01 +mother02 +mother03 +mother10 +mother11 +mother12 +mother123 +mother1234 +mother13 +mother21 +mother22 +mother23 +mother69 +motherfuck +motherfucker +motherfucker1 +motherhood +motherland +motherlode +motherlove +mothermary +motherof2 +motherof3 +motherof4 +motherof5 +mothers1 +motherwell +motivated +motivation +motleycrue +motocros +motocross +motocross1 +motocross2 +motoguzzi +motomoto +motorbike +motorbike1 +motorcross +motorcycle +motorhead +motorhead1 +motorola +motorola1 +motorola12 +motorola2 +motorolav3 +motorolla +motorrad +motorsport +motrya.larina +mouhamed +moulinrouge +mouloudia +moumoune +mounette +mountain +mountain1 +mountain2 +mountainde +mountaindew +mountains +mountains1 +mouse123 +mousepad +mousetrap +moustache +moustapha +moustique +movement +movement1 +moviestar +movingon +movingon1 +movistar +mozellbranou81e +mozilla1 +mp3player +mpnaduysi +mr.stas192 +mrdmarina +mrf11277215 +mrkitty1 +mrniceguy +mrs.brown +ms.cc.gg +ms.dolgikh +ms.polza +ms0083jxj +ms123456 +mshelp12 +mtizndu2 +mu080295 +mu0lfpv2 +muaythai +muaythai1 +muchacha +muchlove +mudar123 +mudvayne +mudvayne1 +muenchen +muffdiver +muffin01 +muffin10 +muffin11 +muffin12 +muffin123 +muffin13 +muffin14 +muffin21 +muffin22 +muffin23 +muffin69 +muffinman +muffinman1 +muffins1 +mugwell15 +muhammad +muhammad1 +muhammed +muhammet +mulberry +mulligan +mulligan1 +multimedia +multipass +multipla +multiplelog +multisync +mumanddad +mumanddad1 +mummy123 +mummydaddy +mummypapa +munchie1 +munchies +munchies1 +munchkin +munchkin1 +municipal +munnabhai +munster1 +murakami +murat123 +murcielago +murder187 +murder666 +murdock1 +murielle +murmansk +murphy01 +murphy10 +murphy11 +murphy12 +murphy123 +murphy13 +murphy22 +murzilka +musa123456 +musashi1 +muscles1 +mushr00m +mushroom +mushroom1 +mushroomka +mushrooms +mushrooms1 +music000 +music101 +music123 +music1234 +music12345 +music2008 +music2009 +music2010 +music4ever +music4life +music4me +music666 +music=life +musica10 +musica123 +musical1 +musicbox +musician +musician1 +musicislif +musicislife +musiclove1 +musiclover +musicman +musicman1 +musicmusic +musicovery +musicrocks +musift10 +musique1 +muslimah +mussolini +mustafa1 +mustafa123 +mustang! +mustang. +mustang00 +mustang01 +mustang02 +mustang03 +mustang04 +mustang05 +mustang06 +mustang07 +mustang08 +mustang09 +mustang1 +mustang10 +mustang11 +mustang12 +mustang123 +mustang13 +mustang14 +mustang2 +mustang200 +mustang21 +mustang22 +mustang23 +mustang24 +mustang3 +mustang302 +mustang4 +mustang5 +mustang5.0 +mustang50 +mustang500 +mustang6 +mustang64 +mustang65 +mustang66 +mustang67 +mustang68 +mustang69 +mustang7 +mustang73 +mustang77 +mustang8 +mustang86 +mustang87 +mustang88 +mustang89 +mustang9 +mustang90 +mustang91 +mustang92 +mustang93 +mustang94 +mustang95 +mustang96 +mustang97 +mustang98 +mustang99 +mustanggt +mustanggt1 +mustangs +mustangs1 +mustapha +mustard1 +musyka85 +mutalim.gusenov +muthafucka +muttley1 +muzaffar +mv46vkmz10 +mxyzptlk +my-space +my.space +my123456 +my1andonly +my1space +my1stlove +my204856 +my2angels +my2babies +my2girls +my3angels +my3babies +my3girls +my3loves +my4babies +my4girls +my_komp_777 +my_space +myaccount +myaccount1 +myangel1 +myangels +mybabies +mybabies1 +mybabies2 +mybabies3 +mybaby01 +mybaby07 +mybaby08 +mybaby09 +mybaby12 +mybaby123 +mybaby13 +mybabyboy +mybabyboy1 +mybabygirl +mybirthday +mybitch1 +myblocker +mybossmyhero1 +mybrother +mybuddy1 +mybusiness +mychemical +mychemicalromance +mychildren +mycomputer +mydaddy1 +mydarling +mydestiny +mydreams +myebiz123 +myfamily +myfamily1 +myfamily4 +myfamily5 +myfather +myfriend +myfriend1 +myfriends +myfriends1 +myfuture +mygirls1 +mygirls2 +mygirls3 +mygirls4 +mygodisgood +myheart1 +myhoney1 +myhouse1 +myhumps1 +myhusband +myjesus1 +mykids02 +mykids03 +mykids04 +mykids123 +mylastfm +mylife08 +mylife09 +mylife11 +mylife12 +mylife123 +mylinkedin +mylove01 +mylove07 +mylove08 +mylove09 +mylove10 +mylove11 +mylove12 +mylove123 +mylove1234 +mylove12345 +mylove13 +mylove14 +mylove15 +mylove16 +mylove18 +mylove21 +mylove22 +mylove23 +mylove24 +mylove4u +mylove69 +mylovely +myloveone +mylover1 +mymommy1 +mymoney1 +mymother +mymother1 +mymusic1 +mymyspace +mymyspace1 +myname12 +myname123 +mynameis +mynameis1 +mynameiskhan +mynewlife +mynigga1 +mynumber1 +myparents +mypass123 +mypassphrase +mypassw0rd +mypassword +mypassword1 +myplace1 +myprince +myprincess +myrtille +myschool +mysecret +mysecret1 +myself123 +mysister +myspace! +myspace#1 +myspace* +myspace. +myspace.1 +myspace.co +myspace0 +myspace00 +myspace001 +myspace007 +myspace01 +myspace02 +myspace03 +myspace05 +myspace06 +myspace07 +myspace08 +myspace09 +myspace1 +myspace1! +myspace10 +myspace100 +myspace101 +myspace11 +myspace111 +myspace12 +myspace121 +myspace123 +myspace13 +myspace14 +myspace15 +myspace16 +myspace17 +myspace18 +myspace19 +myspace197 +myspace198 +myspace199 +myspace2 +myspace20 +myspace200 +myspace201 +myspace21 +myspace22 +myspace23 +myspace24 +myspace25 +myspace26 +myspace27 +myspace28 +myspace29 +myspace3 +myspace30 +myspace31 +myspace32 +myspace321 +myspace33 +myspace34 +myspace4 +myspace420 +myspace44 +myspace45 +myspace4me +myspace5 +myspace55 +myspace56 +myspace6 +myspace66 +myspace666 +myspace67 +myspace69 +myspace7 +myspace75 +myspace76 +myspace77 +myspace777 +myspace78 +myspace79 +myspace8 +myspace81 +myspace82 +myspace83 +myspace84 +myspace85 +myspace86 +myspace87 +myspace88 +myspace89 +myspace9 +myspace90 +myspace91 +myspace92 +myspace93 +myspace94 +myspace95 +myspace96 +myspace98 +myspace99 +myspace999 +myspace? +myspacepas +myspacesuc +mysterio +mysterio1 +mysterio61 +mysterio619 +mysterious +mystery1 +mystical +mystical1 +mystikal +mystique +mystuff1 +mythology +mythreesons +myworld1 +mzyankin +n0=acc3ss +n0vember +n1234567 +n12345678 +n123456789 +n1cholas +n2xcfgjcvr +n8zgt5p0shw= +n_pletneva +nacho123 +nacional +nacional1 +nacional10 +nadanada +nadezhda +nadia123 +nadine123 +nagamani +nagaraju +nagasaki +nagendra +nailpolish +nakamura +nallepuh +namaskar +namaste1 +namaste78 +nameless +nameless1 +nana1234 +nanakwame +nananana +nancy123 +nancydrew +nanda123 +nandhini +nando123 +nanny123 +nanonano +nanou4552 +nantes44 +nantucket +naomi123 +napolean +napoleon +napoleon1 +napoleone +napoletano +napoli10 +napoli1926 +napster1 +narashchivaiunoghti +narasimha +narayana +narayanan +narcisse +narendra +nargiz-a +narkoman +naruhina +narusegawa +naruto00 +naruto01 +naruto07 +naruto08 +naruto09 +naruto10 +naruto100 +naruto101 +naruto11 +naruto12 +naruto123 +naruto1234 +naruto13 +naruto14 +naruto15 +naruto16 +naruto17 +naruto18 +naruto19 +naruto20 +naruto21 +naruto22 +naruto23 +naruto24 +naruto25 +naruto33 +naruto45 +naruto55 +naruto666 +naruto69 +naruto77 +naruto88 +naruto89 +naruto90 +naruto91 +naruto92 +naruto924 +naruto93 +naruto94 +naruto95 +naruto96 +naruto97 +naruto98 +naruto99 +narutofan1 +narutokun +narutouzumaki +nascar01 +nascar03 +nascar08 +nascar09 +nascar11 +nascar12 +nascar123 +nascar14 +nascar17 +nascar18 +nascar20 +nascar24 +nascar29 +nascar38 +nascar48 +nascar88 +nascar99 +nascimento +nasfat12 +nashi1996 +nashville +nashville1 +nasigoreng +nastasia +nastenabendel +nastenka +nastina33592 +nastusha +nasty123 +nastya-b86 +nastya12 +nastya123 +nastya1995 +nastya1996 +nastya1997 +nastya1998 +nastya2010 +nastyaanciferova +nastyanastya +nastygirl +nastygirl1 +nata271283 +nata_titj25 +natacion +natalia1 +natalia12 +natalia123 +natalia2 +natalie! +natalie01 +natalie06 +natalie07 +natalie08 +natalie1 +natalie10 +natalie11 +natalie12 +natalie123 +natalie13 +natalie2 +natalie23 +natalie3 +natalie4 +natalie5 +natalie7 +natalie8 +natalie9 +natalija +natalina +nataliya +nataliystre +natalka1 +natalya.dmitrieva.1978 +natanael +natanata +natas666 +natascha +natasha1 +natasha11 +natasha12 +natasha123 +natasha13 +natasha2 +natasha3 +natasha7 +natasha_19.65 +natashka +natation +natatuma79 +nate1234 +natedog1 +natedogg +natedogg1 +nathalia +nathalie +nathalie1 +nathan00 +nathan01 +nathan02 +nathan03 +nathan04 +nathan05 +nathan06 +nathan07 +nathan08 +nathan09 +nathan10 +nathan11 +nathan12 +nathan123 +nathan1234 +nathan13 +nathan14 +nathan15 +nathan16 +nathan17 +nathan18 +nathan19 +nathan21 +nathan22 +nathan23 +nathan24 +nathan69 +nathan98 +nathan99 +nathanael +nathaniel +nathaniel1 +nathaniel2 +nati.beridze.92 +natiichen999 +national +national1 +natividad +natural1 +natureza +naughty1 +naughty69 +nausicaa +nautica1 +nautical +nautilus +navarro1 +navigator +navigator1 +navyblue +navyseal +navyseal1 +navyseals +nayarit1 +naynay12 +naynay123 +nazareno +nazareth +nazarova +nbuhtyjr +nbvbb32fa9 +nbvjityrj +ncabeax2vx +ncc-1701 +ncc1701a +ncc1701d +ncc1701e +ncc74656 +ncstate1 +nd2ia8v8az +ndacebx2wx +ndubuisi +nebraska +nebraska1 +necro666 +necromancer +necronomicon +nectar2011 +nederland +nederland1 +nedved11 +need4speed +needajob +needforspeed +needletail +needlove +needmoney +needwork +nefertari +nefertiti +negative +negative1 +neger123 +negrita1 +negrito1 +negro123 +neguinha +nehemiah +nehemiah1 +neighbor +nekoneko +nelly123 +nelson01 +nelson11 +nelson12 +nelson123 +nemesis1 +nemezida +nemochkao1975 +nemonemo +nemtudom +nenalinda +neng2000 +neopet12 +neopets1 +neopets10 +neopets11 +neopets12 +neopets13 +neopets22 +neophyte +nepal123 +nepenthe +nephilim +neptune1 +neronero +nesakysiu +neslihan +neslyxovska +nessa123 +nessa1234 +netball1 +netgear1 +netscape +netscape1 +netti-88 +network1 +network123 +networking +networks +nevaeh06 +nevaeh07 +nevaeh08 +never123 +never4get +never_desponding +neveragain +neverdie +neverever +neverever1 +neverforget +nevergiveu +nevergiveup +neverguess +neverland +neverland1 +nevermind +nevermind1 +nevermore +nevermore1 +neversaydie +neversayne +neversaynever +nevershout +nevertarget7 +neverwinter +neville1 +new-york +new975wen +new_user +newbaby1 +newborn1 +newcastle +newcastle1 +newcastle9 +newdelhi +newengland +newfoundland +newgame9 +newholland +newhope1 +newhouse +newhouse1 +newjersey +newjersey1 +newlife07 +newlife08 +newlife09 +newlife1 +newlife10 +newlife11 +newlife12 +newlife123 +newlife2 +newlife201 +newlife2010 +newlife2011 +newlife3 +newlife4me +newlife7 +newlove1 +newlove12 +newman12 +newmexico +newmexico1 +newmoney +newmoney1 +newmoon1 +newmoon2 +neworder +neworleans +neworleans12345 +newpass1 +newpasswor +newpassword +newport01 +newport1 +newport100 +newport12 +newport123 +newport2 +newport20 +newport3 +newport69 +newport7 +newports +newports1 +newshoes +newsletter +newspaper +newspaper1 +newstart +newstart1 +newthree51 +newuser1 +newvision +newworld +newyear08 +newyear09 +newyear1 +newyork! +newyork. +newyork01 +newyork07 +newyork08 +newyork09 +newyork1 +newyork10 +newyork11 +newyork12 +newyork123 +newyork13 +newyork14 +newyork2 +newyork21 +newyork22 +newyork23 +newyork3 +newyork4 +newyork5 +newyork6 +newyork69 +newyork7 +newyork8 +newyork9 +newyorkcity +newyorker +newyourk +newzealand +neymar11 +nezabudka +nfhfcjdf +nfnmzyrf +nfvthkfy +nfyznfyz +nglw9840 +ngockhoa +nguyen123 +nguyen4thewin +nha7ebf6kp +nhoemnhieu +niallhoran +nibbles1 +nicaragua +nicaragua1 +nicegirl +nicegirl1 +niceguy1 +nicenice +nicetry1 +nich0las +nichelle +nichelle1 +nicholas +nicholas! +nicholas. +nicholas01 +nicholas1 +nicholas10 +nicholas11 +nicholas12 +nicholas123 +nicholas13 +nicholas14 +nicholas16 +nicholas2 +nicholas21 +nicholas22 +nicholas3 +nicholas4 +nicholas5 +nicholas6 +nicholas7 +nicholas8 +nicholas9 +nichole1 +nichole12 +nichole123 +nichole2 +nichole3 +nichole7 +nichols1 +nicholson +nick1234 +nick12345 +nick2000 +nickcarter +nickelback +nicki123 +nickiminaj +nickjonas +nickjonas! +nickjonas1 +nickjonas2 +nickname +nicknick +nicknick1 +nickolas +nickolas1 +nicky123 +nico1234 +nicodemus +nicolas01 +nicolas1 +nicolas10 +nicolas12 +nicolas123 +nicolas2 +nicolas7 +nicole00 +nicole01 +nicole02 +nicole03 +nicole04 +nicole05 +nicole06 +nicole07 +nicole08 +nicole09 +nicole10 +nicole101 +nicole11 +nicole12 +nicole123 +nicole1234 +nicole13 +nicole14 +nicole15 +nicole16 +nicole17 +nicole18 +nicole19 +nicole20 +nicole21 +nicole22 +nicole23 +nicole24 +nicole25 +nicole26 +nicole27 +nicole28 +nicole29 +nicole30 +nicole31 +nicole32 +nicole33 +nicole34 +nicole44 +nicole69 +nicole77 +nicole82 +nicole83 +nicole84 +nicole85 +nicole86 +nicole87 +nicole88 +nicole89 +nicole90 +nicole91 +nicole92 +nicole93 +nicole94 +nicole95 +nicole96 +nicole97 +nicole98 +nicole99 +nicoleta +nicoletta +nicolette +nicolette1 +nicolina +nicolino +nicolle1 +niconico +nicotheo +nicotine +nideknil +nietzsche +niewiem1 +nigeria1 +nigerian +nigga101 +nigga123 +nigga4life +niggaplz1 +nigger11 +nigger12 +nigger123 +nigger13 +nigger22 +nigger23 +nigger420 +nigger666 +nigger69 +niggers1 +night123 +nightcrawler +nightfall +nightfire +nighthawk +nighthawk1 +nightingale +nightjar +nightmare +nightmare1 +nightmare2 +nightmare6 +nightowl +nightrider +nightshade +nightwing +nightwish +nightwish1 +nightwolf +nihao123 +niharika +nijmegen +nika_kisa88 +nikanika +nike1234 +nikeair1 +nikenike +nikiniki +nikita01 +nikita10 +nikita11 +nikita12 +nikita123 +nikita13 +nikita1995 +nikita1996 +nikita1997 +nikita1998 +nikita1999 +nikita2000 +nikita2001 +nikita2002 +nikita2010 +nikita98 +nikita99 +nikitina +nikitosik +nikki101 +nikki123 +nikki1234 +nikkisixx +nikola123 +nikolaev +nikolaeva +nikolaevna +nikolai1 +nikolas1 +nikolaus +nikolay_thebest +nikoleta +nikolina +nikoniko +nikprommet +nimbus2000 +nina1234 +ninanina +nineball +ninenine +niners49 +nineteen +nineteen19 +ningning +nininini +ninja101 +ninja123 +ninja250 +ninja636 +ninja666 +ninjaman +ninjasaga +ninjutsu +ninochka +ninonino +nintend0 +nintendo +nintendo1 +nintendo12 +nintendo2 +nintendo64 +nintendods +nipples1 +niranjan +nirankar +nirvana! +nirvana. +nirvana1 +nirvana11 +nirvana12 +nirvana123 +nirvana13 +nirvana2 +nirvana3 +nirvana5 +nirvana6 +nirvana666 +nirvana69 +nirvana7 +nirvana8 +nirvana9 +nirvana94 +nisha123 +nishizhu +nissan01 +nissan12 +nissan123 +nissan240 +nissan300 +nissan350 +nissan350z +nitin123 +nitro123 +nitrogen +nitrous1 +nittany1 +nivedita +nj2mp73t +nj9st4ye3f +njdevils +njhygtftb567 +nji90okm +nkechi12 +nks230kjs82 +nmt89109328673 +nnnnnnnn +nnnnnnnnnn +no1butme +no1cares +no1knows +noaccess +noaccess99 +noah1234 +noah2007 +noahsark +nochance +nocturne +nodefinido +nodnarb1 +nodoubt1 +nogueira +noiembrie +noisette +nokia1100 +nokia123 +nokia1234 +nokia12345 +nokia1600 +nokia2000 +nokia2700 +nokia3100 +nokia3110 +nokia3120 +nokia3200 +nokia3210 +nokia3220 +nokia3230 +nokia3250 +nokia3310 +nokia3650 +nokia5130 +nokia5200 +nokia5228 +nokia5230 +nokia5300 +nokia5310 +nokia5320 +nokia5530 +nokia5610 +nokia5700 +nokia5800 +nokia6020 +nokia6120 +nokia6131 +nokia6210 +nokia6230 +nokia6230i +nokia6233 +nokia6280 +nokia6300 +nokia6303 +nokia6500 +nokia6600 +nokia6610 +nokia6630 +nokia6680 +nokia6700 +nokia7210 +nokia7610 +nokia8210 +nokia8800 +nokiae51 +nokiae63 +nokiae65 +nokiae71 +nokian70 +nokian72 +nokian73 +nokian80 +nokian81 +nokian82 +nokian90 +nokian95 +nokian97 +nokianokia +nolimit1 +nolimits +nolongthing +nomeacuerdo +nomelase +nomercy1 +nomorerack +noname123 +noncapa09 +nonenone +nonmember +nononono +nonpayment +nonsense +nonudity! +noobnoob +noodle12 +noodle123 +noodles1 +noodles123 +noodles2 +nooneknows +nopasaran +nopasswo +nopassword +noproblem +noranora +norbert1 +norberto +norcal14 +noregrets +noregrets1 +norfolk1 +norma123 +normajean +normajean1 +norman12 +norman123 +normandie +normandy +norteno14 +north123 +northeast +northeast1 +northern +northern1 +northshore +northside +northside1 +northside2 +northside4 +northstar +northstar1 +northwest +northwest1 +northwood +norwegen +norwich1 +norwood1 +nosferatu +nosferatu1 +nosmoking +nosoup4u +nostalgia +nostradamus +nostress +nostromo +not4u2no +not_needed +notagain +notagain1 +notebook +notebook1 +notforyou +nothanks +nothing! +nothing. +nothing0 +nothing1 +nothing11 +nothing12 +nothing123 +nothing2 +nothing3 +nothing7 +nothings123 +notorious +notorious1 +notreal1 +notredame +notredame1 +notrust1 +nottelling +nottingham +notvalid +notyours +notyours1 +nounette +nounoune +nounours +nov151963 +novanova +novartis +novasenha +novell123 +november +november01 +november05 +november06 +november07 +november08 +november09 +november1 +november10 +november11 +november12 +november13 +november14 +november15 +november16 +november17 +november18 +november19 +november2 +november20 +november21 +november22 +november23 +november24 +november25 +november26 +november27 +november28 +november29 +november3 +november30 +november4 +november5 +november6 +november7 +november8 +november9 +novembre +novembro +novgorod +noviembre +noviembre1 +noviembre2 +novikova +novosibirsk +noway123 +nowayjose +nowayout +nowehaslo +nowitzki41 +noworries +nrfxtyrj +nssadmin +nthvbyfnjh +ntktdbpjh +nuclear1 +nuevavida +nugget12 +nuggets1 +nuggets15 +nuggets3 +number01 +number10 +number11 +number12 +number123 +number13 +number14 +number15 +number16 +number17 +number18 +number19 +number1dad +number1fan +number1mom +number1son +number20 +number21 +number22 +number23 +number24 +number25 +number27 +number32 +number33 +number34 +number41 +number44 +number55 +number69 +number88 +number99 +numberone +numberone1 +numbers1 +numbers123 +numbnuts +numero10 +numerouno +numlock1 +nummero1 +nuncamas +nuo0725nuo +nupe1911 +nurse123 +nursing08 +nursing1 +nursultan +nurudeen +nusha.88 +nutcracker +nutella1 +nutrition +nutsack1 +nuttertool +nuttertools +nwo4life +nygiants +nygiants1 +nyknicks +nyq28giz1z +nyyankees +nyyankees1 +o0o0o0o0 +o1234567 +o123456789 +o67l2xzfvn +o8lhe2z7bo +oakcliff1 +oakland1 +oakland510 +oakridge +oaktree1 +oakwood1 +oasis123 +oassw0rd +oatmeal1 +obama2008 +obama2009 +obi4amte +obituary +oblivion +oblivion1 +obsession +obsidian +obvious1 +oc247ngucz +ocean123 +oceans11 +oceans12 +oceanside +oceanside1 +ocpoook325 +octavia1 +octavian +octavio1 +october01 +october02 +october03 +october05 +october06 +october07 +october08 +october09 +october1 +october10 +october11 +october12 +october13 +october14 +october15 +october16 +october17 +october18 +october19 +october2 +october20 +october21 +october22 +october23 +october24 +october25 +october26 +october27 +october28 +october29 +october3 +october30 +october31 +october4 +october5 +october6 +october7 +october8 +october9 +octopus1 +oddball1 +oddworld +odysseus +odyssey1 +odz1w1rb9t +office123 +officer1 +official +official1 +offroad1 +offshore +offspring +offspring1 +offthewall +oficinag3 +ogplanet +ohcaptain +ohiostate +ohiostate1 +ohiostate2 +ohmnamah23 +ohmygod! +ohmygod1 +ohmygosh +oinkoink +ok123456 +okcomputer +okechukwu +okiedokie +okinawa1 +oklahoma +oklahoma1 +okmijnuhb +okokokok +oks65b6666 +oksana130279 +oksanaorgadykova +oksanav-13 +oladimeji +oladipupo +olajumoke +olakunle +olalekan +olalekan1 +olamide1 +olamilekan +olanrewaju +olaolaola +olaoluwa +olarewaju +olasunkanmi +olatunde +olatunji +olawale1 +olawunmi +olayinka +olayinka1 +olayiwola +oldfart1 +oldnavy1 +oldschool +oldschool1 +oldskool +oldskool1 +oldsmobile +oldspice +oldspice1 +oldtimer +oldtrafford +oleander +olechka061187 +oleg-andry +oleg.jann +oleg1992 +oleg1995 +oleg1996 +oleg1997 +oleg1998 +oleg272727 +oleginator1 +olegoleg +olegshut +olemiss1 +olesya.kolchina +olga.kazakova_85 +olga.lekarewa +olga.ponomarenko.2012 +olga.rumyanceva.1985 +olga1234 +olga1987 +olga2010 +olgaolga +olgastrashney +olgha.pietrova.1979 +olimpia1 +olitec00 +olivares +olive123 +oliveira +olivejuice +oliveoil +oliver00 +oliver01 +oliver06 +oliver07 +oliver08 +oliver09 +oliver10 +oliver11 +oliver12 +oliver123 +oliver13 +oliver14 +oliver15 +oliver16 +oliver21 +oliver22 +oliver23 +oliver69 +oliver77 +oliver88 +oliver99 +olivetti +olivia01 +olivia02 +olivia03 +olivia04 +olivia05 +olivia06 +olivia07 +olivia08 +olivia09 +olivia10 +olivia11 +olivia12 +olivia123 +olivia13 +olivia14 +olivia15 +olivia16 +olivia21 +olivia22 +olivia23 +olivia99 +olivier1 +ollie123 +olo65b6666 +ololo123 +ololoeva-99 +olqa_motosova +olubunmi +olufiz14 +olugbenga +olumide1 +olusegun +olushola +oluwadare +oluwafemi +oluwakemi +oluwasegun +oluwaseun +oluwaseun1 +oluwaseyi +oluwatobi +oluwatosin +oluwatoyin +olya.i.02 +olyashev12 +olympia1 +olympiakos +olympic1 +olympics +olympique +olympus1 +omar1234 +omarbravo9 +omarion1 +omarion2 +omarion21 +omaromar +omega123 +omegared +omg12345 +omgomg123 +omgomgomg +omgwtfbbq +omnamahshivay +omnislash +omowunmi +omsainath +omsairam +omsakthi +omshanti +omshantiom +omsrisairam +onamrdiu +one1love +one1two2 +one23456 +one2three +one2three4 +oneandonly +oneblood +oneblood1 +onedirecti +onedirection +onelove! +onelove. +onelove1 +onelove12 +onelove123 +onelove13 +onelove2 +onelove3 +onelove4 +onelove420 +onelove69 +onelove7 +onemoretime +onepiece +onepiece1 +onetime1 +onetreehill +onetwo12 +onetwo34 +onetwothree +onimusha +online12 +online123 +only14me +only1god +only1love +only4you +onlylove +onlyone1 +onlyyou1 +onmyown1 +ontario1 +ontheroad +onyebuchi +oogabooga +ooicu812 +oojs4ykl +oooo0000 +oooooooo +oooooooooo +opelastra +opelastra123 +opelcorsa +opelvectra +open1234 +opendoor +opennow1 +openopen +opensaysme +opensesame +operation +operation1 +operations +operator +operator1 +opernhaus1 +opeyemi1 +ophelia1 +opiumbaron +opopopop +opportunity +optical1 +optimist +optimistic +optimus1 +optimusprime +optiplex +optiplex1 +optiquest +oracle123 +orange01 +orange07 +orange08 +orange09 +orange10 +orange11 +orange12 +orange123 +orange1234 +orange13 +orange14 +orange15 +orange16 +orange17 +orange18 +orange19 +orange20 +orange21 +orange22 +orange23 +orange24 +orange25 +orange27 +orange33 +orange44 +orange55 +orange66 +orange69 +orange77 +orange88 +orange99 +orangejuice +oranges1 +oranges2 +orangina +orangutan +orchard1 +orchestra +orchidea +orchidee +ordenador +ordinary +ordinateur +orellana +oreo1234 +oreocookie +oreoluwa +oreooreo +organic1 +oriental +oriflame +oriflame_1910 +original +original1 +original21 +orioles1 +orion123 +orlando! +orlando1 +orlando11 +orlando12 +orlando123 +orlando13 +orlando2 +orlando3 +orlando5 +orlando7 +orlandobloom +orleans1 +orochimaru +orologio +orquidea +orthodox +orwell1984 +osbourne +oscar123 +oscar1234 +oscardog +oscardog1 +oscarito +oscarwilde +oskar123 +osman123 +ossi2000 +osvaldo1 +oswaldo1 +osynadepu +othello1 +otherside +ottootto +ou171423 +ou29q6666 +ou812345 +ou8124me +ou8125150 +ou812ou812 +ouk29q6666 +our3kids +outback1 +outcast1 +outdoors +outkast1 +outlander +outlaw69 +outlaws1 +outlawz1 +outreach +outside1 +outsider +outsider1 +outsiders +ovation1 +ovechkin +ovechkin8 +over2yangshuo +over9000 +overcome +overcomer +overdose +overdrive +overflow +overkill +overkill1 +overload +overlook +overlord +overlord1 +override +overseas +overtime +ovr220278 +owahodarea +ownage123 +owned123 +owner@hr.com +owt243ygbh +owt243ygbj +oxnard805 +oxymoron +oyekunle +oyindamola +p00hbear +p00pp00p +p0o9i8u7 +p0o9i8u7y6 +p0rnstar +p1234567 +p12345678 +p123456789 +p1466186 +p1assword1 +p1p2p3p4 +p1ssword +p2ssw0rd +p2ssword +p2wcffjcvr +p2xcfgjcvr +p3avbwjw +p3rat54797 +p455w0rd +p455word +p4ssw0rd +p4ssword +p4vkinrw6x +p51mustang +p5415420 +p6264758 +p7678287 +p8ntball +p@$$w0rd +p@$$word +p@55w0rd +p@55word +p@ssw0rd +p@ssword +p@ssword1 +pa$$w0rd +pa$$word +pa1ub65udd +pa22word +pa33word +pa44word +pa55w0rd +pa55word +pa55wrd1 +pa88word +pablito1 +pablo123 +pacers31 +pacheco1 +pachuca1 +paciencia +pacific1 +pacifica +pacifico +packard1 +packardbell +packers04 +packers1 +packers12 +packers123 +packers2 +packers4 +pacman12 +pacman123 +pacopaco +paddington +paddy123 +padilla1 +padmavathi +padrepio +paganini +pagedown +paige123 +painislove +painkiller +painless +paintball +paintball0 +paintball1 +paintball2 +paintball3 +paintball4 +paintball5 +paintball7 +paintball8 +paintball9 +painter1 +painting +painting1 +paisley1 +pajarito +pakalolo +pakistan +pakistan1 +pakistan12 +pakistan123 +pakistan12345 +pakistan1947 +pakistan2 +pakistan47 +pakistan786 +pakistani +pakistani1 +pakkness +palacios +paladin1 +palangga +palembang +palencia +palermo1 +palestina +palestine +palestine1 +palestra +pallavolo +pallmall +pallmall1 +palmeiras +palmetto +palmtree +palmtree1 +palmtrees +paloalto +paloma123 +palomino +palomita +paluso00 +pamela01 +pamela11 +pamela12 +pamela123 +pamelita +pampers1 +pamplona +panasonic +panasonic1 +panasonik +panatha13 +panathinaikos +pancake1 +pancakes +pancakes1 +panchita +panchito +panchito1 +pancho12 +pancho123 +pancho13 +panda101 +panda123 +panda_3108 +pandabear +pandabear1 +pandapanda +pandemonium +pandora1 +panganiban +pangeran +pangetako +pangetka +pangitka +panic123 +pankaj123 +panmen188 +pannekoek +panocha1 +panorama +pantalon +pantera1 +pantera12 +pantera123 +pantera2 +pantera3 +pantera6 +pantera666 +pantera69 +panther1 +panther10 +panther11 +panther12 +panther123 +panther13 +panther2 +panther21 +panther3 +panther4 +panther5 +panther6 +panther7 +panther9 +panthera +panthere +panthers +panthers! +panthers08 +panthers09 +panthers1 +panthers10 +panthers11 +panthers12 +panthers13 +panthers2 +panthers23 +panthers3 +panthers5 +panthers7 +panthers89 +panties1 +pantyhose +pantyhose1 +paokara4 +paola123 +paoletta +paolo123 +papa1234 +papabear +papabear1 +papacito +papagaio +papamama +papamama1 +papamaman +papamummy +papapapa +paparazi +paparazzi +paparoach +paparoach1 +papasito +papasito1 +papaslexzy +papasmurf +papasmurf1 +papatoma1 +paper123 +paperboy +paperboy1 +paperclip +paperclip1 +papercut +papercut1 +paperina +paperino +papermate +papermate1 +papichulo +papichulo1 +papillon +papillon1 +papoose1 +papounet +pappa123 +pappagallo +paprika1 +papuskin +parabellum +parabola +paracetamol +parachute +paradigm +paradigma +paradise +paradise1 +paradise2 +paradise7 +paradiso +paradox1 +paragon1 +paraguay +parakeet +paralegal +paralelepipedo +paramedic +paramedic1 +paramore +paramore! +paramore1 +paramore12 +paramount +paramount1 +paranoia +paranoid +paranoid1 +paranormal +parasite +parents1 +parfenovav +paris123 +paris2010 +parishilton +parisien +parisparis +parker01 +parker08 +parker09 +parker10 +parker11 +parker12 +parker123 +parker13 +parker22 +parkour1 +parkside +parkside1 +parkview +parkway1 +parlament +parliament +parol123 +parola12 +parola123 +parola33 +parolamea +parolparol +parrish1 +parrotlet +parsifal +parsons1 +partizan +partizan1 +partner1 +partners +partridge +partsites +party101 +party123 +partyboy +partyboy1 +partygirl +partygirl1 +partyhard1 +partyof5 +partyone +partytime +partytime1 +parvathi +parvathy +pasadena +pasadena1 +pasaway1 +pascaline +pasha123 +paska123 +pasodeblas +paspass1234 +pasquale +pass-word +pass.word +pass1234 +pass12345 +pass123456 +pass12sa +pass1478 +pass1word +pass2244 +pass2word +pass4word +pass9876 +pass@123 +pass@word1 +pass_2011 +pass_rrewq +pass_rrr +pass_word +passcode +passcode1 +passenger +passer2009 +passer2010 +passer2011 +passerotto +passion1 +passion12 +passion123 +passion2 +passion3 +passion4 +passion69 +passion7 +passion8 +passionate +passione +passions +passions1 +passord1 +passover +passpass +passpass1 +passport +passport1 +passrett222 +passsword +passw0rd +passw0rd! +passw0rd1 +passw3rd +passward +passward1 +passwerd +passwerd1 +passwor1 +password +password! +password!! +password#1 +password* +password-1 +password. +password.. +password.1 +password0 +password00 +password001 +password007 +password01 +password02 +password03 +password04 +password05 +password06 +password07 +password08 +password09 +password1 +password1! +password1. +password10 +password100 +password101 +password11 +password111 +password12 +password123 +password1234 +password12345 +password123456 +password1234567 +password12345678 +password123456789 +password13 +password14 +password15 +password16 +password17 +password18 +password19 +password2 +password20 +password2010 +password2011 +password21 +password22 +password23 +password24 +password25 +password26 +password27 +password28 +password29 +password3 +password30 +password31 +password32 +password321 +password33 +password34 +password35 +password36 +password37 +password4 +password40 +password41 +password42 +password420 +password43 +password44 +password45 +password47 +password5 +password50 +password51 +password52 +password54 +password55 +password56 +password57 +password6 +password64 +password65 +password66 +password666 +password67 +password69 +password7 +password71 +password72 +password73 +password74 +password75 +password76 +password77 +password777 +password78 +password79 +password8 +password80 +password81 +password82 +password83 +password84 +password85 +password86 +password87 +password88 +password89 +password9 +password90 +password91 +password92 +password93 +password94 +password95 +password96 +password97 +password98 +password99 +password: +password? +password@1 +password@123 +password_1 +password_rr +passwordd +passwordd1 +passwordko +passwordnew +passwordpassword +passwords +passwords1 +passworld +passwort +passwort! +passwort1 +passwort12 +passwort123 +pasta123 +pastis51 +pastorius +pastrana +pasuma12 +paswoord +pasword1 +pasword123 +patagonia +patanahi +patapouf +patatina +patch123 +patches01 +patches1 +patches11 +patches12 +patches123 +patches2 +patches3 +patches7 +paterson +paterson1 +pathetic +pathfinder +pathology +patience +patience1 +patitofeo +patrice1 +patricia +patricia1 +patricia12 +patricia2 +patricia3 +patricio +patricio1 +patrick! +patrick. +patrick01 +patrick07 +patrick08 +patrick09 +patrick1 +patrick10 +patrick11 +patrick12 +patrick123 +patrick13 +patrick14 +patrick15 +patrick16 +patrick17 +patrick18 +patrick2 +patrick21 +patrick22 +patrick23 +patrick24 +patrick3 +patrick4 +patrick5 +patrick6 +patrick69 +patrick7 +patrick8 +patrick9 +patriot1 +patriots +patriots1 +patriots12 +patriots2 +patrizia +patrizio +patrycja +patrycja1 +patryk123 +patterson +patterson1 +pattinson +patty123 +pattycake +paul1234 +paula123 +paulchen +paulette +paulette1 +paulina1 +paulina123 +pauline1 +paulinha +paulinho +paulinka +pauljohn +paulo123 +paulpaul +paulwall1 +pavankumar +pavel123 +pavement +pavilion +pavilion1 +pavithra +pavlenko +pawel123 +pawelek1 +payaso13 +payback1 +payton01 +payton12 +payton34 +pazeamor +pazyamor +pazzainter +pazzword +pazzword123 +pbvfktnj +pcwac33gb9 +pdbdfby2xx +pdtpljxrf +pe#5gz29ptzmse +peabody1 +peace&love +peace101 +peace123 +peace1234 +peace420 +peace4all +peace4me +peaceandlo +peaceandlove +peaceful +peaceful1 +peacelove +peacelove1 +peacemaker +peaceman +peaceout +peaceout1 +peach123 +peaches! +peaches01 +peaches08 +peaches09 +peaches1 +peaches10 +peaches11 +peaches12 +peaches123 +peaches13 +peaches2 +peaches21 +peaches22 +peaches23 +peaches3 +peaches4 +peaches5 +peaches6 +peaches69 +peaches7 +peaches8 +peaches9 +peachtree +peacock1 +peanut00 +peanut01 +peanut02 +peanut03 +peanut04 +peanut05 +peanut06 +peanut07 +peanut08 +peanut09 +peanut10 +peanut101 +peanut11 +peanut12 +peanut123 +peanut1234 +peanut13 +peanut14 +peanut15 +peanut16 +peanut17 +peanut18 +peanut21 +peanut22 +peanut23 +peanut24 +peanut33 +peanut69 +peanut77 +peanut88 +peanut99 +peanutbutt +peanutbutter +peanuts1 +peanuts2 +peanuts5 +pearl123 +pearljam +pearljam1 +pearljam10 +pearson1 +pebbles01 +pebbles1 +pebbles12 +pebbles123 +pebbles2 +pebbles3 +pebbles7 +pebdfcz3yx +pebefcz3yx +peckerwood +pedagogia +pedarsag +pedersen +pedigree +pedrinho +pedrito1 +pedro123 +peekab00 +peekaboo +peekaboo1 +peepers1 +peewee11 +peewee12 +peewee123 +peewee13 +pegasus1 +peggy123 +peggysue +peinture +pekanbaru +pekida30 +peleleco +pelican1 +pelicano +pelon123 +pelotudo +peluche1 +peluchin +pelusita +pembroke +pencil12 +pencil123 +pendeja1 +pendejo1 +pendragon +pendragon1 +pendulum +penelopa +penelope +penelope1 +pengpeng +penguin! +penguin1 +penguin11 +penguin12 +penguin123 +penguin13 +penguin2 +penguin22 +penguin3 +penguin4 +penguin5 +penguin7 +penguin8 +penguin9 +penguins +penguins1 +penis123 +penis666 +pennstate +pennstate1 +penny123 +pennydog +pennylane +pennylane1 +pennywise +pennywise1 +pensacola +pensacola1 +penshoppe +pentagon +pentagram +penthouse +pentium1 +pentium2 +pentium3 +pentium4 +people11 +people12 +people123 +people22 +peoples1 +pepe1234 +pepepepe +peperoni +pepper00 +pepper01 +pepper02 +pepper06 +pepper07 +pepper08 +pepper09 +pepper10 +pepper101 +pepper11 +pepper12 +pepper123 +pepper1234 +pepper13 +pepper14 +pepper15 +pepper16 +pepper21 +pepper22 +pepper23 +pepper24 +pepper33 +pepper69 +pepper77 +pepper88 +pepper99 +pepperdog +peppermint +pepperoni +pepperoni1 +peppers1 +pepsi101 +pepsi123 +pepsicola +pepsicola1 +pepsimax +pepsimax1 +percival +percussion +peregrine +perempuan +perez123 +perfect1 +perfect10 +perfect12 +perfect123 +perfect2 +perfect7 +perfection +perfecto +performance +perfume1 +pericles +periwinkle +perkele1 +perkins1 +permanent +pernille +perpignan +perrito1 +perritos +perro123 +perroloco +perry123 +persempre +persephone +pershing +persian1 +persimmon +personal +personal1 +personale +personne +personnel +pervert1 +pescador +pesciolino +peshawar +petanque +peter123 +peter1234 +peterbilt +peterbilt1 +peterbuilt +peterburg +peterpan +peterpan1 +peterpan2 +peterpeter +petersen +peterson +peterson1 +peterson28 +petewentz +petewentz1 +petey123 +petra123 +petrenko +petroleum +petronas +petrovich +petrovna +petrucci +petruska +petunia1 +peugeot1 +peugeot106 +peugeot206 +peugeot306 +peugeot307 +peugeot406 +pewdiepie +peyton01 +peyton08 +peyton12 +peyton18 +pfchfytw +pfqxjyjr +pfqxtyjr +pg260365 +phantom1 +phantom2 +phantom7 +phantoms +pharmacie +pharmacist +pharmacy +pharmacy1 +pharrell +phatboy1 +phatfarm +pheasant +pheonix1 +phialpha +philadelphia +philip12 +philip123 +philipp1 +philippa +philippe +philippe1 +philippine +philippines +philips1 +philips123 +phillies +phillies08 +phillies1 +phillip1 +phillip123 +phillip2 +phillips +phillips1 +philly123 +philly215 +philomena +philosophy +phish420 +phoebe01 +phoebe12 +phoebe123 +phoenix! +phoenix01 +phoenix1 +phoenix11 +phoenix12 +phoenix123 +phoenix13 +phoenix2 +phoenix3 +phoenix5 +phoenix602 +phoenix69 +phoenix7 +phoenix8 +phoenix888 +phoenix9 +phone123 +photo123 +photograph +photography +photoshop +phyllis1 +physical +physics1 +pi314159 +piankova72 +piano123 +pianoforte +pianoman +pianoman1 +piazza31 +picasso1 +piccione +piccolina +piccolo1 +pickle11 +pickle12 +pickle123 +pickle13 +pickles! +pickles1 +pickles12 +pickles123 +pickles2 +pickles3 +pickles7 +pickwick +picture1 +pictures +pictures1 +piedmont +pieface1 +pieisgood +pierce34 +piercing +pierluigi +pierpaolo +pierre123 +pierrick +piggies1 +piggy123 +piglet01 +piglet12 +piglet123 +pikachu1 +pikachu12 +pikachu123 +pikachu2 +pikachu25 +pikapika +pilchard +pilgrim1 +piligrim +pilipinas +pilipino +pillow123 +pilot123 +pimentel +pimousse +pimp1234 +pimp12345 +pimp2006 +pimp4life +pimpdaddy +pimpdaddy1 +pimpdaddy2 +pimpette +pimpette1 +pimpin01 +pimpin06 +pimpin07 +pimpin08 +pimpin09 +pimpin10 +pimpin101 +pimpin11 +pimpin12 +pimpin123 +pimpin13 +pimpin14 +pimpin15 +pimpin16 +pimpin21 +pimpin22 +pimpin23 +pimpin24 +pimpin420 +pimpin69 +pimping1 +pimpjuice +pimpjuice1 +pimpman1 +pimpollo +pimppimp +pimppimp1 +pimpshit +pimpshit1 +pimpster +pimpster1 +pinacolada +pinarello +pinball1 +pincopallino +pindakaas +pineapple +pineapple! +pineapple1 +pineapple2 +pineapple3 +pineapple7 +pineapples +pinecone +pinecone1 +pinetree +pinetree1 +pinewood +pingouin +pingping +pingpong +pingpong1 +pinguino +pinhead1 +pinheiro +pink1234 +pink12345 +pinkerton +pinkflower +pinkfloyd +pinkfloyd1 +pinkgirl +pinkgirl1 +pinklady +pinklady1 +pinklove +pinklove1 +pinklover +pinklover1 +pinkness +pinkpanthe +pinkpanther +pinkpink +pinkpink1 +pinkrose +pinkrose1 +pinkstar +pinky101 +pinky123 +pinnacle +pinnacle1 +pinocchio +pinoyako +pinuccio +pioneer1 +pioneers +piotrek1 +pioupiou +pipeline +pipeline1 +piper123 +pipi1000 +pipicaca +pipopipo +pippen33 +pippo123 +pippopippo +piramida +piramide +pirate12 +pirate123 +pirate13 +pirates! +pirates1 +pirates12 +pirates123 +pirates2 +pirates3 +pirouette +pirulito +pisellino +pisellone +pisicuta +pissedoff +pissedoff1 +pissoff1 +pistache +pistons1 +pitagoras +pitapooe1 +pitbull1 +pitbull12 +pitbull123 +pitbull13 +pitbull2 +pitbull23 +pitbull3 +pitbull5 +pitbull69 +pitbull7 +pitbulls +pitbulls1 +pitcher1 +pitchoune +pitiponc +pittbull +pittbull1 +pittsburgh +pitufina +pixie123 +pixiedust +pixiedust1 +pizza101 +pizza123 +pizza1234 +pizzaboy +pizzahut +pizzahut1 +pizzaman +pizzaman1 +pizzapie +pizzapie1 +pizzapizza +pizzeria +pk3x7w9w +placebo1 +placement +planb123 +plankova2012 +plankton +planner1 +planning +plastic1 +plastics +platano1 +platinum +platinum1 +platypus +platypus1 +play2win +play4fun +playa123 +playa4life +playball +playball1 +playbill +playboi1 +playboy! +playboy. +playboy01 +playboy07 +playboy08 +playboy09 +playboy1 +playboy10 +playboy101 +playboy11 +playboy12 +playboy123 +playboy13 +playboy14 +playboy15 +playboy16 +playboy17 +playboy18 +playboy2 +playboy21 +playboy22 +playboy23 +playboy3 +playboy4 +playboy5 +playboy6 +playboy69 +playboy7 +playboy8 +playboy9 +playboys +player01 +player07 +player08 +player09 +player10 +player101 +player11 +player12 +player123 +player13 +player14 +player15 +player16 +player17 +player18 +player21 +player22 +player23 +player24 +player69 +players1 +playful1 +playgame +playgames +playgirl +playgirl1 +playgirl69 +playground +playgurl +playhard +playing1 +playmaker +playmate +playmate1 +playplay +playstatio +playstation +playstation1 +playstation2 +playstation3 +playtime +playtime1 +pleasant +pleasant1 +please11 +please12 +please123 +pleaseme +pleasure +pleasure1 +pletnevakaterina +pljhjdmt +plokijuh +plombier +plopplop +ploppy10 +plumber1 +plumbing +plumbing1 +plumeria +pluto123 +plymouth +plymouth1 +pnufsci218 +pocahontas +pochacco +pocket12 +pockets1 +pocoloco +poderosa +poderoso +podolski +podstava +poepen19 +pogiako1 +pogiako123 +pohekale +poilkjmnb +pointblank +pointbreak +pointer1 +pointers +pointjor +poipoipoi +poisonivy +poissons +poiu0987 +poiu1234 +poiupoiu +poiuy123 +poiuyt12 +poiuyt123 +poiuytre +poiuytrew1 +poiuytrewq +poiuytrewq1 +poiuytreza +pok29q6666 +pokemon! +pokemon. +pokemon0 +pokemon00 +pokemon01 +pokemon09 +pokemon1 +pokemon10 +pokemon100 +pokemon101 +pokemon11 +pokemon12 +pokemon123 +pokemon1234 +pokemon12345 +pokemon13 +pokemon14 +pokemon15 +pokemon2 +pokemon21 +pokemon22 +pokemon23 +pokemon3 +pokemon4 +pokemon5 +pokemon6 +pokemon69 +pokemon7 +pokemon8 +pokemon88 +pokemon9 +pokemon90 +pokemon98 +pokemon99 +pokemons +poker123 +pokerface +pokerface1 +pokerstar +pokesmot +pokopushkin +polarbear +polarbear1 +polaris1 +polaroid +polenka1 +police01 +police11 +police12 +police123 +police911 +policeman +policeman1 +polikloh00000 +polinesia +polinochka +polipoli +politics +polkadot +polkadot1 +polkadots +polkadots1 +polkaudio +polkaudio1 +polkovnik +pollack1 +pollito1 +pollo123 +pollution +polly123 +pollyanna +polniypizdec0211 +polniypizdec1102 +polniypizdec110211 +polo1234 +polochon +polonia1 +polopolo +polopolo1 +polosport +polpetta +polpol11 +polpolpol +polska11 +polska12 +polska123 +pomalo123 +pommes123 +pomodoro +pomona909 +pompiers +ponderosa +pongpong +ponorogo +pontiac1 +pontiacg6 +pontianak +ponyboy1 +ponytail +poobear1 +poochie1 +poochie2 +poodles1 +pooface1 +pooh1234 +poohbaby1 +poohbear +poohbear! +poohbear01 +poohbear07 +poohbear08 +poohbear09 +poohbear1 +poohbear10 +poohbear11 +poohbear12 +poohbear13 +poohbear14 +poohbear15 +poohbear16 +poohbear17 +poohbear18 +poohbear19 +poohbear2 +poohbear20 +poohbear21 +poohbear22 +poohbear23 +poohbear3 +poohbear4 +poohbear5 +poohbear6 +poohbear69 +poohbear7 +poohbear8 +poohbear9 +poohead1 +poohpooh +poohpooh1 +pooja123 +pookie01 +pookie08 +pookie10 +pookie11 +pookie12 +pookie123 +pookie13 +pookie14 +pookie21 +pookie22 +pookie23 +pookie69 +pookiebear +poolpool +poolshark +poontang +poontang1 +poop1234 +poop12345 +poopdick +poopdick1 +pooper12 +pooper123 +poopers1 +poopface +poopface1 +poophead +poophead1 +poopie12 +poopie123 +poopies1 +pooping1 +poopmaster +poopoo11 +poopoo12 +poopoo123 +poopoo22 +poopoopoo +pooppoop +pooppoop1 +poopsie1 +poopstain +poopstain1 +poopy123 +poopypants +poornima +pop12345 +pop168168 +popapopa +popcorn! +popcorn. +popcorn1 +popcorn10 +popcorn101 +popcorn11 +popcorn12 +popcorn123 +popcorn13 +popcorn2 +popcorn22 +popcorn23 +popcorn3 +popcorn4 +popcorn5 +popcorn6 +popcorn7 +popcorn8 +popcorn9 +popeye123 +popo1234 +popokatepetl +popopopo +popovkin83 +poppop12 +poppop123 +poppoppop +poppy123 +poppydog +poprocks +poprocks1 +popsicle +popsicle1 +popstar1 +popstar123 +poptart1 +poptart2 +poptarts +poptarts1 +poptropica +popular1 +porche911 +porcinet +porcodio +porcodio1 +porcupine +porfavor +porkchop +porkchop1 +porkypig +porno123 +pornostar +pornporn +pornstar +pornstar1 +pornstar69 +porridge +porsche1 +porsche9 +porsche911 +porsche944 +porshe911 +porsiempre +portable +portakal +portfolio +portillo +portis26 +portishead +portland +portland1 +portocala +portsmouth +portugal +portugal1 +portugal12 +portugal17 +portugal7 +portugues +portvale +poseidon +poseidon1 +poseinfopass +positano +positive +positive1 +positivo +posoxina.88 +possible +possible1 +postcard +postman1 +postoffice +potapova +potato12 +potato123 +potatoe1 +potatoes +potatoes1 +potential +pothead1 +pothead2 +pothead420 +pothead69 +potter11 +potter12 +potter123 +potter13 +poubelle +pouetpouet +poulette +poupette +poupoune +pourquoi +povlmly727 +povray14 +power123 +power1234 +power12345 +power999 +powerade +powerade1 +powerball +powerful +powerful1 +powerfull +powerhouse +powerman +powerman1 +powermax +powerof3 +powerplay +powerpower +powerpuff +powerpuff1 +powerrange +powerranger +powerrangers +powerslave +powerstroke +pp123456 +ppoo0099 +pppppppp +ppppppppp +pppppppppp +pqntmt1247 +pr1nc3ss +pr1ncess +prabhakar +practical +practice +practice1 +praisegod +praisegod1 +praisehim +praisethelord +prajakta +praktikum +prancer1 +prankster1 +prasad123 +prasanna +prasanth +prashant +prashanth +pratibha +pratiksha +praveena +preacher +preacher1 +preciosa +preciosa1 +precioso +precious +precious! +precious01 +precious1 +precious10 +precious11 +precious12 +precious13 +precious2 +precious3 +precious5 +precious7 +precision +predator +predator1 +predator2 +pregmar2 +pregnant +pregnant1 +prelude1 +premier1 +premiere +premium1 +presario +presario1 +preschool +prescott +president +president1 +presidente +presley1 +pressure +pressure1 +prestige +prestige1 +prestigio +preston1 +preston12 +preston123 +preston2 +preston3 +pretender +pretinha +pretoria +pretty01 +pretty07 +pretty08 +pretty09 +pretty10 +pretty101 +pretty11 +pretty12 +pretty123 +pretty13 +pretty14 +pretty15 +pretty16 +pretty17 +pretty18 +pretty21 +pretty22 +pretty23 +prettyboi1 +prettyboy +prettyboy1 +prettyboy2 +prettyboys +prettygirl +prettygurl +prettyinpink +prettylady +prettyme +prettyme1 +prettypink +prettywoman +pretzel1 +preview1 +prezident +priceless +priceless1 +pridprid +pridurok +prieto77 +prikoluxa +primavara +primavera +primavera1 +primetime +primetime1 +primetime2 +primrose +primrose1 +princ3ss +prince01 +prince07 +prince08 +prince09 +prince10 +prince11 +prince12 +prince123 +prince1234 +prince13 +prince14 +prince1999 +prince21 +prince22 +prince23 +prince33 +prince55 +prince69 +prince99 +princes1 +princesa +princesa1 +princesa12 +princesa2 +princesita +princess +princess! +princess#1 +princess* +princess. +princess0 +princess00 +princess01 +princess02 +princess03 +princess04 +princess05 +princess06 +princess07 +princess08 +princess09 +princess1 +princess10 +princess101 +princess11 +princess12 +princess123 +princess13 +princess14 +princess15 +princess16 +princess17 +princess18 +princess19 +princess2 +princess20 +princess21 +princess22 +princess23 +princess24 +princess25 +princess26 +princess27 +princess28 +princess29 +princess3 +princess30 +princess31 +princess32 +princess33 +princess34 +princess4 +princess44 +princess45 +princess5 +princess55 +princess56 +princess6 +princess66 +princess69 +princess7 +princess77 +princess78 +princess8 +princess81 +princess82 +princess83 +princess84 +princess85 +princess86 +princess87 +princess88 +princess89 +princess9 +princess90 +princess91 +princess92 +princess93 +princess94 +princess95 +princess96 +princess97 +princess98 +princess99 +princessa +princessa1 +princesse +princesse1 +princeton +princeton1 +principal +principe +principe1 +principessa +pringles +pringles1 +prinsesa +printemps +printer1 +printesa +printing +prinzessin +priscila +priscilla +priscilla1 +prishtina +prisonbreak +prisoner +privacy1 +private1 +private123 +private2 +privet123 +privetik +priya123 +priyanka +priyanka1 +probation1 +problem1 +prodigy1 +produce1 +producer +producer1 +production +profesional +profesor +profesora +profession +professional +professionaltools +professor +professor1 +professora +profile1 +profissional +progamer +program1 +programmer +progress +progress1 +progressive +project1 +project123 +project8 +project86 +projects +projectsadminx +prometeo +prometheus +promise1 +promise123 +promise2 +promises +promote1 +promotion +promotion1 +propaganda +property +property1 +prophecy +prophet1 +prospect +prospect1 +prosper1 +prosperity +prospero +prosto_chelkynchik +prostreet +prosvirkind +protect1 +protected +protection +protector +protocol +protoss1 +prototype +protozoa +proutprout +provence +proverbs +proverbs1 +proverbs31 +proverbs35 +proverka +providence +provider +proview1 +prowler1 +prozukin-shift +prudence +prudence1 +prunelle +przemek1 +przyjaciolki +psalm119 +psalm121 +psalm139 +psalms23 +psalms91 +psicologa +psicologia +psp71835 +psycho13 +psycho666 +psycho69 +psychology +psytrance +pt120439 +ptcruiser +ptybnxtvgbjy +publicidad +pudding1 +puddles1 +puertorico +puffdaddy +puffetta +puffpuff +pugsley1 +pulguita +pulpfiction +pulsar150 +pulsar180 +pumapuma +pumas123 +pumpkin! +pumpkin01 +pumpkin1 +pumpkin11 +pumpkin12 +pumpkin123 +pumpkin13 +pumpkin2 +pumpkin22 +pumpkin3 +pumpkin4 +pumpkin5 +pumpkin7 +pumpkin8 +pumpkin9 +pumpkinpie +pumpkins +pumpkins1 +punisher +punisher1 +punjabi1 +punk1234 +punk4life +punkass1 +punkista +punkpunk +punkrock +punkrock! +punkrock1 +punkrock10 +punkrocker +punksnotdead +puntacana +puppies! +puppies1 +puppies12 +puppies123 +puppies2 +puppies3 +puppies4 +puppies5 +puppies7 +puppy101 +puppy123 +puppydog +puppydog1 +puppylove +puppylove1 +puppylove2 +puppylover +puppyluv +puppyluv1 +puravida +purchase +purchasing +purelove +purple00 +purple01 +purple02 +purple03 +purple04 +purple05 +purple06 +purple07 +purple08 +purple09 +purple10 +purple101 +purple11 +purple12 +purple123 +purple1234 +purple13 +purple14 +purple15 +purple16 +purple17 +purple18 +purple19 +purple20 +purple21 +purple22 +purple23 +purple24 +purple25 +purple26 +purple27 +purple28 +purple29 +purple30 +purple32 +purple33 +purple34 +purple420 +purple44 +purple45 +purple55 +purple66 +purple67 +purple69 +purple76 +purple77 +purple78 +purple87 +purple88 +purple89 +purple90 +purple92 +purple93 +purple94 +purple95 +purple96 +purple97 +purple99 +purplehaze +purplelove +purplerain +purpose1 +pusspuss +pusspuss1 +pussy101 +pussy123 +pussy1234 +pussy420 +pussy4me +pussy666 +pussy6969 +pussycat +pussycat1 +pussycat2 +pussycat69 +pussyeater +pussylicker +pussylips +pussylover +pussyman +pussypussy +putamadre +putamadre1 +putangina +putanginam +putanginamo +putaputa +puttputt +pw2012yr +pw898klkag +pwisdiwhs +pwlamea10 +px6gcr51 +pyanzina_elena +pyramid1 +pyramide +pyramids +q0tsrbv488 +q1111111 +q1234567 +q12345678 +q123456789 +q1234567890 +q123456q +q123q123 +q12we34r +q18lg49iq8bhu +q1q1q1q1 +q1q1q1q1q1 +q1q2q3q4 +q1q2q3q4q5 +q1w2e3r4 +q1w2e3r4t +q1w2e3r4t5 +q1w2e3r4t5y6 +q1w2e3r4t5y6u7 +q1w2e3r4t5y6u7i8 +q1w2e3r4t5y6u7i8o9 +q1w2e3r4t5y6u7i8o9p0 +q1w2q1w2 +q2345678 +q2w3e4r5 +q2w3e4r5t +q2w3e4r5t6 +q3538004 +q8a74ippxd +q963258741q +qa27111985qa +qamilek1 +qarglr123 +qavcx411 +qawsed12 +qawsed123 +qawsedrf +qawsedrf1 +qawsedrftg +qawsedrftgyh +qaywsx123 +qaywsxedc +qaz123123 +qaz12345 +qaz123456 +qaz123456789 +qaz123qaz +qaz123wsx +qaz123wsx456 +qaz12wsx +qaz1wsx2 +qazedctgb +qazplm123 +qazqaz11 +qazqaz12 +qazqaz123 +qazqazqaz +qazw21123 +qazwsx11 +qazwsx12 +qazwsx123 +qazwsx1234 +qazwsx12345 +qazwsx123456 +qazwsx13 +qazwsx23 +qazwsx321 +qazwsx741 +qazwsxed +qazwsxed1 +qazwsxedc +qazwsxedc1 +qazwsxedc12 +qazwsxedc123 +qazwsxedc12345 +qazwsxedc2 +qazwsxedcr +qazwsxedcrfv +qazwsxedcrfvtgb +qazwsxqazwsx +qazxcdews +qazxcvbnm +qazxsw111 +qazxsw12 +qazxsw123 +qazxsw21 +qazxswed +qazxswedc +qazxswedc1 +qazxswedc123 +qazxswedcvfr +qazzaq123 +qdujvyg5sxa +qdxzc43gba +qdye17t1zv +qebefcz3yx +qecegda3zx +qfcfgda3zx +qg9543bh7 +qh6xl1p9xj +qianqian +qiciqdp162 +qingqing +qn4kbwv559 +qnxe66l7or +qoxrzwfr +qpalzm123 +qpqpqpqp +qpwoeiru +qpwoeiruty +qq000000 +qq111111 +qq112233 +qq123000 +qq123123 +qq123456 +qq123456789 +qq18ww899 +qq5201314 +qqq123456 +qqqaaazzz +qqqq1111 +qqqq1234 +qqqqq11111 +qqqqqq11 +qqqqqqq1 +qqqqqqqq +qqqqqqqq1 +qqqqqqqqq +qqqqqqqqq1 +qqqqqqqqqq +qqqqqqqqqqqq +qqqqwwww +qqqwwweee +qqww1122 +qqwweerr +qsdfghjklm +qsefthuko +qti7zxh18u +quackers +quagmire +quality1 +quality123 +quantum1 +quaresma +quarter1 +quasimodo +que-veux-tu +queen123 +queen4life +queenbee +queenbee1 +queenie1 +queensland +quentin1 +question +question1 +queteimporta +qugrqfo825 +quicksilve +quicksilver +quidditch +quiksilver +quilting +quintana +quintero +quintin1 +quinton1 +quovadis +qvo78evm +qw10081973 +qw123321 +qw123456 +qw12er34 +qw12qw12 +qwas1234 +qwasqwas +qwaszx11 +qwaszx12 +qwaszx123 +qwaszx1234 +qwaszxedc +qwaszxerdfcv +qwaszxqw +qwaszxqwaszx +qwe058058a +qwe1122334 +qwe123123 +qwe123321 +qwe12345 +qwe123456 +qwe123456789 +qwe123asd +qwe123qwe +qwe123qwe123 +qwe123rty +qwe123rty456 +qwe123zxc +qwe12qwe +qweasd11 +qweasd12 +qweasd123 +qweasdqwe +qweasdqweasd +qweasdyxc +qweasdzx +qweasdzxc +qweasdzxc1 +qweasdzxc12 +qweasdzxc123 +qwedcxza +qwedcxzas +qwedsa123 +qwedsazxc +qweewq123 +qwegta13091990 +qwepoiasdlkj +qweqwe11 +qweqwe12 +qweqwe123 +qweqwe123123 +qweqweqwe +qweqweqwe1 +qwer0987 +qwer1234 +qwer12345 +qwer123456 +qwer4321 +qwer5678 +qwerasdf +qwerasdf1 +qwerasdf1234 +qwerasdfzxcv +qwerfdsa +qwerpoiu +qwerqwer +qwerqwer1 +qwerqwer2 +qwerrewq +qwert.0002 +qwert123 +qwert1234 +qwert12345 +qwert123456 +qwert54321 +qwert789 +qwertasd +qwertasdf +qwertasdfg +qwertasdfgzxcvb +qwertgfdsa +qwertqwert +qwerttrewq +qwerty00 +qwerty000 +qwerty007 +qwerty01 +qwerty02 +qwerty06 +qwerty07 +qwerty08 +qwerty09 +qwerty098 +qwerty0987 +qwerty1! +qwerty10 +qwerty100 +qwerty101 +qwerty11 +qwerty111 +qwerty112233 +qwerty12 +qwerty121 +qwerty123 +qwerty1231 +qwerty123321 +qwerty1234 +qwerty12345 +qwerty123456 +qwerty1234567 +qwerty12345678 +qwerty123456789 +qwerty1234567890 +qwerty13 +qwerty14 +qwerty15 +qwerty1517 +qwerty16 +qwerty17 +qwerty18 +qwerty19 +qwerty1981 +qwerty1985 +qwerty1986 +qwerty1987 +qwerty1988 +qwerty1989 +qwerty1990 +qwerty1991 +qwerty1992 +qwerty1993 +qwerty1994 +qwerty1995 +qwerty20 +qwerty2009 +qwerty2010 +qwerty2011 +qwerty2012 +qwerty21 +qwerty22 +qwerty23 +qwerty24 +qwerty25 +qwerty26 +qwerty27 +qwerty28 +qwerty30 +qwerty31 +qwerty32 +qwerty321 +qwerty33 +qwerty333 +qwerty34 +qwerty4321 +qwerty44 +qwerty45 +qwerty456 +qwerty54321 +qwerty55 +qwerty555 +qwerty56 +qwerty65 +qwerty654321 +qwerty66 +qwerty666 +qwerty67 +qwerty69 +qwerty76 +qwerty765 +qwerty77 +qwerty777 +qwerty777888 +qwerty78 +qwerty789 +qwerty7890 +qwerty79 +qwerty80 +qwerty82 +qwerty83 +qwerty84 +qwerty85 +qwerty86 +qwerty87 +qwerty88 +qwerty888 +qwerty89 +qwerty90 +qwerty91 +qwerty911 +qwerty92 +qwerty93 +qwerty94 +qwerty95 +qwerty96 +qwerty97 +qwerty98 +qwerty987 +qwerty99 +qwerty999 +qwertyas +qwertyasd +qwertyasdf +qwertyasdfg +qwertyasdfgh +qwertykolakola +qwertyqaz +qwertyqwerty +qwertytrewq +qwertyu1 +qwertyu12 +qwertyu123 +qwertyu7 +qwertyu8 +qwertyui +qwertyui1 +qwertyui12 +qwertyui2p +qwertyui9 +qwertyuio +qwertyuio0 +qwertyuio1 +qwertyuio9 +qwertyuiop +qwertyuiop0 +qwertyuiop1 +qwertyuiop12 +qwertyuiop123 +qwertyuiop1234 +qwertyuiop12345 +qwertyuiop123456 +qwertyuiop123456789 +qwertyuiop1234567890 +qwertyuiop789 +qwertyuiop[] +qwertyuiopasdfg +qwertyuiopasdfghjkl +qwertyuiopasdfghjkl151515 +qwertyuiopasdfghjklzxcvbnm +qwertyytrewq +qwertz12 +qwertz123 +qwertz1234 +qwertzu1 +qwertzui +qwertzuiop +qwerzxcv +qwest123 +qwezxc123 +qwezxcasd +qwqw1212 +qwqwqw12 +qwqwqwqw +qwqwqwqwqw +qxvbgfibuq +qxxm93js +qy5togr996 +qzwxecrv +r.polinin +r00tb33r +r00tbeer +r041stcu +r0ckstar +r1234567 +r12345678 +r123456789 +r1r2r3r4 +r26nnxjx7n +r2d2c3p0 +r2d2c3po +r2d2r2d2 +r3m3mb3r +r4e3w2q1 +r4evc8d8vs +r5gnqyrr +r6a50de3ujwtog4 +r9e8w7q6 +r9lw4j8khx +r_masick +rabat1945 +rabbit01 +rabbit11 +rabbit12 +rabbit123 +rabbit13 +rabbit69 +rabbits1 +raccoon1 +racecar1 +racecar2 +racecars +rachael1 +racheal1 +rachel01 +rachel07 +rachel08 +rachel09 +rachel10 +rachel11 +rachel12 +rachel123 +rachel13 +rachel14 +rachel15 +rachel16 +rachel17 +rachel18 +rachel21 +rachel22 +rachel23 +rachel24 +rachel69 +rachel88 +rachel99 +rachelle +rachelle1 +rachelle289ariyoshi5251987 +radcliffe +radhakrishna +radharani +radhasoami +radhaswami +radhekrishna +radheradhe +radiance +radiation +radiator +radical1 +radik070775 +radio123 +radiohead +radiohead1 +radiology +radion-dankov +radmila5 +raduga2508 +raduga388 +rafael01 +rafael10 +rafael12 +rafael123 +rafael13 +rafaella +raffaele +raffaella +raffaello +rafferty +ragdoll1 +raghavendra +ragnarok +ragnarok1 +rahasia1 +rahasia123 +rahmudinov92 +rahul123 +raider11 +raider12 +raider13 +raiders! +raiders#1 +raiders01 +raiders07 +raiders08 +raiders09 +raiders1 +raiders10 +raiders11 +raiders12 +raiders123 +raiders13 +raiders14 +raiders15 +raiders18 +raiders2 +raiders20 +raiders21 +raiders22 +raiders23 +raiders24 +raiders3 +raiders34 +raiders4 +raiders5 +raiders6 +raiders69 +raiders7 +raiders8 +raiders81 +raiders9 +raiders99 +raiderz1 +raikkonen +railroad +railroad1 +raimundo +rainbow! +rainbow. +rainbow01 +rainbow08 +rainbow1 +rainbow10 +rainbow11 +rainbow12 +rainbow123 +rainbow13 +rainbow14 +rainbow15 +rainbow16 +rainbow2 +rainbow21 +rainbow22 +rainbow23 +rainbow24 +rainbow3 +rainbow4 +rainbow5 +rainbow6 +rainbow69 +rainbow7 +rainbow8 +rainbow9 +rainbows +rainbows1 +raindrop +raindrop1 +raindrops +rainfall +rainforest +rainmaker +rainman1 +rainrain +rainyday +raisa720290 +raisa_smelkova +raistlin +raistlin1 +raj12345 +raja1234 +rajababu +rajaraja +rajarani +rajasthan +rajawali +rajendra +rajesh123 +rajeshwari +rajeswari +rajinder +rajkumar +rajneesh +rakesh123 +raleigh1 +ralph123 +ralphc8xf +ralphie1 +ramadevi +ramadhan +ramakrishna +ramarama +ramayana +rambler1 +rambo123 +rambutan +ramchandra +ramesh123 +ramirez1 +ramis_bairamov +ramkumar +rammstein +rammstein1 +rammstein6 +ramon123 +ramones1 +rampage1 +ramramram +ramsia1986 +ramstein +ranchero +randall1 +randolph +randolph1 +random11 +random12 +random123 +random13 +randomness +randy123 +randymoss1 +randyorton +ranger00 +ranger01 +ranger10 +ranger11 +ranger12 +ranger123 +ranger13 +ranger21 +ranger22 +ranger23 +ranger69 +ranger75 +ranger88 +ranger99 +rangerover +rangers01 +rangers1 +rangers10 +rangers11 +rangers12 +rangers123 +rangers1690 +rangers1873 +rangers2 +rangers7 +rangers9 +rangers94 +rangersfc +rangersfc1 +ranking21 +rantanplan +raoujfl963 +rap4life +raphael1 +rapid123 +rapstar1 +raptor22 +raptor350 +raptor660 +raptor700 +raptors1 +rapture1 +rapunzel +raqdc4ml +rasberry +rascal01 +rascal11 +rascal12 +rascal123 +rascal13 +rasengan +rasengan1 +rashaun966krager1993 +rashawn1 +rasheed1 +raskevichtanja +raspberry +raspberry1 +rasputin +rasputin1 +rasta123 +rasta420 +rastafari +rastafari1 +rastaman +rastaman1 +ratashn67 +ratatouille +ratchet1 +rattlesnake +raumschiff +rauzawcsiv +raven123 +raven666 +ravenclaw +ravens52 +ravi1234 +ravich92 +ravikumar +ravinder +ravindra +ravipass +ravshan1017 +rawalpindi +rawiswar +rawr1234 +rawrrawr +rayallen +rayallen20 +raylewis52 +raymond1 +raymond12 +raymond123 +raymond2 +raymond3 +raymond5 +raymond7 +raymonde +raymonde336schwegel7331987 +raymundo +rayquaza +rayray11 +rayray12 +rayray123 +rayray13 +rayray14 +rayray23 +razdvatri3 +razor123 +razorback +razorback1 +razorbacks +razorblade +rb26dett +rbotmvz954 +rbrbvjhf +rbtsozeva +rc.itymrf +rc95kzbj1v +rcalgif86 +rdfhnbhf +rdfhnbhfyy +rdfhnfk1 +rdfpbvjlj +rdukv46x +rdxyd43hca +re-enter +reaction +reading1 +ready123 +ready2go +realbetis +realdeal +realdeal1 +realest1 +realestate +realist1 +reality1 +reallife +reallove +reallove1 +realmadrid +realmadrid1 +realmadrid7 +realnigga +realnigga1 +realsim07 +realtalk1 +realtek. +realtime +realtor1 +realtors +reanimator +reaper12 +reaper123 +reaper13 +reaper666 +reaper69 +rebecca! +rebecca01 +rebecca1 +rebecca10 +rebecca11 +rebecca12 +rebecca123 +rebecca13 +rebecca2 +rebecca3 +rebecca4 +rebecca5 +rebecca7 +rebekah1 +rebel123 +rebel4life +rebelde1 +rebelde10 +rebelde12 +rebelde123 +rebelde2 +rebelde3 +rebelde6 +rebellion +rebirth1 +rebound1 +reception +recherche +reckless +reckless1 +record10 +records1 +recovery +recovery1 +recruiter +recruiter1 +recruitment +recycle1 +red12345 +red123456 +redab1993 +redalert +redalert1 +redalert2 +redapple +redapple1 +redbaron +redbird1 +redbirds +redblack +redblood +redblue1 +redbone1 +redbull1 +redbull12 +redbull123 +redbull2 +redcross +reddevil +reddevil1 +reddevils +reddog12 +reddog123 +reddragon +reddragon1 +reddwarf +reddwarf1 +reddy123 +redeemed +redeemed1 +redeemer +redemption +redfish1 +redfred1 +redgreen +redhead1 +redhead2 +redheads +redhorse +redhouse +rediffmail +redlight +redlight1 +redline1 +redman123 +rednaxela +redneck! +redneck01 +redneck08 +redneck09 +redneck1 +redneck101 +redneck11 +redneck12 +redneck123 +redneck13 +redneck16 +redneck2 +redneck21 +redneck3 +redneck5 +redneck69 +redneck7 +redouane +redred12 +redred123 +redredred +redrider +redriver +redrobin +redrock1 +redrose1 +redroses +redroses1 +redrover +redrover1 +redrum187 +redrum666 +redshoes +redskin1 +redskins +redskins1 +redskins12 +redskins2 +redskins21 +redskins26 +redskins89 +redsox01 +redsox04 +redsox05 +redsox07 +redsox08 +redsox09 +redsox10 +redsox11 +redsox12 +redsox123 +redsox13 +redsox14 +redsox15 +redsox18 +redsox2004 +redsox21 +redsox22 +redsox23 +redsox24 +redsox33 +redsox34 +redsoxs1 +redstar1 +redstone +redstorm +redtruck +redtruck1 +redwall1 +redwarbike +redwin3d +redwine1 +redwing1 +redwings +redwings1 +redwings19 +redwood1 +redzone1 +reece123 +reefer420 +reese123 +referee1 +reference +refillmotives +refinnej +reflection +refresh1 +regawf7ss1dm7rn +regenbogen +regenboog +reggaeton +reggaeton1 +reggie01 +reggie11 +reggie12 +reggie123 +reggie25 +reggie31 +regiment +regina-rebina +regina12 +regina123 +reginald +reginald1 +reginka2393 +regional +register +register1 +registrati +registration +reglisse +regulator +reinaldo +reindeer +reinhard +rekbrjdf +relation +relationship +relentless +reliable +reliance +relientk +relientk1 +religion +reloaded +rembrandt +remedios +remember +remember! +remember1 +remember12 +remember2 +remember7 +rememberme +remilekun +reminder +remington +remington1 +remo1d72a +rempit46 +rena.vano1990 +renaissance +renan123 +renault1 +renault19 +renault5 +rencontre +rencontres +rendakova_sveta +rendezvous +renee123 +renegade +renegade1 +renesmee +renesmeecallen +renkanom +renren15 +repmvbyf +reporter +reptile1 +reptiles +republic +republic1 +republica +repytwjd +repytwjdf +repytxbr +requiem1 +rerehepf +rererere +rerfhfxf +rerfhtre +research +research1 +reserved +reset123 +reset12345 +resident +resident1 +resident4 +residentev +residentevil +residentevil4 +resing1965 +resistance +resistant50m +resource +respect1 +response +restart1 +restaurant +restinpeace +restless +retamozo +retard12 +retard123 +retarded +retarded1 +retired1 +retirement +retraite +retriever +reunion1 +reunion974 +reussite +revelation +revenge! +revenge1 +revenge2 +reverend +revolucion +revolution +revolver +revolver1 +rewq1234 +rewq4321 +rexocinod +reyes123 +reymisteri +reymisterio +reymysteri +reymysterio +reynaldo +reynaldo1 +reynolds +reynolds1 +reyrey619 +reyrtutyd +rezo_2010 +rezvanov_a +rfczgecz11 +rfgbnjirf +rfgtkmrf +rfhbyjxrf +rfhectkm +rfhfrfnbwf +rfhfufylf +rfhfvtkm +rfhfvtkmrf +rfhfylfi +rfhjkbyf +rfhlbyfk +rfhnjirf +rfkbybyf +rfkmrekznjh +rfktylfhm +rfnfcnhjaf +rfnthbyf +rfnthbyrf +rfntymrf +rfnzrfnz +rfpfyjdf +rfpfynbg +rfrfirf1 +rfrfitxrf +rfvbrflpt +rfvfcenhf +rfvtgbyhn +rfvxfnrf +rfybreks +rhapsody +rhbcnbyf +rhbcnbyjxrf +rhbcnbyrf +rhfcbdfz +rhfcfdbwf +rhfcfdxbr +rhfcjnrf +rhfcyjlfh +rhfcyjzhcr +rhfdxtyrj +rhianna1 +rhiannon +rhiannon1 +rhino123 +rhinos111 +rhjrjlbk +rhodan01 +rhtdtlrj +ribka227555 +ricardito +ricardo07 +ricardo1 +ricardo10 +ricardo12 +ricardo123 +ricardo13 +ricardo2 +ricardo22 +ricardo7 +riccardo +riccardo1 +rich1234 +richard! +richard. +richard01 +richard07 +richard08 +richard1 +richard10 +richard11 +richard12 +richard123 +richard13 +richard14 +richard15 +richard18 +richard2 +richard21 +richard22 +richard23 +richard3 +richard4 +richard5 +richard6 +richard69 +richard7 +richard8 +richard9 +richards +richards1 +richardson +richbitch1 +richboy1 +richelle +richelle1 +richgirl +richie123 +richierich +richman1 +richmond +richmond1 +rickjames +rickjames1 +rickross +rickross1 +ricky123 +ricochet +ricorico +riddick1 +ride4life +ridebmx1 +rideordie +rideordie1 +riffraff +righteous +righteous1 +rightnow +righton1 +rigoberto +rihanna1 +rikimaru +riley123 +rileydog +rinat-88 +rinat.76 +rincewind +ringo123 +ringostar +ringring +rinoceronte +rintintin +riodejaneiro +riogrande +ripcurl1 +riquelme +risingsun +rita_nizhnik_r +ritarita +ritchie1 +rivendell +river123 +riverdale +riverplate +riverrat +riverrat1 +riverside +riverside1 +riversidec +riverview +riwr2hky4w3tjgg +rjdfkmxer +rjdfktyrj +rjgo7we138 +rjhjdf777 +rjhjkmbien +rjhjktdf +rjhjnrb1 +rjntyjxtr +rjrfrjkf +rjvgm.nth +rjyatnrf +rjycnbnewbz +rjycnfynby +rkamkin.karoli1988mp +rkfdbfnehf +rksk3210 +rktjgfnhf +roadkill +roadkill1 +roadking +roadking1 +roadrunner +roadstar +roadster +roadtrip +roanne42300 +robaczek +robbie01 +robbie11 +robbie12 +robbie123 +robby123 +robert00 +robert01 +robert02 +robert03 +robert04 +robert05 +robert06 +robert07 +robert08 +robert09 +robert10 +robert101 +robert11 +robert12 +robert123 +robert1234 +robert13 +robert14 +robert15 +robert16 +robert17 +robert1708 +robert18 +robert19 +robert20 +robert21 +robert22 +robert23 +robert24 +robert25 +robert26 +robert27 +robert28 +robert30 +robert33 +robert44 +robert45 +robert55 +robert66 +robert69 +robert77 +robert87 +robert88 +robert89 +robert93 +robert99 +roberta1 +robertina +robertino +robertito +roberto1 +roberto12 +roberto123 +roberto2 +robertpatt +roberts1 +robertson +robertson1 +robin123 +robinho10 +robinhood +robinhood1 +robinson +robinson1 +robocop1 +robot123 +robotech +robotics +robvandam +rocafella +rocafella1 +rocawear +rocawear1 +rocco123 +rochdale +rochelle +rochelle1 +rochester +rochester1 +rock&roll +rock1234 +rock4ever +rock4life +rockabilly +rockandrol +rockandroll +rockband +rockband1 +rockband2 +rockbottom +rocker101 +rocker12 +rocker123 +rocker13 +rockers1 +rockers123 +rocket01 +rocket11 +rocket12 +rocket123 +rocket21 +rocket22 +rocket69 +rocket88 +rocketmail +rocketman +rocketman1 +rockets1 +rockford +rockford1 +rockhard +rockhard1 +rockhopper +rockies1 +rocking1 +rockland +rocklee1 +rockman1 +rocknroll +rocknroll! +rocknroll1 +rocknroll2 +rocknsock1 +rockon11 +rockon12 +rockon123 +rockout1 +rockport +rockrock +rockrock1 +rockroll +rocks123 +rockstar +rockstar! +rockstar. +rockstar01 +rockstar08 +rockstar09 +rockstar1 +rockstar10 +rockstar11 +rockstar12 +rockstar123 +rockstar13 +rockstar14 +rockstar15 +rockstar16 +rockstar17 +rockstar18 +rockstar19 +rockstar2 +rockstar21 +rockstar22 +rockstar23 +rockstar24 +rockstar3 +rockstar4 +rockstar5 +rockstar6 +rockstar69 +rockstar7 +rockstar8 +rockstar9 +rocksteady +rockwell +rockwell1 +rockwood +rocky007 +rocky101 +rocky111 +rocky123 +rocky1234 +rocky12345 +rockybalboa +rockyboy +rockydog +rockydog1 +rockyou1 +rockyroad +roderick +roderick1 +rodman91 +rodney12 +rodney123 +rodolfo1 +rodolphe +rodrigo1 +rodrigo123 +rodrigue +rodrigues +rodriguez +rodriguez1 +rodriguez2 +roflcopter +roflmao1 +roflmao123 +roflrofl +rogelio1 +roger123 +rogovivan72 +rogovsasha123 +rohan123 +rohit123 +roland123 +roland7859 +rolandia42 +rolando1 +roleplay1 +rollercoaster +rollin20 +rollin60 +rolling1 +rollingstones +rollins1 +rollsroyce +rolltide +rolltide1 +rolltide12 +roma1234 +roma1927 +roma1996 +roma2010 +roman123 +romance! +romance1 +romanenko +romania1 +romanista +romanova +romanova.natalya.96 +romanroman +romans116 +romans12 +romans828 +romanson +romantic +romantic1 +romantica +romantico +romantik +romantika +romaroma +romashka +romeo123 +romka_ya93 +ronald12 +ronald123 +ronaldinho +ronaldinho10 +ronaldo07 +ronaldo09 +ronaldo1 +ronaldo10 +ronaldo11 +ronaldo12 +ronaldo123 +ronaldo17 +ronaldo2 +ronaldo7 +ronaldo77 +ronaldo9 +ronaldo99 +ronnie01 +ronnie10 +ronnie11 +ronnie12 +ronnie123 +roofing1 +rooney08 +rooney10 +rooney123 +roosevelt +roosevelt1 +rooster1 +rooster2 +roosters +roosters1 +rootbeer +rootbeer1 +rootbeer12 +rootbeer2 +rootroot +roro1024 +rosa1234 +rosales1 +rosalie1 +rosalina +rosalind +rosalinda +rosalinda1 +rosamaria +rosangela +rosanna1 +rosario1 +rosarosa +roscoe131 +rose1234 +rose24731 +roseann1 +roseanne +rosebud1 +rosebud12 +rosebud123 +rosebud2 +rosebud7 +rosebuds +rosedale +rosegarden +roseline +rosemarie +rosemarie1 +rosemary +rosemary1 +rosenrot +roserose +roses123 +rosetta1 +rosewood +rosewood1 +rosie123 +rosiedog +rossella +rossia19 +rossignol +rossoneri +rossonero +rostislav +rostov8888 +roswell1 +rothmans +rotterdam +rotterdam1 +rottweiler +roudoudou +roulette +rousseau +route666 +rover123 +roxanne1 +roxie123 +roxy1234 +roxydog1 +roxygirl +roxygirl1 +roxyroxy +royal123 +royalflush +royals22 +royalty1 +rrrrrrrr +rrrrrrrrrr +rtertuy77ijyhu7i +rtw150809 +rtyfghvbn +rubberband +rubberduck +rubberducky +ruben123 +rubicon1 +ruby1234 +rubyred1 +rubyrose +rubyruby +rucaxefu +rudeboy1 +rudolph1 +ruffles1 +ruffryder +ruffryders +rufus123 +rugby123 +rugbyman +rugrats1 +ruicosta +rukhsana +ruler1991 +run4life +runaway1 +runescape +runescape! +runescape1 +runescape123 +runescape2 +runescape3 +runescape5 +runescape9 +runner11 +runner12 +running1 +rus20dem +rusali_1979 +rush2112 +rushhour +rushmore +rushrush +rusiphon4 +ruslan009 +ruslan123 +russell1 +russell123 +russell2 +russia11 +russia123 +russian1 +russland +rusty123 +rustydog +rustydog1 +rutgers1 +rutherford +ruthless +ruthless1 +ryabec.m +ryan1234 +ryan12345 +ryan2000 +ryan2005 +ryan2006 +ryan2007 +ryan2008 +ryan962052 +ryangiggs +ryanjames +ryanryan +ryjgjxrf +ryleigh1 +ryu750103 +rzaev_ilgar +s-firsova +s0ftball +s0mething +s1234567 +s12345678 +s123456789 +s123456s +s1s2s3s4 +s1t2o3n4 +s39jwbw5ia +s7777777 +s8kril9u4f +s8ylpe9jdpvym +s987654321 +s9qxa9yn9cc= +sa123456 +sa2rawybas +saab9000 +saavedra +sabastian +sabbath1 +sabedoria +sabertooth +sabiduria +sabine12 +sabine21 +sable123 +sabotage +sabrina! +sabrina01 +sabrina1 +sabrina10 +sabrina11 +sabrina12 +sabrina123 +sabrina13 +sabrina2 +sabrina22 +sabrina3 +sabrina5 +sabrina7 +sabrina9 +sacha1234 +sachin123 +sacramento +sacrifice +sactown916 +sadgirl1 +sadie123 +sadiedog +sadiedog1 +sadiegirl +sadiegirl1 +sadiemae +sadiemae1 +sadness1 +safety123 +safety1st +safeway1 +saffron1 +safonova.1967 +safronov_3112 +sagar123 +sagarika +sagitaire +sagitario +sagitario1 +sagitarius +sagittario +sagittarius +sagopakajmer +sahhas1221 +saibaba1 +saibaba123 +saidov12345 +sailboat +sailboat1 +sailfish +sailing1 +sailormoon +saints01 +saints09 +saints10 +saints11 +saints12 +saints123 +saints25 +saintseiya +saintsrow2 +saipan670 +sairam123 +sakamoto +sakartvelo +sakarya54 +sakoshka_masha +sakura11 +sakura12 +sakura123 +sakura13 +sakuragi +salam123 +salamanca +salamander +salamandra +salamsalam +salas831 +salasana +salasana1 +salazar1 +saleens7 +salem123 +salento12 +sales123 +salesman +salim123 +salimata +salinas1 +salinas831 +salinger +salisbury +sally123 +sallyann +sallydog +salma123 +salman123 +salmankhan +salomon1 +salsa123 +salsabila +saltanat +saltlake +saltwater +saltydog +salut123 +salvacion +salvador +salvador1 +salvador12 +salvador13 +salvador2 +salvation +salvation1 +salvatore +salvatore1 +salzburg +sam12345 +sam123456 +samanta1 +samantha +samantha! +samantha. +samantha01 +samantha06 +samantha07 +samantha08 +samantha09 +samantha1 +samantha10 +samantha11 +samantha12 +samantha123 +samantha13 +samantha14 +samantha15 +samantha16 +samantha17 +samantha18 +samantha19 +samantha2 +samantha20 +samantha21 +samantha22 +samantha23 +samantha3 +samantha4 +samantha5 +samantha6 +samantha69 +samantha7 +samantha8 +samantha9 +samarinda +samarkand +samatron +sambuca1 +sameer123 +samiksha +samir123 +samisami +samitluiza1 +sammi123 +sammie01 +sammie11 +sammie12 +sammie123 +sammie13 +sammy101 +sammy111 +sammy123 +sammy1234 +sammyboy +sammyboy1 +sammycat +sammydog +sammydog1 +sammyjo1 +samourai +sampaguita +sampdoria +sample123 +sample1234 +sampoerna +sampson1 +sampson2 +samsam12 +samsam123 +samsamsam +samson01 +samson10 +samson11 +samson12 +samson123 +samsonite +samsuchonok +samsun55 +samsung! +samsung. +samsung0 +samsung01 +samsung09 +samsung1 +samsung10 +samsung11 +samsung12 +samsung123 +samsung13 +samsung14 +samsung2 +samsung21 +samsung22 +samsung23 +samsung3 +samsung4 +samsung5 +samsung6 +samsung69 +samsung7 +samsung8 +samsung88 +samsung9 +samtheman +samtron1 +samuel01 +samuel02 +samuel07 +samuel08 +samuel09 +samuel10 +samuel100 +samuel11 +samuel12 +samuel123 +samuel1234 +samuel12345 +samuel13 +samuel14 +samuel15 +samuel21 +samuel22 +samuel23 +samuel99 +samuelito +samurai1 +samurai7 +samuraix +sanandreas +sanandres +sanane123 +sananelan +sananto210 +sanantonio +sanasana +sancarlos +sanchez1 +sanchez12 +sanchez123 +sanchez13 +sanchez2 +sanchita +sanctuary +sandberg +sandberg5 +sandeep1 +sandeep123 +sanders1 +sanders20 +sanders21 +sanderson +sandgrouse +sandiego +sandiego1 +sandiego13 +sandiego61 +sandman1 +sandman2 +sandokan +sandoval +sandoval1 +sandpiper +sandra01 +sandra10 +sandra11 +sandra12 +sandra123 +sandra13 +sandra14 +sandra15 +sandra18 +sandra21 +sandra22 +sandra23 +sandra69 +sandrina +sandrine +sandrita +sandrock +sandstorm +sandwich +sandwich1 +sandy123 +sandy1234 +sandydog +sandydog1 +sanford1 +sanfran1 +sanfran49 +sanfrancisco +sangeeta +sangeetha +sanglier +sangohan +sanguine +sanjay123 +sanjo408 +sanjose1 +sanjose408 +sanju123 +sanjuan1 +sanlorenzo +sanluis1 +sanmarcos +sanmartin +sanmiguel +sanosuke +sanpedro +sanpedro1 +sans2010 +santa123 +santaclara +santaclaus +santacruz +santacruz1 +santafe1 +santamaria +santana1 +santana2 +santander +santarosa +santeria +santhosh +santi123 +santiago +santiago1 +santiago12 +santiago123 +santiago2 +santillan +santino1 +santodomingo +santorini +santos10 +santos12 +santos123 +santos13 +santos14 +santosh123 +santoshi +saopaulo +saphira1 +saphire1 +sapphire +sapphire1 +saprissa +saqartvelo +sara1234 +sara2000 +sara7272 +sarafina +sarah101 +sarah123 +sarah1234 +sarahann +sarahjane +sarahjane1 +sarajane +sarajevo +sarajevo1 +saranghae +saranghe +sarasara +sarasota +sarasota1 +saraswathi +saraswati +saratoga +saratoga1 +saravana +saravanan +sardegna +saregama +sargent1 +sargento +sargodha +sarkar123 +sarmiento +sarojini +sarumi101 +sasa1234 +sasanext +sasasasa +sasha007 +sasha111 +sasha123 +sasha1234 +sasha12345 +sasha1987 +sasha1988 +sasha1989 +sasha1990 +sasha1991 +sasha1992 +sasha1993 +sasha1994 +sasha1995 +sasha1996 +sasha1997 +sasha1998 +sasha1999 +sasha2000 +sasha2001 +sasha2002 +sasha2003 +sasha2010 +sasha2011 +sasha777 +sasha_007 +sashadog +sashasasha +sashenka +sasikala +sasin414 +sasquatch +sasquatch1 +sassafras +sassi123 +sassy101 +sassy123 +sassy1234 +sassycat +sassycat1 +sassydog +sassygirl +sassygirl1 +sasuke01 +sasuke10 +sasuke101 +sasuke11 +sasuke12 +sasuke123 +sasuke1234 +sasuke13 +sasuke14 +sasuke15 +sasuke22 +sasuke23 +sasukeuchiha +sasusaku +sataieva.elinka +satan123 +satan666 +satana666 +satanas666 +satanic666 +satchmo1 +satelite +satellite +satellite1 +satheesh +satisfaction +satriani +satriani1 +sattorov-q +saturday +saturday1 +saturn01 +saturn12 +saturnus +saucisse +saudades +saunders +saunders1 +sausage1 +sausages +sausages1 +savage12 +savage123 +savage23 +savanah1 +savanna1 +savannah +savannah01 +savannah07 +savannah08 +savannah1 +savannah10 +savannah11 +savannah12 +savannah13 +savannah2 +savannah3 +savannah4 +savannah5 +savannah7 +savatage +savemoney +saviour1 +savithri +sawsaw1212 +saxaphone +saxophone +saxophone1 +sayang12 +sayang123 +sayang87 +sayang88 +sayang89 +sayang90 +sayangkamu +sayangku +sayangku1 +sayangmama +sayonara +saywhat1 +sb123456 +sbally_64 +sc00byd00 +sc0tland +scamper1 +scanner1 +scarabeo +scarecrow +scarecrow1 +scareface +scareface1 +scarface +scarface1 +scarface10 +scarface11 +scarface12 +scarface13 +scarface2 +scarface21 +scarface23 +scarface3 +scarface5 +scarface69 +scarface7 +scarlet1 +scarlett +scarlett1 +schaefer +schalke04 +schastie +schatten +schatz123 +schatzi1 +schatzie +schecter1 +scheisse +scheisse1 +schilf02 +schiller +schlampe +schlampe1 +schlange +schlumpf +schmetterling +schmidt1 +schnauzer +schnecke +schnecke1 +schneider +schneider1 +schnitzel +schnucki +schnuffel +schnuffi +schnulli +schokolade +scholes18 +school01 +school07 +school08 +school09 +school10 +school101 +school11 +school12 +school123 +school1234 +school13 +school14 +school22 +school23 +schoolboy +schoolboy1 +schoolbus +schoolbus1 +schoolgirl +schoolsucks +schooner +schroeder +schubert +schultz1 +schumacher +schuster +schuyler +schwartz +schweden +schweini +schwimmen +science1 +scientist +scimitar +scirocco +scissors +scissors1 +scofield +scoobie1 +scooby-doo +scooby01 +scooby08 +scooby10 +scooby11 +scooby12 +scooby123 +scooby13 +scooby14 +scooby21 +scooby22 +scooby23 +scooby69 +scoobyd00 +scoobydo +scoobydoo +scoobydoo1 +scoobydoo2 +scoobydoo3 +scoobydoo7 +scooter! +scooter01 +scooter1 +scooter10 +scooter11 +scooter12 +scooter123 +scooter13 +scooter2 +scooter22 +scooter23 +scooter3 +scooter4 +scooter5 +scooter6 +scooter69 +scooter7 +scooter8 +scooter9 +scooters +scorpian +scorpio1 +scorpio11 +scorpio12 +scorpio123 +scorpio13 +scorpio2 +scorpio21 +scorpio3 +scorpio69 +scorpio7 +scorpio8 +scorpio9 +scorpion +scorpion1 +scorpion12 +scorpion13 +scorpion2 +scorpion7 +scorpione +scorpions +scorpions1 +scotland +scotland1 +scott123 +scottie1 +scottish +scotty01 +scotty12 +scotty123 +scoubidou +scout123 +scouting +scrabble +scrabble1 +scranton +scrapbook +scrapper +scrapper1 +scrappy1 +scrappy12 +scrappy123 +scrappy13 +scrappy2 +scratch1 +scratchy +scraty98 +scream123 +screamer +screamo1 +screwed1 +screwyou +screwyou1 +screwyou2 +scruffy1 +scruffy123 +scruffy2 +scubadiver +scuderia +scumbag1 +scvmofas79 +sczouvie26 +sd123456 +sdf7asdf6asdg8df +sdf7asdf6asdg8df1 +sdfghjkl +sdfsdfsd +sdfsdfsdf +sdsadee23 +sdsdsdsd +seabass1 +seabreeze +seafood1 +seagull1 +seagulls +seahawk1 +seahawks +seahawks1 +seahorse +seahorse1 +sealteam6 +sean1234 +seanjohn +seanjohn1 +seanpaul +seanpaul1 +seansean +search123 +searcher +searching +seashell +seashell1 +seashells +seashore +seaside1 +seatibiza +seatleon +seattle1 +seattle206 +seaweed1 +seaworld +sebas123 +sebastia +sebastian +sebastian. +sebastian0 +sebastian1 +sebastian106 +sebastian12 +sebastian123 +sebastian2 +sebastian3 +sebastian5 +sebastian7 +sebastian8 +sebastian9 +sebastiano +sebastiao +sebastien +sebastien1 +sebring1 +seccion33 +secret00 +secret007 +secret01 +secret08 +secret10 +secret101 +secret11 +secret12 +secret123 +secret1234 +secret13 +secret21 +secret22 +secret23 +secret24 +secret666 +secret69 +secret77 +secret99 +secretaria +secretary +secreto1 +secretos +secrets1 +section1 +section8 +securite +security +security1 +seduction +seductive +seedsnipe +seekbang1 +seether1 +sefa1986 +segura88 +seguridad +sehnsucht +seigneur +seinfeld +seinfeld1 +selamanya +selassie +selassie1 +selena11 +selena12 +selena123 +selena13 +selenagome +selenagomez +selfish1 +selfmade +selfmade1 +selim2010 +selvaggia +semangat +semarang +sembarang +sembilan +semenova +semeolvido +semina-alina +seminole +seminole1 +seminoles +seminoles1 +semperf1 +semperfi +semperfi1 +sempurna +semsenha +senator1 +senators +senegal1 +senerity +senha123 +senhasenha +senior04 +senior05 +senior06 +senior07 +senior08 +senior09 +senior10 +senior11 +senior12 +senior2008 +senior2009 +senior2010 +senior2011 +seniors06 +seniors07 +seniors08 +seniors09 +seniseviyoru +seniseviyorum +senorita +sensation +sensation1 +sensesfail +sensitive +sensizim +sentinel +sentnece +senveben +seo12345 +seo123456 +seo21saafd23 +seos1234 +sephiroth +sephiroth1 +sephiroth7 +septembe +september +september0 +september1 +september11 +september12 +september13 +september2 +september21 +september22 +september23 +september3 +september4 +september5 +september6 +september7 +september8 +september9 +septembre +septembrie +septiembre +sepultura +sepultura1 +sequoia1 +ser12345 +ser123456 +ser_kuzmin +serafima +serafina +serafina14 +serafino +seraphim +serash2240 +serban24 +serduszko +serega-cash +serega123 +serega777 +serega_torov +seregakalygin +seregjvich +serena12 +serenade +serendipit +serendipity +serenella +serenity +serenity1 +serenity12 +serenity2 +serenity3 +serenity7 +serfeliz +serg-ks.87 +serg-niki20 +serg.aleg +sergan11 +sergdock +sergeant +sergeev2212 +sergeeva +sergeevna +sergeevna_10.10.91 +sergei1986inna +sergei_man9 +sergej_de_sad +sergey-ivanov +sergey-personal +sergey.lushnikoff +sergey.melnik-1996 +sergey123 +sergey_brrr24 +serginho +sergio-emperior +sergio.b93 +sergio01 +sergio10 +sergio11 +sergio12 +sergio123 +sergio13 +sergserg +serikpaevna_92 +serious1 +seriously +serj-gr1966 +seronoser +serova2008 +serpent1 +serpente +serpiente +serrano1 +servant1 +server123 +service1 +service45 +services +sesshomaru +sesshoumaru +setembro +setiawan +settembre +settings +sevastopol +seven777 +sevendust +sevenfold +sevenof9 +sevenseven +seventeen +seventeen1 +seventeen17 +seventy7 +severina +severine +severino +sevgeyq9v7kor +sevgilim +sevilla1 +sevillafc +seviyorum +sex12345 +sex123456 +sex4life +sexbomb1 +sexesexe +sexiest1 +sexii123 +sexisfun +sexisgood +sexisgood1 +sexkitten +sexkitten1 +sexlover +sexmachine +sexonthebeach +sexosexo +sexpistols +sexsex123 +sexsex69 +sexsexsex +sexsexsex1 +sextrime1 +sexual69 +sexy1234 +sexy12345 +sexy123456 +sexy2006 +sexy2007 +sexy2008 +sexy2009 +sexy2010 +sexy4ever +sexy4life +sexy6969 +sexy_julija +sexyangel +sexyangel1 +sexyass1 +sexybabe +sexybabe1 +sexybabe12 +sexybaby +sexybaby1 +sexybaby12 +sexybaby2 +sexyback +sexyback1 +sexyback12 +sexyback2 +sexybeast +sexybeast! +sexybeast1 +sexybeast2 +sexybitch +sexybitch! +sexybitch0 +sexybitch1 +sexybitch2 +sexybitch3 +sexybitch4 +sexybitch5 +sexybitch6 +sexybitch7 +sexybitch9 +sexyblack +sexyblack1 +sexyblack2 +sexyboi1 +sexyboo1 +sexyboy1 +sexyboy12 +sexyboy123 +sexyboy13 +sexyboy2 +sexycani +sexycani1 +sexychick +sexychick1 +sexydiva +sexydiva1 +sexyeyes +sexygirl +sexygirl! +sexygirl01 +sexygirl09 +sexygirl1 +sexygirl10 +sexygirl11 +sexygirl12 +sexygirl13 +sexygirl14 +sexygirl15 +sexygirl16 +sexygirl2 +sexygirl23 +sexygirl3 +sexygirl5 +sexygirl69 +sexygirl7 +sexygirl9 +sexygirls +sexygirls1 +sexygurl +sexygurl1 +sexygurl12 +sexygurl2 +sexyguy1 +sexylady +sexylady1 +sexylady12 +sexylady2 +sexylegs +sexylexy +sexylove +sexylove1 +sexylove12 +sexylove2 +sexymama +sexymama! +sexymama1 +sexymama10 +sexymama11 +sexymama12 +sexymama13 +sexymama2 +sexymama3 +sexymama69 +sexymami1 +sexymamma1 +sexyman1 +sexyman123 +sexyman2 +sexyme123 +sexymom1 +sexymomma +sexymomma1 +sexyness +sexyness1 +sexyone1 +sexyred1 +sexysexy +sexysexy1 +sexythang +sexythang1 +sexything +sexything1 +sexytime +sexytime1 +sexytime69 +seychelles +seymour1 +seyxe44hca +sfasdfsdfa +sfgiants +sfring31 +sgdhhfc4x2 +sgydvntep +sh0pping +sh123456 +sh1thead +sh_o_a_2013 +sha22una +shadmoss +shadmoss1 +shadow00 +shadow007 +shadow01 +shadow02 +shadow0262 +shadow03 +shadow04 +shadow05 +shadow06 +shadow07 +shadow08 +shadow09 +shadow10 +shadow101 +shadow11 +shadow12 +shadow123 +shadow1234 +shadow13 +shadow14 +shadow15 +shadow16 +shadow17 +shadow18 +shadow19 +shadow20 +shadow21 +shadow22 +shadow23 +shadow24 +shadow25 +shadow26 +shadow27 +shadow28 +shadow32 +shadow33 +shadow420 +shadow44 +shadow45 +shadow55 +shadow66 +shadow666 +shadow69 +shadow77 +shadow777 +shadow87 +shadow88 +shadow89 +shadow90 +shadow91 +shadow92 +shadow93 +shadow94 +shadow95 +shadow98 +shadow99 +shadowcat +shadowfax +shadowman +shadowman1 +shadows1 +shadrach +shady123 +shaggy12 +shaggy123 +shaggy2dop +shaggy69 +shagufta +shahrukh +shahrukhkhan +shailendra +shailesh +shakademous +shakeit1 +shakespear +shakespeare +shakira1 +shakira123 +shakmakovataisiya1992 +shakuntala +shalimar +shalom123 +shamanking +shambala +shameless +shameless1 +shampoo1 +shamrock +shamrock1 +shana123 +shane123 +shanell1 +shanelle +shaney14 +shanghai +shanghai1 +shangrila +shanice1 +shaniqua +shaniya1 +shannara +shannon! +shannon01 +shannon1 +shannon10 +shannon11 +shannon12 +shannon123 +shannon13 +shannon2 +shannon21 +shannon22 +shannon3 +shannon4 +shannon5 +shannon6 +shannon69 +shannon7 +shannon8 +shannon9 +shanshan +shantanu +shantel1 +shantell +shantell1 +shaolin1 +shaquille +shaquille1 +shaquillesecx10 +shar-vin +sharapova +shareaza +sharingan +sharingan1 +shark123 +sharkbait +sharkboy +sharlene +sharma123 +sharmaine +sharmaine005foskett6071988 +sharmila +sharon01 +sharon11 +sharon12 +sharon123 +sharpie1 +shasha123 +shashank +shaun123 +shawn123 +shawnee1 +shawshank +shawty10 +shawty12 +shawty123 +shawty13 +shayne123 +shayshay +shayshay1 +shayshay12 +shea019bernabei1992 +shearer1 +shearer9 +shearwater +sheba123 +sheba417yorck1986vxm7 +sheckler +sheckler1 +shedevil +sheep123 +sheepdog +sheffield +sheffield1 +sheila123 +shekinah +shelbie1 +shelby01 +shelby06 +shelby07 +shelby08 +shelby10 +shelby11 +shelby12 +shelby123 +shelby13 +shelby14 +shelby15 +shelby22 +shelby500 +shelby67 +shelby69 +shelby99 +shelbygt500 +sheldon1 +shell123 +shelley1 +shellie1 +shelly12 +shelly123 +shelter1 +shelton1 +shemale1 +shenlong +shepard1 +shepherd +shepherd1 +sheppard +sheraton +sherbert +sherbert1 +sheridan +sheridan1 +sheriff1 +sherlock +sherlock1 +sherman1 +sherrie1 +sherry123 +sherwin1 +sherwood +sherwood1 +shesthe1 +shetland +shevchenko +shevcov_alesha +shianne1 +shikamaru +shikamaru1 +shimmer1 +shinchan +shine123 +shinedown +shinedown1 +shinichi +shinigami +shinigami1 +shiningeagle +shinobi1 +shinoda1 +shipping +shippuden +shippuden1 +shippuuden +shirankova42 +shirley1 +shirshov.1968 +shishmarev76 +shit1234 +shitass1 +shitbag1 +shitface +shitface1 +shitface2 +shitfuck +shitfuck1 +shithappen +shithappens +shithead +shithead! +shithead1 +shithead12 +shithead2 +shithead3 +shithead69 +shithole +shithole1 +shitshit +shitshit1 +shitter1 +shiva123 +shivangi +shivbaba +shiznit1 +shiznits +shizzle1 +shocker1 +shockwave +shoelace +shoelace1 +shoes123 +shokolad +shokoladka +shooter1 +shooters +shooting +shootingstar +shopaholic +shopgirl +shopper1 +shopping +shopping! +shopping1 +shopping12 +shopping2 +shortcake +shortcake1 +shortie1 +shortstop +shortstop1 +shortstuff +shorty#1 +shorty01 +shorty06 +shorty07 +shorty08 +shorty09 +shorty10 +shorty101 +shorty11 +shorty12 +shorty123 +shorty1234 +shorty13 +shorty14 +shorty15 +shorty16 +shorty17 +shorty18 +shorty19 +shorty20 +shorty21 +shorty22 +shorty23 +shorty24 +shorty25 +shorty69 +shorty77 +shorty88 +shortys1 +shotgun1 +shotgun12 +shotgun2 +shotokan +shotokan1 +shovelhead +showdown +showmethemoney +showtime +showtime1 +shponka35 +shraddha +shravani +shredder +shredder1 +shree420 +shreeganesh +shreeram +shrek123 +shrestha +shriganesh +shrikant +shrikrishna +shrooms1 +shubhangi +shuffle1 +shuhrat007 +shukshinasveta +shukurova-ismigu +shumaher +shumaila +shunia0505 +shuriken +shutdown +shutup12 +shutup123 +shyamala +shyanne1 +shygirl1 +sibelius +siberian +sibiryak5 +sicherheit +siciliano +sickness +sickness1 +siddhant +siddharth +siddhartha +siddiqui +sidekick +sidekick08 +sidekick1 +sidekick2 +sidekick3 +sideshow +sidewalk +sideways +sidewinder +sidharth +sidney12 +sidorenko +sidorova +sidorow64 +sidorval +siegfried +siegheil +siegheil88 +siemens1 +siemens123 +siempre1 +sierra01 +sierra10 +sierra11 +sierra117 +sierra12 +sierra123 +sierra13 +sierra99 +sieuwaprd +sig53num +sigaretta +sigmachi +signature +sigora79 +siiifonjiknalivai +sikander +silakova.nadezhda.2012 +silantyi1987 +silenakriv +silence1 +silencer +silencio +silent13 +silenthill +silentium +silkroad +silly123 +sillybilly +sillygirl +sillygirl1 +sillygoose +silmaril +silva123 +silvana1 +silver00 +silver01 +silver10 +silver11 +silver12 +silver123 +silver13 +silver14 +silver16 +silver17 +silver18 +silver21 +silver22 +silver23 +silver24 +silver25 +silver33 +silver69 +silver77 +silver88 +silver99 +silverado +silverado1 +silverado2 +silverback +silverchair +silverfish +silverfox +silverfox1 +silverio +silverkey3 +silvermoon +silverstar +silverstone +silversurfer +silverwolf +silvester +silvestre +silvestro +silvia123 +silvietta +simakov_evg +simba123 +simbacat +simcity4 +simmons1 +simon123 +simone01 +simone11 +simone12 +simone123 +simonetta +simonoff-dj +simonona +simonova5570 +simonova_lyudmila_73 +simonovskiy1970 +simonsays +simorodok62 +simple01 +simple11 +simple12 +simple123 +simple23 +simplegirl +simpleman +simpleplan +simplicity +simplyme +simpson1 +simpsons +simpsons1 +simpsons12 +simpsons2 +simsalabim +sin-gulya +sinaloa1 +sinaloa13 +sinatra1 +sincere1 +sincity1 +sinclair +sinclair1 +singapore +singapore1 +singapur +singer12 +singer123 +singh123 +singhisking +singing1 +single01 +single07 +single08 +single09 +single10 +single101 +single11 +single12 +single123 +single13 +single14 +single15 +single16 +single18 +single2010 +single21 +single22 +single23 +single69 +singleagain +singlelady +singlelife +singlemom +singleton +singsing +singsong +sinister +sinister1 +sinterklaas +siobhan1 +siouxsie +sipfhair +siracusa +sirazhdinov.shamil +sirenita +sirik010875 +sissy123 +sistemas +sister11 +sister12 +sister123 +sisters1 +sisters2 +sisters3 +sisters4 +sithlord +sithlord1 +sivakumar +sivasiva +sivenkovklin +sixflags +sixflags1 +sixpack1 +sixsixsix +sixteen1 +sixteen16 +sixtynine +sixtynine6 +sj811212 +sjiecj1a9x +sk123456 +sk84ever +sk84life +sk8board +sk8er4life +sk8erboi +sk8erboy +sk8erdude +sk8ergirl +sk8forlife +sk8mafia +sk8ordie +sk8r4life +sk8terboi +sk8terboy +sk8tergirl +ska02ska +skank123 +skate101 +skate123 +skate1234 +skate420 +skate4ever +skate4life +skate666 +skateboard +skateboard1 +skateboarding +skateordie +skater01 +skater09 +skater10 +skater101 +skater11 +skater12 +skater123 +skater1234 +skater13 +skater14 +skater15 +skater16 +skater17 +skater18 +skater21 +skater22 +skater23 +skater24 +skater32 +skater4lif +skater69 +skater88 +skater99 +skaterboy +skaterboy1 +skaterboy2 +skaterdude +skaters1 +skating1 +skeeter1 +skeeter2 +skeleton +skeleton1 +skeletor +skelitor66 +skeptron +skidrow1 +skillet1 +skills12 +skincare +skinhead +skinhead1 +skinhead69 +skinhead88 +skinner1 +skipper1 +skipper123 +skipper2 +skippy01 +skippy11 +skippy12 +skippy123 +skittle1 +skittles +skittles! +skittles1 +skittles10 +skittles11 +skittles12 +skittles13 +skittles14 +skittles2 +skittles3 +skittles4 +skittles5 +skittles69 +skittles7 +skittlez1 +skooter1 +skorpion +skorpion1 +skorpions23.5 +skrillex +skrip-natalya +skull123 +skullcandy +skyblue1 +skydive1 +skydiver +skylark1 +skyler12 +skyler123 +skylight +skyline1 +skyline12 +skyline123 +skyline2 +skyline3 +skyline34 +skyline7 +skylinegtr +skyliner +skyliner33 +skyliner34 +skywalker +skywalker1 +sl1pkn0t +sl1pknot +slacker1 +sladkaya +slam1984 +slamdunk +slamdunk1 +slammer1 +slankers +slapnuts +slapshock +slapshot +slapshot1 +slaptasis +slash123 +slasher1 +slastenka93 +slaughter +slaughter1 +slava-45 +slava.grinco +slava123 +slava_kulbidyuk +slavik200887 +slayer01 +slayer11 +slayer12 +slayer123 +slayer13 +slayer66 +slayer666 +slayer69 +slbenfica +sleeper1 +sleeping +sleeping1 +sleepy13 +slick123 +slickrick +slickrick1 +slideshow +slim1970 +slimjim1 +slimshady +slimshady1 +slimthug1 +slingshot +slipchenko2004 +slipkn0t +slipknot +slipknot! +slipknot. +slipknot0 +slipknot01 +slipknot1 +slipknot10 +slipknot11 +slipknot12 +slipknot123 +slipknot13 +slipknot14 +slipknot2 +slipknot21 +slipknot22 +slipknot3 +slipknot4 +slipknot5 +slipknot6 +slipknot66 +slipknot666 +slipknot69 +slipknot7 +slipknot8 +slipknot9 +slipper1 +slippers +slippers1 +slippery +slippery1 +slniecko +slobodan +sloneczko +sloneczko1 +slonenok1009 +slovakia +slovenija +slovensko +slowhand +slowpoke +slugger1 +slunicko +slurpee1 +slutbag1 +slutface1 +slytherin +sm.karat +sm123456 +smackdown +smackdown1 +smackdown2 +smackthat1 +smail.ru +smallboy +smallfry +smallville +smart123 +smartass +smartass1 +smartboy +smartest1 +smartgirl +smartguy +smartie1 +smarties +smarties1 +smartone +smashing +smashing1 +smb0512bz +smeghead +smeghead1 +smelly123 +smellycat +smellycat1 +smile0_0 +smile101 +smile123 +smile1234 +smile4ever +smile4me +smiles12 +smiles123 +smiles4u +smilesmile +smiley01 +smiley10 +smiley101 +smiley11 +smiley12 +smiley123 +smiley13 +smiley14 +smiley22 +smiley23 +smiley69 +smileyface +smiling1 +smirnoff +smirnoff1 +smirnova +smith123 +smithers +smoke123 +smoke420 +smokepot +smoker420 +smokeweed +smokeweed1 +smokeweed4 +smokey01 +smokey07 +smokey08 +smokey09 +smokey10 +smokey101 +smokey11 +smokey12 +smokey123 +smokey13 +smokey14 +smokey15 +smokey16 +smokey21 +smokey22 +smokey23 +smokey420 +smokey69 +smokey77 +smokey88 +smokey99 +smokeyjoe +smokin420 +smoking1 +smolensk +smooches +smooches1 +smoochie +smoochie1 +smoothie +smoothie1 +smudge123 +smurfette +sn0wball +sn1ckers +snake123 +snakebite +snakeeyes +snakeman +snapper1 +snapple1 +snapshot +sneaker1 +sneakers +sneakers1 +snicker1 +snickers +snickers! +snickers01 +snickers1 +snickers11 +snickers12 +snickers13 +snickers2 +snickers22 +snickers3 +snickers4 +snickers5 +snickers7 +sniffles +sniper01 +sniper11 +sniper12 +sniper123 +sniper13 +sniper69 +snivanie +snoogans +snooker1 +snooker147 +snookie1 +snookums +snoop123 +snoopdog +snoopdog1 +snoopdogg +snoopdogg1 +snoopy01 +snoopy07 +snoopy08 +snoopy09 +snoopy10 +snoopy101 +snoopy11 +snoopy12 +snoopy123 +snoopy13 +snoopy14 +snoopy15 +snoopy16 +snoopy17 +snoopy21 +snoopy22 +snoopy23 +snoopy24 +snoopy25 +snoopy69 +snoopy77 +snoopy88 +snoopy99 +snorre98 +snow1234 +snowangel +snowball +snowball1 +snowball11 +snowball12 +snowball2 +snowball3 +snowball7 +snowbell +snowbird +snowbird1 +snowboard +snowboard1 +snowboard2 +snowboarding +snowbunny +snowbunny1 +snowdrop +snowfall +snowflake +snowflake1 +snowflake2 +snowflake3 +snowflakes +snowhite +snowman1 +snowman12 +snowman123 +snowman2 +snowman3 +snowman7 +snowshoe +snowsnow +snowstorm +snowwhite +snowwhite1 +snowy123 +snuffles +snuggle1 +snuggles +snuggles1 +snuggles2 +soboleva +sobriety +soccer#1 +soccer00 +soccer01 +soccer02 +soccer03 +soccer04 +soccer05 +soccer06 +soccer07 +soccer08 +soccer09 +soccer10 +soccer100 +soccer101 +soccer11 +soccer12 +soccer123 +soccer1234 +soccer13 +soccer14 +soccer15 +soccer16 +soccer17 +soccer18 +soccer19 +soccer20 +soccer2010 +soccer21 +soccer22 +soccer23 +soccer24 +soccer25 +soccer26 +soccer27 +soccer28 +soccer29 +soccer30 +soccer31 +soccer32 +soccer33 +soccer34 +soccer35 +soccer44 +soccer45 +soccer4lif +soccer55 +soccer56 +soccer66 +soccer69 +soccer77 +soccer87 +soccer88 +soccer89 +soccer90 +soccer91 +soccer92 +soccer93 +soccer94 +soccer95 +soccer96 +soccer97 +soccer98 +soccer99 +soccerball +soccerboy +soccerboy1 +soccergirl +soccerman1 +soccermom +soccermom1 +soccerstar +sochi2014 +social12 +social123 +socialbook +socialwork +sociology +socks123 +socorro1 +socrates +socrates1 +sodapop1 +sodikov.talat +sofia123 +sofresh1 +softail1 +softball +softball! +softball. +softball00 +softball01 +softball02 +softball03 +softball05 +softball06 +softball07 +softball08 +softball09 +softball1 +softball10 +softball11 +softball12 +softball13 +softball14 +softball15 +softball16 +softball17 +softball18 +softball19 +softball2 +softball20 +softball21 +softball22 +softball23 +softball24 +softball25 +softball27 +softball3 +softball32 +softball33 +softball4 +softball44 +softball5 +softball6 +softball7 +softball8 +softball9 +softball99 +softtail +software +software1 +sofya.kulikova.87 +sogevigdil1981 +soinlove +sojdlg123aljg +sokolova +sokrates +solange1 +solaris1 +soldier1 +soldier2 +soldiers +solecito +soledad1 +soleil12 +soleil123 +soleil13 +soleluna +solidsnake +solidworks +solitaire +solitaria +solitario +solitario1 +solitude +solnishko +solnyshko +solo7590 +solomaha-denis +soloman1 +solomon1 +solomon123 +solosolo +solotime +soloveibormalei +solstice +solution +solution1 +solutions +solutions1 +solyluna +somanypickles27 +sombrero +somebody +somebody1 +someday1 +someone1 +somerset +somerset1 +something +something1 +something2 +sometime +sometimes +sometimes1 +somewhere +somierda +sommer07 +sommer08 +sommer09 +sommer123 +sonechka +sonechko +songbird +songbird1 +songohan +songoku1 +sonia-91 +sonia123 +sonic123 +sonicboom +sonne123 +sonnenblume +sonnensche +sonnenschein +sonny123 +sonnyboy +sonnyboy1 +sonofabitch +sonofgod +sonshine +sonu1234 +sonumonu +sonusonu +sony1234 +sonya200102 +sonyericson +sonyericss +sonyericsson +sonysony +sonyvaio +sonyvaio1 +sooners1 +sooty123 +sophia01 +sophia07 +sophia08 +sophia10 +sophia11 +sophia12 +sophia123 +sophia13 +sophie01 +sophie05 +sophie06 +sophie07 +sophie08 +sophie09 +sophie10 +sophie11 +sophie12 +sophie123 +sophie13 +sophie14 +sophie15 +sophie21 +sophie22 +sophie23 +sophie99 +sophieytorf +soprano1 +sopranos +sopranos1 +sorcerer +sorciere +sorellina +sorokina +sorokina-999-01 +sorokina7778 +sorpresa +sorrento +sorry123 +soso123aljg +sosososo +soufeliz +soufiane +soukaina +soukayna +souleater +soulfly1 +soulfood +souljaboy +souljaboy1 +souljaboy2 +soulmate +soulmate1 +soulmates +soulreaver +soundwave +south123 +southafrica +southampton +southeast +southeast1 +southend +southend1 +southern +southern1 +southgate +southpark +southpark1 +southpark2 +southpaw +southpole +southpole1 +southpole2 +southport +southsid3 +southside +southside0 +southside1 +southside13 +southside2 +southside3 +southside4 +southside5 +southside6 +southside7 +southside8 +southside9 +southwest +southwest1 +souvenir +sovereign +sovin.sv +sowjanya +soyelmejor +soyfeliz +soylamejor +soyma.ivan +sp.zakaz +sp0ngeb0b +sp1derman +space123 +space1999 +space4me +spaceball1 +spaceballs +spacebar +spacejam +spaceman +spaceman1 +spacemy1 +spaceship +spaceship1 +spagetti +spaghetti +spaghetti1 +spalding +spalding1 +spamar33 +spamspam +spanish1 +spanish2 +spanking +spankme1 +spanky01 +spanky11 +spanky12 +spanky123 +spanky13 +spanky69 +spanner1 +sparhawk +sparkey1 +sparkie1 +sparkle1 +sparkle123 +sparkle2 +sparkles +sparkles1 +sparkplug +sparky01 +sparky10 +sparky101 +sparky11 +sparky12 +sparky123 +sparky13 +sparky22 +sparky23 +sparky69 +sparky99 +sparrow1 +sparrows +spartacus +spartacus1 +spartak1 +spartak1922 +spartan1 +spartan117 +spartan2 +spartan300 +spartan7 +spartans +spartans1 +sparten117 +sparticus +spawn123 +spawn666 +speak2me +speaker1 +speakers +speakers1 +special1 +special123 +special2 +speciala +specialist +specialized +specialk +specialk1 +speckles +spection +spectrum +spectrum1 +speed123 +speedracer +speedster +speedtouch +speedway +speedway1 +speedy01 +speedy11 +speedy12 +speedy123 +speedy13 +spellbound +spelling +spencer! +spencer01 +spencer1 +spencer11 +spencer12 +spencer123 +spencer13 +spencer2 +spencer3 +spencer4 +spencer5 +spencer7 +speranta +speranza +spez3012 +spice333 +spicegirls +spider-man +spider01 +spider10 +spider11 +spider12 +spider123 +spider13 +spider21 +spider22 +spider23 +spider69 +spider99 +spiderma +spiderman +spiderman! +spiderman. +spiderman0 +spiderman1 +spiderman12 +spiderman123 +spiderman2 +spiderman3 +spiderman4 +spiderman5 +spiderman6 +spiderman7 +spiderman8 +spiderman9 +spiderpig +spiderpig1 +spiders1 +spiderweb +spierdalaj +spike123 +spike1234 +spinner1 +spinning +spionin8688 +spiridonmarkin1982 +spirit12 +spirit123 +spiritual +spitfire +spitfire1 +spitsy16 +splender +splendid +splendor +splinter +splinter1 +splintercell +spoiled1 +spokane1 +spongbob +spongbob1 +sponge12 +sponge123 +spongebob +spongebob! +spongebob. +spongebob0 +spongebob1 +spongebob12 +spongebob123 +spongebob2 +spongebob3 +spongebob4 +spongebob5 +spongebob6 +spongebob7 +spongebob8 +spongebob9 +spongecola +spookie1 +spooky12 +spooky123 +spooky13 +spooner1 +sport123 +sportage +sporting +sporting1 +sports10 +sports101 +sports11 +sports12 +sports123 +sports13 +sports21 +sports22 +sports23 +sportsman +sportsmen +sportster +sportster1 +sporu-netu +spotlight +spotlight1 +spread-hop +spring01 +spring06 +spring07 +spring08 +spring09 +spring10 +spring11 +spring12 +spring123 +spring938burston0001990 +spring99 +springbok +springer +springer1 +springfield +springsteen +springtime +sprinkle +sprinkles +sprinkles1 +sprint01 +sprinter +sprinter1 +sprite12 +sprite123 +sprocket +sprocket1 +spurs123 +sputnik1 +sq8hm7l4 +squadup1 +squeaker +squeaky1 +squirrel +squirrel1 +squirtle +squishy1 +sraka105 +sravanthi +srcuqq1_2j1h3rbf +sredina-va +sreedevi +sriganesh +srikanth +srikrishna +srilanka +srilanka1 +srilatha +srinivas +srinivasa +srinivasan +srisairam +srivastava +ss123456 +ss23081937 +ss563563ss +ss6z2sw6lu +ssj4goku +sslazio1900 +sss-nastya-sss +ssssssss +sssssssss +ssssssssss +ssssssssssss +sssuka80 +ssyu1314 +st.louis +stacey12 +stacey123 +stacy123 +staff123 +stafford +stafford1 +stainless +stairway +stalingrad +stalker1 +stalker123 +stalker2 +stalker_lemurrr +stallion +stallion1 +stallone +stamford +stampede +stan021092 +standard +standard1 +standart +stanford +stanford1 +stanislas +stanislav +stanley1 +stanley123 +stanley2 +stanton1 +stapler1 +staples1 +star1234 +star12345 +star2000 +star2006 +star2010 +star7827 +starbaby +starbright +starbuck +starbuck1 +starbucks +starbucks1 +starbucks2 +starburst +starburst1 +starchild +starchild1 +starcraft +starcraft1 +starcraft2 +stardoll +stardoll1 +stardust +stardust1 +staredobre +starfire +starfire1 +starfish +starfish1 +starfleet +starfox1 +stargate +stargate1 +stargatesg1 +stargazer +stargazer1 +stargirl +stargirl1 +starkiller +starlet1 +starlight +starlight1 +starlight2 +starling +starlite +starlite1 +starman1 +starmoon +starpozitiv +starr123 +stars123 +starscream +starshine +starshine1 +starship +starship1 +starsky1 +starstar +starstar1 +starstruck +start123 +starter1 +startfinding +startrek +startrek1 +starwar5 +starwars +starwars! +starwars01 +starwars03ja +starwars1 +starwars10 +starwars11 +starwars111 +starwars12 +starwars123 +starwars13 +starwars2 +starwars22 +starwars3 +starwars4 +starwars5 +starwars6 +starwars7 +starwars77 +starwars9 +starwarsfan10 +starz123 +stas.gorodissky +stas_kolos +stas_the_best.ru +stason16.92 +stason729 +stassenka +stasstas +station1 +station2 +station3 +statistics +stayaway +staycool +stayfly1 +stayoff1 +stayout! +stayout1 +staystrong +stealth1 +steamboat +stecova85 +steeler1 +steelers +steelers! +steelers#1 +steelers01 +steelers06 +steelers07 +steelers08 +steelers09 +steelers1 +steelers10 +steelers11 +steelers12 +steelers13 +steelers2 +steelers3 +steelers36 +steelers43 +steelers5 +steelers6 +steelers7 +steelers86 +steelhead +steelhead1 +steelman +steelseries +stefan12 +stefan123 +stefancelmare +stefangreil1983 +stefani1 +stefania +stefania1 +stefanie +stefanie1 +stefano1 +steffen1 +steflio3123 +steinbock +steinway +stella01 +stella10 +stella11 +stella12 +stella123 +stella13 +stella22 +stella354926 +stellar1 +stellina +stepa-2009 +stepanov +stepanov.ag +stepanov_georgij +stepanova +stepashka +steph123 +stephan1 +stephane +stephane1 +stephani +stephanie +stephanie! +stephanie. +stephanie0 +stephanie1 +stephanie2 +stephanie3 +stephanie4 +stephanie5 +stephanie6 +stephanie7 +stephanie8 +stephanie9 +stephany +stephany1 +stephen1 +stephen11 +stephen12 +stephen123 +stephen2 +stephen3 +stephen7 +stephens +stephie1 +stephon1 +sterling +sterling1 +sternchen +sternchen1 +steroids +stetson1 +steve123 +steven01 +steven06 +steven07 +steven08 +steven09 +steven10 +steven11 +steven12 +steven123 +steven1234 +steven13 +steven14 +steven15 +steven16 +steven17 +steven18 +steven19 +steven20 +steven21 +steven22 +steven23 +steven24 +steven69 +steven88 +stevenash +stevenash1 +stevens1 +stevenson +stevenson1 +stevevai +stewart1 +stewart14 +stewart20 +stgeorge +sticazzi +stickers +stickman +stickman1 +stiffler +stigmata +stiletto +stillwater +stinger1 +stingray +stingray1 +stinker1 +stinky01 +stinky12 +stinky123 +stirling +stitch626 +stitches +stjoseph +stlouis1 +stocazzo +stockholm +stockholm1 +stocking +stockings +stockton +stockton1 +stokecity +stokecity1 +stokrotka +stokrotka1 +stomatolog +stone123 +stone_mitich +stonecold +stonecold1 +stonecold3 +stoned420 +stonehenge +stoner420 +stoner69 +stonewall +stonewall1 +stoopid1 +storm123 +stormdogs +stormers +stormie1 +stormy12 +stormy123 +str8edge +straight +straight1 +strange.lena +strange1 +stranger +stranger1 +strangle +strannik +strasbourg +strategy +stratfor +stratford +stratocast +stratocaster +stratovarius +stratton +stratus1 +strawb3rry +strawberr1 +strawberri +strawberries +strawberry +strawberry1 +street12 +street123 +streetball +streetfighter +streets1 +strekoza +strekoza79 +strelka.m +strength +strength1 +stressed +stressed1 +stretch1 +strezhetova +strider1 +striker1 +strikers +stringer +striper1 +stripes1 +stripped +stripper +stripper1 +strobe93 +stroikarat +stroker1 +strokes1 +strongbad +strongbow +strongbow1 +stronger +stronger1 +stronghold +strongman +structure +struggle +strummer +stryker1 +stsnatasha2008 +stthomas +student1 +student12 +student123 +student2 +studentka +students +studio54 +studioworks +studmuffin +stuff123 +stunner1 +stunt101 +stuntman +stupid01 +stupid101 +stupid11 +stupid12 +stupid123 +stupid13 +stupid22 +stupid69 +stupidass +stupidass1 +stupidbitc +stupidgirl +stuttgart +stuttgart1 +style_style +stylist1 +su123456 +su224466 +sub-zero +subaru29 +subaru555 +subhanallah +sublime1 +sublime2 +sublime420 +sublime69 +sublime7 +submarine +submarine1 +submission +submit123 +subprodukty +subtitle +suburban +suburban1 +subwoofer +subwoofer1 +subzero1 +success! +success01 +success08 +success09 +success1 +success11 +success12 +success123 +success2 +success4me +success7 +success8 +successful +suchitra +suckadick1 +suckdick +suckdick1 +sucker123 +suckers1 +suckit12 +suckit123 +suckit69 +suckme69 +suckmyass69 +suckmyballs +suckmycock +suckmydick +sudarshan +sudhakar +sugar123 +sugarbabe +sugarbaby +sugarbaby1 +sugarbear +sugarbear1 +sugarcane +sugardaddy +sugarfoot +sugarfree +sugarlips +sugarlips1 +sugarpie +sugarpie1 +sugarplum +sugarplum1 +sugarray +sugarsugar +sugipula +suhasini +suicidal +suicidal1 +suicide1 +suikoden +sukabumi +sukasbliat +sukasuka +sukisuki +sulaiman +sulaimon +sulamifcherenchikova1979 +suleiman +suleyman +sullivan +sullivan1 +sulochana +suman123 +summer.fruit +summer00 +summer01 +summer02 +summer03 +summer04 +summer05 +summer06 +summer07 +summer08 +summer09 +summer10 +summer101 +summer11 +summer12 +summer123 +summer1234 +summer13 +summer14 +summer15 +summer16 +summer17 +summer18 +summer19 +summer20 +summer2005 +summer2006 +summer2007 +summer2008 +summer2009 +summer2010 +summer2011 +summer2012 +summer21 +summer22 +summer23 +summer24 +summer25 +summer33 +summer44 +summer45 +summer55 +summer66 +summer67 +summer69 +summer77 +summer78 +summer88 +summer89 +summer96 +summer98 +summer99 +summerfun +summerland +summerlove +summerof69 +summers1 +summertime +summoner +sun1shine +sun2shine +sunburst +sundance +sundance1 +sundaram +sunday12 +sunday123 +sunderland +sundevil +sundin13 +sundrop1 +sunfire1 +sunflower +sunflower1 +sunflower2 +sunflower3 +sunflower4 +sunflower5 +sunflower7 +sunflower8 +sunflowers +sungatullinad +sungelika86 +sunglasses +sunil123 +sunilkumar +sunkanmi +sunkist1 +sunlight +sunlight1 +sunnepa1 +sunnny56 +sunny123 +sunny1234 +sunnyboy +sunnyboy1 +sunnyday +sunnyday1 +sunnydays +sunnyest +sunnyside +sunnyside1 +sunrise1 +sunset12 +sunset123 +sunsh1n3 +sunsh1ne +sunshin3 +sunshine +sunshine! +sunshine. +sunshine0 +sunshine00 +sunshine01 +sunshine02 +sunshine05 +sunshine06 +sunshine07 +sunshine08 +sunshine09 +sunshine1 +sunshine10 +sunshine11 +sunshine12 +sunshine123 +sunshine13 +sunshine14 +sunshine15 +sunshine16 +sunshine17 +sunshine18 +sunshine19 +sunshine2 +sunshine20 +sunshine21 +sunshine22 +sunshine23 +sunshine24 +sunshine25 +sunshine26 +sunshine27 +sunshine28 +sunshine29 +sunshine3 +sunshine30 +sunshine32 +sunshine33 +sunshine4 +sunshine44 +sunshine45 +sunshine5 +sunshine55 +sunshine6 +sunshine66 +sunshine69 +sunshine7 +sunshine77 +sunshine8 +sunshine87 +sunshine88 +sunshine89 +sunshine9 +sunshine99 +sup3rman +supa1906 +super007 +super100 +super123 +super1231 +super1234 +superbad +superbad1 +superbee +superbike +superbowl +superbowl1 +superboy +superboy1 +supercar +supercat +supercool +supercool1 +supercross +superdave +superdog +superdog1 +superdude +superdude1 +superduper +superduty +superfly +superfly1 +superfreak +supergirl +supergirl1 +supergirl2 +superhero +superhero1 +superhuman +superior +superior1 +superjunio +superjunior +superman +superman! +superman. +superman0 +superman00 +superman01 +superman06 +superman07 +superman08 +superman09 +superman1 +superman10 +superman11 +superman12 +superman123 +superman13 +superman14 +superman15 +superman16 +superman17 +superman18 +superman19 +superman2 +superman20 +superman21 +superman22 +superman23 +superman24 +superman25 +superman26 +superman27 +superman28 +superman3 +superman30 +superman32 +superman33 +superman34 +superman4 +superman45 +superman5 +superman55 +superman6 +superman69 +superman7 +superman77 +superman78 +superman8 +superman87 +superman88 +superman89 +superman9 +superman99 +supermanboy +supermann +supermario +supermax +supermen +supermodel +supermom +supermom1 +supernatur +supernatural +supernova +supernova1 +superpippo +superpower +superpuper +supersexy +supersexy1 +supersonic +supersport +superstar +superstar! +superstar0 +superstar1 +superstar2 +superstar3 +superstar4 +superstar5 +superstar6 +superstar7 +superstar8 +superstar9 +superstars +supersuper +supertramp +superuser +supervisor +supervista +superwoman +suppandi +support1 +supported +supreme1 +surabaya +surena13 +surendra +sureno13 +surenos13 +surenox3 +suresh123 +sureshot +surethang +surf4life +surfboard +surfboard1 +surfer12 +surfer123 +surfer69 +surfergirl +surfing1 +surfing123 +surfing2 +surfsup1 +surgery1 +suriname +surinder +surooo777 +surprise +surprise1 +surrender +surrender1 +surround +surside13 +surveyor +survival +survivor +survivor1 +susan123 +susanita +susanna1 +susannah +susanne1 +sushi123 +sushmita +susie123 +suspects20 +sutenm123456 +sutherland +suzanne1 +suzette1 +suzuki1000 +suzuki123 +suzuki125 +suzuki250 +suzuki600 +suzuki750 +sverige1 +sveta-kisil +sveta123 +svetasveta +svetik_kryuchkov +svetlana +svetlana-mironova-13 +svetlana1 +svetlana26rus +svetlana_07 +svetlanka +sveto4ka +svetochka +svitlana +svoron1977 +sw0rdf1sh +sw0rdfish +sw705547 +swagg123 +swagger1 +swallow1 +swaminarayan +swamisamarth +swampfire +swamphen +swanlake +swansea1 +swastika +sweeney1 +sweet101 +sweet123 +sweet1234 +sweet666 +sweetangel +sweetass +sweetbaby +sweetbaby1 +sweetboy +sweetcandy +sweetcheeks +sweetdream +sweetdreams +sweetest +sweetgirl +sweetgirl1 +sweethart +sweetheart +sweetheart1 +sweethome +sweethoney +sweetie! +sweetie01 +sweetie1 +sweetie11 +sweetie12 +sweetie123 +sweetie13 +sweetie2 +sweetie22 +sweetie3 +sweetie4 +sweetie5 +sweetie7 +sweetie8 +sweetiepie +sweeties +sweetlady +sweetlips +sweetlove +sweetlove1 +sweetlover +sweetman +sweetmother +sweetness +sweetness1 +sweetness2 +sweetness3 +sweetone +sweetpea +sweetpea! +sweetpea1 +sweetpea12 +sweetpea2 +sweetpea3 +sweetpea7 +sweetpie +sweets12 +sweets123 +sweetstuff +sweetsweet +sweettea +sweetthang +sweetthing +sweetwater +sweety01 +sweety11 +sweety12 +sweety123 +sweety13 +sweety22 +sweety23 +sweetypie +sweetypie1 +swetlana +swimmer1 +swimmer2 +swimming +swimming! +swimming1 +swimming12 +swimming2 +swinger1 +swingers +swisher1 +switchfoot +switzerland +sword123 +swordfis +swordfish +swordfish1 +swordfish2 +swordfish7 +swordsman +sxuaiehatp +sycamore +sycamore1 +sydney00 +sydney01 +sydney07 +sydney08 +sydney10 +sydney11 +sydney12 +sydney123 +sydney13 +sydney2000 +sydney22 +sydney99 +sylvania +sylvester +sylvester1 +sym_cskill1 +symantec +symmetry +symphony +syncmaster +syndicate +synergy1 +synyster +synyster1 +syracuse +syracuse1 +sys64738 +sysadmin +system12 +system123 +system32 +systemofadown +syyrrqbe70 +sz9kqcctwy +szczurek +szerelem +szeretlek +szgd4ey287 +t1234567 +t12345678 +t123456789 +t1nkerbell +t36473647 +t5e1q9shfd +t5r4e3w2q1 +t_v_belyakova +ta123456 +tabaluga +tabasco1 +tabassum +tabatha1 +tabby123 +tabbycat +tabbycat1 +tabitha1 +taburetka +taco1234 +tacobell +tacobell1 +tacobell12 +tacobell2 +tacos123 +tacotaco +tadpole1 +taekwondo +taekwondo1 +tafadzwa +taffy123 +tagesgruppe2010 +tagheuer +taishan2011 +tajmahal +tajudeen +takahiro +takamine +takamine1 +takataka +takayuki +takecare +takedown +takeiteasy +takeover1 +takethat +takishima +takoyaki +talavera +talented +talented1 +taliesin +talisman +talktome +talleres +tallulah +tamagotchi +tamahome +tamara12 +tamara123 +tamarindo +tamerlan +tamilnadu +tammy123 +tampa813 +tampabay +tampabay1 +tamriko0942 +tanechka +tangerang +tangerine +tangerine1 +tanginamo +tanglewood +tango123 +tangtang +tania123 +tanisha1 +tanja1993 +tanjiang999 +tanktank +tanner01 +tanner10 +tanner11 +tanner12 +tanner123 +tanner13 +tanner22 +tanning1 +tanushka +tanya123 +tanzania +taobao887 +tara1234 +tarantado +tarantino +tarantul +tarantula +tarasenko +tarasova +taratara +taratata +target123 +tarheel1 +tarheels +tarheels1 +tarheels23 +tarik-66 +tarragon +tarragona +tartaruga +tarzan00 +tasha123 +tashkent +taskaev777 +tasmania +tassadar +tastatura +tastiera +tata1234 +tata1964 +tatarstan +tatatata +taterbug +taterbug1 +tatertot +tatertot1 +tatiana1 +tatianna +tattoo13 +tattoo69 +tattoos1 +tatyana1 +taugamma +taugammaph +taxidriver +taylor00 +taylor01 +taylor02 +taylor03 +taylor04 +taylor05 +taylor06 +taylor07 +taylor08 +taylor09 +taylor10 +taylor101 +taylor11 +taylor12 +taylor123 +taylor1234 +taylor13 +taylor14 +taylor15 +taylor16 +taylor17 +taylor18 +taylor19 +taylor20 +taylor21 +taylor22 +taylor23 +taylor24 +taylor25 +taylor26 +taylor27 +taylor33 +taylor56 +taylor69 +taylor77 +taylor88 +taylor92 +taylor93 +taylor94 +taylor95 +taylor96 +taylor97 +taylor98 +taylor99 +taylorgang +taylorlaut +taylormade +taylorswif +taylorswift +taytay11 +taytay12 +taytay123 +taytay13 +tayuya44 +tazdevil +tazmania +tazmania1 +tazmanian +tbfj7no671 +tdubdub05 +tdws011286 +teacher1 +teacher12 +teacher123 +teacher2 +teacher3 +teacher5 +teachers +teaching +teamedward +teamjacob +teamo100 +teamo123 +teamoamor +teamobebe +teamodios +teamojesus +teamomama +teamomiamor +teamomucho +teamomuxo +teamwork +teamwork1 +teardrop +teardrop1 +techdeck +techdeck1 +techn9ne +technical +technician +technics +technics1 +technics12 +techno123 +techno13 +techno2009 +technology +tecktonik +tecnologia +tecumseh +teddy101 +teddy123 +teddybear +teddybear! +teddybear0 +teddybear1 +teddybear2 +teddybear3 +teddybear4 +teddybear5 +teddybear6 +teddybear7 +teddybear8 +teddybear9 +teddybears +teddyboy +teenaa111 +teenager +teentitans +teh-consul +teiubesc +teixeira +tekiero1 +telecaster +telechargement +telecom1 +telecono +telefon1 +telefone +telefonica +telefonino +telefono +telefono1 +telefoon +telegina_65 +telemark +telephone +telephone1 +teleport +television +televisione +televizor +tema-bushelev +tema.barabin +temidayo +temitayo +temitope +temitope1 +temp1234 +tempest1 +tempesta +tempesth1941 +templar1 +temporal +temporary +temporary1 +temppass +temppass1 +temppassword +temptation +temptemp +tendresse +tendulkar +tenerife +tenerife1 +tennessee +tennessee1 +tennis01 +tennis07 +tennis08 +tennis09 +tennis10 +tennis11 +tennis12 +tennis123 +tennis13 +tennis14 +tennis21 +tennis22 +tennis23 +tennisball +tennyson +tenten10 +teonamaria1 +tequiero +tequiero1 +tequiero12 +tequiero2 +tequieromu +tequieromucho +tequila1 +tequilla +terenaam +terence1 +teresa01 +teresa11 +teresa12 +teresa123 +teresina +teresita +terezinha +terminal +terminal1 +terminator +terminator1 +terminator2 +termite1 +ternopil +terorist +terra123 +terrance +terrance1 +terranova +terrapin +terrell1 +terrell2 +terremoto +terrence +terrence1 +terrible +terrible1 +terriers +terrific +terrorist +terry123 +terserah +tessa123 +test1234 +test12345 +test123456 +testaccount +testament +teste123 +tester01 +tester12 +tester123 +testing1 +testing123 +testpass +testqa12 +testtest +testtest1 +teufel99 +texas100 +texas123 +texas210 +texas214 +texas254 +texas713 +texas817 +texasdoor +texasmade1 +texastech +texastech1 +tfzwf44idb +tgpw53j3kg +tgzvf55idb +thaddeus +thaddeus1 +thailand +thailand1 +thanatos +thanh123 +thanhcong +thanhtung +thankful +thankful1 +thankgod +thankgod1 +thanksgod +thankyou +thankyou1 +thankyou2 +thatbitch1 +thatcher +thatguy1 +thatnigga1 +thatshot +thatshot1 +thatsme1 +the1andonl +the1andonly +the1ilove +the1nonly +the1ring +the2ofus +the69eyes +theanswer +theanswer3 +theater1 +theatre1 +theband1 +thebeach +thebears12 +thebeast +thebeast1 +thebeatles +thebest1 +thebest12 +thebest123 +thebest2 +thebest99 +thebible +thebigboss +thebitch +thebitch1 +theblock +theblues +thebomb1 +theboss1 +theboys1 +theboys2 +theboys3 +thechamp +thechamp1 +thechosen1 +theclash +thecool1 +thecrazymaxim +thecrew1 +thecrow1 +thecure1 +thedark1 +thedevil +thedoctor +thedoors +thedoors1 +thedude1 +theduke1 +theflash +theforce +theforce1 +thegame1 +thegame12 +thegame123 +thegame2 +theghost +thegirls +thegreat +thegreat1 +thegreat12 +thegreat123 +thegreatone +thehulk1 +theiigd4x2 +theiige4x2 +thejoker +thejoker1 +thekiller +thekiller1 +thekillers +theking1 +theking12 +theking123 +theking2 +theking23 +thelast1 +thelegend +thelord1 +thelordisgood +theman11 +theman12 +theman123 +theman22 +theman23 +theman69 +themaster +themaster1 +thematrix +thematrix1 +thenewme +thenewozer +thenumber1 +theodora +theodore +theodore1 +theone01 +theone11 +theone12 +theone123 +theonly1 +theonlyone +thepassword +thepimp1 +thepower +thequeen +thequeen1 +therapist +therapy1 +therasmus +thereal1 +thereisnospoon +theresa1 +theresa2 +therese1 +theresia +therock1 +therock123 +therock2 +thesaint +thesame1 +thesecret +thesecret1 +thesexy1 +theshit1 +thesimpsons +thesims1 +thesims2 +thesims3 +thesmokin +thespian +thestrokes +thething +thetruth +thetruth1 +thetwins +theused1 +theused2 +thewall1 +theworld +theworld1 +thiago123 +thibault +thickness +thickness1 +thienthan +thierry1 +think123 +think456 +thinkbig +thinking +thinking1 +thinkpad +thinkpink +thinkpink1 +thirdeye +thirteen +thirteen13 +thirty30 +thisisgay +thisisgay1 +thisisit +thisisit1 +thisisme +thisisme1 +thisismine +thisismypassword +thissucks +thissucks1 +thissucks2 +thistle1 +thomas00 +thomas01 +thomas02 +thomas03 +thomas04 +thomas05 +thomas06 +thomas07 +thomas08 +thomas09 +thomas10 +thomas11 +thomas12 +thomas123 +thomas1234 +thomas13 +thomas14 +thomas15 +thomas16 +thomas17 +thomas18 +thomas19 +thomas20 +thomas21 +thomas22 +thomas23 +thomas24 +thomas25 +thomas26 +thomas27 +thomas28 +thomas30 +thomas33 +thomas44 +thomas55 +thomas69 +thomas77 +thomas87 +thomas88 +thomas89 +thomas91 +thomas92 +thomas94 +thomas95 +thomas97 +thomas98 +thomas99 +thompson +thompson1 +thomson1 +thornton +thornton1 +thorsten +thought1 +thousand +thrasher +thrasher1 +three333 +threeboys +threegirls +threekids +threekids3 +threesome +threesome3 +thriller +thriller1 +thtajehzsp +thug4life +thuggin1 +thuglife +thuglife1 +thuglife12 +thuglife13 +thuglife2 +thuglife3 +thuglife7 +thuglove +thuglove1 +thugstools +thumper1 +thumper12 +thumper123 +thumper2 +thumper3 +thunder! +thunder01 +thunder1 +thunder10 +thunder11 +thunder12 +thunder123 +thunder13 +thunder2 +thunder21 +thunder22 +thunder23 +thunder3 +thunder4 +thunder5 +thunder6 +thunder69 +thunder7 +thunder8 +thunder9 +thunderbir +thunderbird +thunderbolt +thundercat +thundercats +thunders +thunderstorm +thursday +thursday1 +thurston +thuylinh +tiago123 +tiamaria +tiamotanto +tiantian +tiberian +tiberium +tiberius +tibia123 +tiburon1 +tichuots +ticktock +ticotico +tiddles1 +tielandros01 +tiffani1 +tiffanie +tiffany! +tiffany. +tiffany01 +tiffany08 +tiffany09 +tiffany1 +tiffany10 +tiffany11 +tiffany12 +tiffany123 +tiffany13 +tiffany14 +tiffany15 +tiffany16 +tiffany17 +tiffany18 +tiffany2 +tiffany21 +tiffany22 +tiffany23 +tiffany3 +tiffany4 +tiffany5 +tiffany6 +tiffany69 +tiffany7 +tiffany8 +tiffany9 +tiger007 +tiger100 +tiger101 +tiger111 +tiger123 +tiger1234 +tiger2000 +tiger2010 +tiger321 +tiger777 +tigerboy +tigercat +tigercat1 +tigereye +tigerlilly +tigerlily +tigerlily1 +tigerman +tigers01 +tigers05 +tigers06 +tigers07 +tigers08 +tigers09 +tigers10 +tigers11 +tigers12 +tigers123 +tigers13 +tigers14 +tigers15 +tigers21 +tigers22 +tigers23 +tigers24 +tigers33 +tigers69 +tigers84 +tigertiger +tigerwoods +tigger00 +tigger01 +tigger02 +tigger03 +tigger04 +tigger05 +tigger06 +tigger07 +tigger08 +tigger09 +tigger10 +tigger101 +tigger11 +tigger12 +tigger123 +tigger1234 +tigger13 +tigger14 +tigger15 +tigger16 +tigger17 +tigger18 +tigger19 +tigger20 +tigger21 +tigger22 +tigger23 +tigger24 +tigger25 +tigger26 +tigger27 +tigger28 +tigger33 +tigger44 +tigger45 +tigger55 +tigger66 +tigger67 +tigger68 +tigger69 +tigger77 +tigger87 +tigger88 +tigger89 +tigger99 +tigrenok +tigresse +tigrotto +tijger3417 +tijgertje +tijuana1 +tikitiki +tilly123 +timbaland +timberlake +timberland +timberwolf +timbuktu +time2die +time2fly +time2play +time4fun +timebomb +timeless +timeless1 +timeline +timelord +timeout1 +timepass +timetime +timfranzke +timileyin +timisoara +timmy123 +timoshka +timothy01 +timothy1 +timothy12 +timothy123 +timothy2 +timothy3 +timothy5 +timothy7 +timoxa94 +tina1234 +tinamarie +tinatina +tingting +tingtong +tink1234 +tink3rb3ll +tinkabell1 +tinker01 +tinker09 +tinker10 +tinker11 +tinker12 +tinker123 +tinker13 +tinker14 +tinker15 +tinker21 +tinker22 +tinker23 +tinkerbe11 +tinkerbel1 +tinkerbell +tinkerbell1 +tinkerbell12 +tinkerbelle +tinktink +tinotenda +tintin123 +tinydancer +tinytim1 +tiphaine +tipperary +tippmann +tippmann1 +tippmann98 +tippy123 +tiramisu +tirupati +tishenkoff +titan123 +titanic1 +titanic12 +titanic123 +titanic1912 +titanic2 +titanium +titanium1 +titans10 +titans12 +titilayo +titititi +titleist +titleist1 +titotito +titties1 +titties2 +tivogliobene +tkachenko +tkbpfdtnf +tkfkdgo0 +tkfkdgo1 +tkfkdgo7 +tkgsoo083bsr +tl281188t +tmnet123 +tmobile1 +tmvlzj12 +tnk0mk16vx +toast123 +toaster1 +tobeornottobe +tobias12 +tobias123 +tobiloba +toblerone +toby1234 +tobydog1 +tobytoby +tochukwu +today123 +toenail1 +together +together1 +together2 +toietmoi +toilatoi +toiyeuem +tokiohotel +tolentino +tolkien1 +tolstyh.oxana +tolulope +tom12345 +tomahawk +tomahawk1 +tomandjerry +tomas123 +tomasito +tomaszek +tomatoes +tomboy07 +tombrady +tombrady12 +tombraider +tombstone +tombstone1 +tomcat14 +tomcruise +tomdelonge +tomek123 +tomfelton +tomislav +tomjerry +tomjones +tomkaulitz +tomlinson +tommy123 +tommy1234 +tommyboy +tommyboy1 +tommygirl +tommygirl1 +tommygun +tommylee +tomodachi +tomorrow +tomorrow1 +tomtom11 +tomtom12 +tomtom123 +tomtomtom +tomwaits +tomwelling +tongtong +tonight1 +tonitoni +tonkpils +tony1234 +tonyhawk +tonyhawk1 +tonymontana +tonyromo9 +tonytony +toocool1 +toocute1 +toodles1 +toohot4u +toolbox1 +toolman1 +tooltime +toomuch1 +toonarmy +toonarmy1 +toontown +toontown1 +toosexy1 +tooshort +tooshort1 +toosweet +toothbrush +toothfairy +toothpaste +toothpick +toothpick1 +tootsie1 +tootsie2 +toottoot +topaz.null +topbutton +topdevice +topgear1 +topmodel +topmodel1 +topnotch +topnotch1 +topogigio +topography +topolina +topolino +topsecret +topsecret1 +toratora +torchwood +torchwood1 +torgsotra +toriamos +toriamos1 +tormenta +tornado1 +toronto1 +torpedo1 +torrance +torrente +torrents +torres09 +torres10 +torres12 +torres123 +tortilla +tortoise +tortuga1 +toshiba1 +toshiba123 +toshiba2 +total12scherz +totally1 +totalwar +totenkopf +toto1234 +totototo +totoybato +tottenham +tottenham1 +tottigol +touchdown +touchdown1 +toughguy +toujours +toulouse +toulouse1 +toulouse31 +tournesol +toutoune +townsend +townsend1 +towtruck +toxicity +toymachine +toyota01 +toyota11 +toyota12 +toyota123 +toyota99 +toyotamr2 +toyplanet +toystory +toystory2 +tpklmq9668 +tpxerxjmp +trabajo1 +trabalho +trabzon61 +trabzonspor +track123 +tracker1 +trackstar +trackstar1 +tracteur +tractor1 +tractors +tracy123 +trademark +trafalgar +traffic1 +trafford +trailblazer +trailer1 +train123 +trainer1 +training +training1 +tralala1 +tramonto +trampoline +trandafir +tranmere +tranquil +transalp +transam1 +transcend +transfer +transform +transform1 +transforme +transformer +transformers +transit1 +transport +transport1 +transporter +trapdoor39 +trapdoor43 +trapdoor60 +trapper1 +trapstar +trapstar1 +trase1990 +trashcan +trashcan1 +travel123 +travel88 +traveler +traveler1 +traveller +travelmate +travelmoleoptin +travelpack1 +traviesa +traviesa1 +travieso +travieso1 +travis01 +travis07 +travis08 +travis09 +travis10 +travis11 +travis12 +travis123 +travis13 +travis14 +travis15 +travis16 +travis199 +travis21 +travis22 +travis23 +travis69 +travolta +traxdata +traxxas1 +treacle1 +treasure +treasure1 +treble99 +trecool1 +tree1234 +treefrog +treefrog1 +treehouse +treehouse1 +treehugger +trees123 +treetop1 +treetops +treetree +treguier +trent123 +trenton1 +trevor01 +trevor10 +trevor11 +trevor12 +trevor123 +trevor13 +treysongz +treysongz1 +treytrey +trezeguet +trfnthbyf +triangle +triangle1 +triathlon +tribunal +trickster +trickster1 +tricolor +trident1 +triforce +triforce1 +trigger1 +trigger2 +trikers21 +trinacria +trindade +trinidad +trinidad1 +trinitron +trinitron1 +trinity01 +trinity05 +trinity06 +trinity07 +trinity08 +trinity1 +trinity11 +trinity12 +trinity123 +trinity2 +trinity3 +trinity4 +trinity5 +trinity6 +trinity7 +trinity8 +tripleh1 +triplet3 +triplets +triplets3 +tripper1 +triskelion +tristan01 +tristan1 +tristan12 +tristan123 +tristan2 +tristan3 +tristan7 +tristen1 +tristian +tristin1 +triston1 +tristram +triumph1 +trivium1 +trixie01 +trixie12 +trixie123 +trofimishe +trogdor1 +troika93 +trojans1 +troll123 +trollface +trombone +trombone1 +trompeta +trompete +trompette +tronwell +trooper1 +trooper2 +troopers +tropical +tropical1 +tropicana +tropicana1 +trotter1 +trouble! +trouble1 +trouble12 +trouble123 +trouble13 +trouble2 +trouble3 +trouble69 +trouble7 +troubled1 +troubles +troubles1 +trouducul +trousers +troyboy1 +truck123 +truckdriver +trucker1 +trucking +trucking1 +trueblood +trueblue +trueblue1 +truelove +truelove! +truelove08 +truelove1 +truelove12 +truelove13 +truelove2 +truelove3 +truelove7 +truffle1 +truffles +truffles1 +trujillo +trujillo1 +trumpet1 +trumpet2 +truskawka +trust123 +trustgod +trustgod1 +trusting +trustingod +trustme1 +trustme2 +trustme_k +trustn01 +trustno1 +trustno2 +trustnoone +tryagain +tryagain1 +trythis1 +tsunami1 +tt123456 +tt1234567 +ttd955audg +tttttttt +tttttttttt +tucker01 +tucker10 +tucker11 +tucker12 +tucker123 +tucker13 +tucker22 +tuermchen +tuesday1 +tuesday2 +tugboat1 +tujheirf +tulipano +tumadre1 +tumbleweed +tunafish +tunafish1 +tunde123 +tunde12345 +tundra_cool2 +tupac123 +tupacshakur +tuppence +tuputamadre +turandot +turbo123 +turion64 +turkey12 +turkey123 +turkish1 +turntable +turntable1 +turquoise +turtle01 +turtle10 +turtle11 +turtle12 +turtle123 +turtle13 +turtle14 +turtle21 +turtle22 +turtle23 +turtle69 +turtles1 +turtles2 +turtoise +tutifruti +tvinktvink +tw1l1ght +tweeling +tweetie1 +tweety01 +tweety06 +tweety07 +tweety08 +tweety09 +tweety10 +tweety101 +tweety11 +tweety12 +tweety123 +tweety13 +tweety14 +tweety15 +tweety16 +tweety17 +tweety18 +tweety19 +tweety20 +tweety21 +tweety22 +tweety23 +tweety24 +tweety25 +tweety69 +tweetybird +tweetypie +twelve12 +twenty20 +twentyfour +twentyone +twentysix +twentytwo +twilight +twilight! +twilight. +twilight01 +twilight08 +twilight09 +twilight1 +twilight10 +twilight11 +twilight12 +twilight123 +twilight13 +twilight14 +twilight15 +twilight16 +twilight17 +twilight2 +twilight21 +twilight22 +twilight23 +twilight3 +twilight4 +twilight5 +twilight6 +twilight7 +twilight8 +twilight9 +twinboys +twingirls +twinkie1 +twinkie2 +twinkies +twinkle1 +twinkle15 +twinkle2 +twinkles +twinkletoes +twins123 +twinturbo +twisted1 +twisted2 +twister1 +twister2 +twiztid1 +twoboys2 +twogirls +twojastara +twokids2 +tx9z6ht5eo +ty123456 +ty2t1hv3oc +tygferrfddss +tygrysek +tyler101 +tyler123 +tyler1234 +tyler12345 +tyler2000 +tyler2006 +tyler2008 +tylerjames +typetogether +typewriter +typhoon1 +tyrael04 +tyrone12 +tyrone123 +tyrone79 +tyshawn1 +tyson123 +tyumchenko_ok +tzir25l5kn +u.hohlov +u0hgtkt617 +u1v7hhh7ef +u6e6r9hwix +u6kz2lppto +u83xu3u83 +ubvyfpbz +uekmyfhf +ufhhbgjnnth +ufhvjybz +ufkfrnbrf +ugaug55jdb +uglybitch1 +ugochukwu +uhbujhbq +uhbujhmtdf +uhfaabnb +uhfybn8888 +uifkjhf522 +uis9zdgysn +ujkjdjkjvrf +uk7860loans +ukflbfnjh +ukflbfnjh12 +ukflbfnjh12345 +ukflbjkec +ukraine1 +ultimate +ultimate1 +ultimatum +ultraman +ultraviolet +ulysse31 +umbrella +umbrella1 +umit1406 +ummagumma +un4given +unbreakable +unclesam +undefined +under0ath +undercover +underdog +underdog1 +undergroun +underground +underoath +underoath1 +underoath7 +underpants +underscore +understand +undertaker +undertaker1 +undertow +underwater +underwear +underwear1 +underwood +underwood1 +underworld +unfaithful +unforgiven +unhappy1 +unicorn1 +unicorn12 +unicorn123 +unicorn2 +unicorn7 +unicornio +unicorns +unicorns1 +unilever +unique123 +united01 +united10 +united11 +united12 +united123 +united99 +unitedkingdom +unitedstates +univers2l +universal +universal1 +universe +universe1 +universidad +universita +universitario +university +universo +universum +unknown1 +unleashed +unleashed1 +unlimited +unlimited1 +unloved1 +unlucky1 +unlucky13 +unodostres +untitled +untouchable +uphill45 +upyachka +upyours1 +upyours2 +uqa9ebw445 +urdg5psk5 +urlacher54 +urmom123 +urmomma1 +uruguay1 +us7860loans +usa12345 +usasf1234 +useless1 +user1234 +username +username1 +useruser +usharani +usher123 +usher8701 +usman123 +usmarine +usmarines +usmc0311 +usmc1775 +usuck123 +utahjazz +uthvfybz +utjuhfabz +utjvtnhbz +utn05wwy +utyyflbq +uuuuuuuu +uvgx8f8232 +uyqlvip773 +uzbekistan +uzbjnei451 +uzumaki1 +uzumaki2 +uzumakinaruto +v1234567 +v12345678 +v123456789 +v1ctoria +v3uriah1 +v3xafy4k3y +vacaciones +vacances +vacation +vacation1 +vader123 +vadim123 +vadyusha.isaev.83 +vaemai31 +vaffanculo +vagabond +vagina12 +vagina123 +vagina69 +vainilla +vaishali +vaishnavi +vakantie +val353nxhc +valdemar +valdivia +valencia +valencia1 +valentin +valentin1 +valentina +valentina.victoria +valentina1 +valentina2 +valentine +valentine1 +valentine2 +valentines +valentinka +valentino +valentino1 +valentino46 +valentinorossi +valenzuela +valeria1 +valeria12 +valeria123 +valeria2 +valerian +valerie1 +valerie12 +valerie123 +valerie2 +valeriya +valhalla +valhalla1 +valiente +valkenhayn +valkiria +valkyrie +valladolid +vallarta +vallejo1 +vallejo707 +valleyforge +valparaiso +valverde +valya-city +valya-garanina +valya-lera1 +valya-sidenko +valya-valya-1982 +valya.2057 +valya.gorodn +valya.ivko +valya.klimenko.87 +valya.korobeynik +valya.kryuchkova.1990 +valya.lantux.83 +valya.shapoval +vampire! +vampire1 +vampire11 +vampire12 +vampire123 +vampire13 +vampire2 +vampire3 +vampire6 +vampire666 +vampire69 +vampire7 +vampires +vampires1 +vampiro1 +vanbasten +vancouver +vancouver1 +vandamme +vandread +vanechka +vanessa! +vanessa. +vanessa01 +vanessa06 +vanessa1 +vanessa10 +vanessa11 +vanessa12 +vanessa123 +vanessa13 +vanessa14 +vanessa141175 +vanessa15 +vanessa16 +vanessa17 +vanessa18 +vanessa2 +vanessa21 +vanessa22 +vanessa23 +vanessa3 +vanessa4 +vanessa5 +vanessa6 +vanessa7 +vanessa8 +vanessa9 +vangelis +vangogh1 +vanguard +vanguard1 +vanhalen +vanhalen1 +vanhelsing +vanilla1 +vanilla12 +vanilla123 +vanilla2 +vanille1 +vannessa +vanpersie +vanquish +vanshika +varadero +varanasi +varduhigohar +varfeevich +varfolomeeva0990 +varfolomey_72 +varghese +varich-masha +varida.alibaeva +varitek33 +varshini +varsity1 +vasantha +vasanthi +vascodagama +vascorossi +vaseline +vaseline1 +vashenko.u.u +vasilenko +vasileva +vasilica +vasilina +vasilisa +vasquez1 +vatoloco +vatoloco1 +vatoloco13 +vatoslocos +vaughan1 +vauxhall +vauxhall1 +vaz21093 +vaz21099 +vazquez1 +vbhjckfdf +vbhjyjdf +vbitymrf +vbkkbjyth +vc123456 +vedro.ru +vef6g55frz +vegas123 +vegas702 +vegemite +vegeta11 +vegeta12 +vegeta123 +vegetable +vehpbkrf +vehvfycr +velasquez +velazquez +velocity +velocity1 +velosiped +vencedor +vendetta +vendetta1 +vendredi +vendredi13 +venezuela +venezuela1 +venganza +vengeance +vengeance1 +venividivici +venkatesh +venom123 +venom666 +venta021 +ventilador +ventura1 +venture1 +venugopal +venus123 +veracruz +veracruz1 +veralipatnikova +veravera +verbatim +verbatim1 +vergessen +vergessen1 +vergeten +veri1234 +veritas1 +verizon1 +verizon123 +verizon2 +vermelho +vermilion +vermillion +vermont1 +verochka +veronica +veronica1 +veronica10 +veronica12 +veronica13 +veronica2 +veronica3 +veronica7 +veronika +veronika1 +veronique +versace1 +versailles +versatile +version1 +vertical +vertigo1 +verto00q +verygood +verynice +vesproongh12 +veterinaria +vfhbfyyf +vfhbjk1801 +vfhbyf123 +vfhbyjxrf +vfhecmrf +vfhnsirf +vfhufhbnf +vfhufhbnrf +vfhvtkfl +vfhvtkflrf +vfiekmrf +vfifvfif +vfitymrf +vfkmdbyf +vfktymrbq +vfktymrfz +vflfufcrfh +vfnbkmlf +vfnhtirf +vfntvfnbrf +vfpfafrf +vfrcbv123 +vfrcbvec +vfrcbvjdf +vfrcbvrf +vfrfhjdf +vfrfhjys +vfvekbxrf +vfvekmrf +vfvektxrf +vfvfbgfgf +vfvfgfgf +vfvfgfgfz +vfvfvfvf +vfvfvskfhfve +vfvihss591 +vfylfhby +vfylfhbyrf +vfyxtcnth +vgizetdinov +vhbth55jec +vicecity +vicecity1 +vicelord5 +vicente1 +vicious1 +vicky123 +victoire +victor01 +victor10 +victor11 +victor12 +victor123 +victor13 +victor14 +victor15 +victor16 +victor21 +victor22 +victor23 +victor69 +victor_evdokimov +victor_sakhalin1990-20 +victorclavier +victorfrunz +victorhugo +victori1967 +victoria +victoria! +victoria-berkat-energo +victoria-dyatlova +victoria. +victoria.20000 +victoria.kl106 +victoria01 +victoria07 +victoria08 +victoria1 +victoria10 +victoria11 +victoria12 +victoria123 +victoria13 +victoria14 +victoria14.09 +victoria15 +victoria19 +victoria2 +victoria20 +victoria21 +victoria22 +victoria23 +victoria3 +victoria392eliezrie1992frp +victoria4 +victoria5 +victoria6 +victoria7 +victoria8 +victoria9 +victoria989 +victoria_002 +victoria_91 +victoria_shkurco +victoriandr01 +victorious +victoriy70 +victory1 +victory123 +victory2 +victory7 +vicusa.tatyana +vidaloca +vidaloka +vidanova +vidanueva +video123 +videogame +videogame1 +videogames +viernes13 +vietnam1 +viewsonic +viewsonic1 +vigilante +vihlaeva2012 +vihotsieva94 +vihrova1974 +vijay123 +vijaykumar +vik22535477 +vika-selfish +vika.krivonos.1995 +vika1994 +vika1995 +vika1996 +vika1997 +vika1998 +vika2010 +vikas123 +vikavika +viking11 +viking12 +viking123 +vikings1 +vikings11 +vikings12 +vikings2 +vikings28 +viktoria +viktoria1 +viktorija +viktoriy +viktoriya +villa123 +village1 +villalobos +villamor +villanova +villanueva +villareal +villarreal +ville666 +villegas +villeneuve +villevalo +villevalo1 +vinay123 +vinayaka +vince123 +vincent01 +vincent1 +vincent11 +vincent12 +vincent123 +vincent13 +vincent2 +vincent3 +vincent5 +vincent7 +vincenza +vincenzo +vincenzo1 +vindiesel +vineyard +vinicius +vinny123 +vinograd +vintage1 +violator +violence +violet12 +violet123 +violeta1 +violetta +violette +vip_trading +viper123 +vipergts +viphv5j736 +virendra +virgilio +virgilio12 +virginia +virginia1 +virginia12 +virginia2 +virginie +virgo123 +viridiana +viridiana1 +virtual1 +virtue1234 +virus123 +vishakha +vishal123 +vishenka +vision123 +vitalina +vitamin1 +vitamina +vitamine +vitaminka88 +vitolino10 +vitor123 +vitor1268123 +vitoria1 +vittoria +vittorio +vivalabam +vivalabam1 +vivalafica +vivalafiga +vivalavida +vivamexico +vivek123 +vivian123 +viviana1 +vivienne +vivitron +vjflkig522 +vjhjpjdf +vjhrjdrf +vjqgfhjkm +vjs9zdgyrn +vjzctvmz +vjzgjxnf +vk_vk_777 +vkontakte +vkontakte.ru +vkontkate +vkoomare88 +vkorotin +vkoryano +vkot_2010 +vkoval87 +vkovshut_annab1988fg +vkpxrnoda +vkravchenko +vkrbashyan +vkryshkin +vks1zz9v_7ceu69 +vkundeyai +vkuradovetc +vlad1234 +vlad12345 +vlad1994 +vlad1995 +vlad1996 +vlad1997 +vlad1998 +vlad1999 +vlad2000 +vlada1206 +vladcherktecktonik +vladimir +vladimir1 +vladimirovna +vladislav +vladislava +vladivostok +vladvlad +vm.shlykov +vodafone +vodafone1 +vodka123 +voetbal1 +voitures +vojykgi959 +volcano1 +volcom11 +volcom12 +volcom123 +volcom13 +volcom14 +volcom21 +volcom22 +volcom23 +volcom69 +voldemar +voldemort +voldemort1 +volfram.kozlov123633 +volfram.kozlov173902 +volga11955 +volgirevagv +volgograd +volgograd.orlovka +volhina-73 +volhsara56 +voliahim1891 +volik-yulia +volimte1 +voljanka1976 +volkodav +volkorez +volkova.67 +volkova.elena.13 +volkova.ksyusha.89 +volkovanata77 +volkovaolguna +volkovoi_net +volkslt35 +volkswagen +volkswagon +volley11 +volley12 +volleybal1 +volleyball +volleyball1 +vollyball1 +volodina.elena66 +volodya-ivanov-63 +volohovich-t +volokitina.olga +voloshink +voltage1 +voltaire +voltron1 +volunteer +volunteer1 +volvo123 +volvo240 +volvo740 +volvo850 +volvofh12 +volvos40 +volvos60 +volvos80 +volvov40 +volvov70 +volvoxc90 +vondutch +voodoo13 +voroshilova.liliya +vote4pedro +vova1997 +vova1998 +vovavova +vovochka +voyager1 +vqsablpzla +vqz6qyo294 +vrbgqns997 +vrushali +vsevolod +vsjasnel12 +vthctltc +vtkmybrjdf +vtuf36jhufpv +vtufgjkbc +vuc7neyu0 +vvv666vvv +vvvvvvvv +vvvvvvvvvv +vwpassat +vyacheslav +vyjujnjxbt +w00tw00t +w0rdpass +w12101957 +w1234567 +w12345678 +w123456789 +w123456789w +w1aubvoq +w1ll1ams +w1w2w3w4 +w2e3r4t5 +w3wjnhek +w45bj9upkz +w5tn36alfw +w5txn36alfw +w66yrybgra +w8agc47kla +w9998999 +wachtwoord +wachtwoord1 +waffenss +waffles1 +waffles2 +waheguru +waheguru1 +waheguruji +waiting1 +waiting4u +wakaflocka +wakawaka +wakeboard +wakeboard1 +wakefield +wal-mart +walalang +waldemar +waldiw82 +walgreens1 +walhalla +walik007 +walker01 +walker11 +walker12 +walker123 +walking1 +walkitout1 +walkman1 +wallace1 +wallace2 +wallace3 +walleye1 +wallflower +wallpaper +wallpaper1 +wallstreet +wally123 +walmart1 +walmart2 +waltdisney +walter01 +walter11 +walter12 +walter123 +walter34 +walters1 +wanda123 +wanderer +wanderers +wanderlust +wang123456 +wangjian +wangjing +wangwang +wangyang +wangyut2 +wanker123 +wankers1 +wannabe1 +wannadupe +wanshuai198202 +wanted123 +waqas123 +warcraft +warcraft1 +warcraft12 +warcraft123 +warcraft2 +warcraft3 +warcraft4 +wareagle +wareagle1 +warehouse +warehouse1 +warfreak +wargames +warhammer +warhammer1 +warhammer4 +warhammer40k +warlock1 +warlord1 +warlords +warning1 +warranty +warren123 +warrington +warrior1 +warrior11 +warrior12 +warrior123 +warrior13 +warrior2 +warrior3 +warrior5 +warrior7 +warriors +warriors1 +warriors12 +warriors2 +warszawa +warszawa1 +warthog1 +warwick1 +wasd1234 +wasdwasd +washburn +washburn1 +washington +washington1 +wassa12345 +wasser123 +wassermann +watanabe +watchdog +watchout +watchtower +water123 +water1234 +waterart +waterboy +waterboy1 +waterfall +waterfall1 +waterfalls +waterford +watergate +waterh20 +waterh2o +waterlily +waterloo +waterloo1 +waterman +waterman1 +watermelon +watermelon1 +waterpolo +waterpolo1 +waterski +waterwater +watever1 +watford1 +watitdo1 +watkins1 +watson831 +way2cool +wayne123 +waynerooney +wcdd93h9pq +wdtnjxtr +wealthy1 +weare138 +weareone +weather1 +webcode1 +webhompass +webkinz1 +webkinz12 +webkinz123 +webmaster +webmaster1 +webmaster123 +website1 +webster1 +webster7 +wedding07 +wedding08 +wedding09 +wedding1 +wedding65 +weddings +wednesday +wednesday1 +weed1234 +weed4life +weedhead +weedhead1 +weedman1 +weedman420 +weedweed +weedweed1 +weekend1 +weezy123 +weezybaby1 +weezyfbaby +weg63tt243 +welcome! +welcome0 +welcome01 +welcome1 +welcome10 +welcome11 +welcome12 +welcome123 +welcome1234 +welcome12345 +welcome2 +welcome22 +welcome3 +welcome4 +welcome5 +welcome6 +welcome7 +welcome8 +welcome9 +welcome99 +welcome@123 +welding1 +welkom01 +welkom123 +wellcome +wellcome1 +welldone +wellington +wellness +wendell1 +wendy123 +wenef45313 +wentworth +wentworth1 +wenyin12 +wer11111 +wer123456 +werderbremen +werewere +werewolf +werewolf1 +werilopert +weronika +weronika1 +weronika1992 +wert1234 +werthvfy +wertwert +werty123 +werty12345 +wertyuio +wertyuiop +werwerwer +wesley01 +wesley12 +wesley123 +west1234 +westbrom +westbrom1 +westbrook +westbrook1 +westcoast +westcoast1 +westend1 +western1 +westfield +westfield1 +westgate +westham1 +westham123 +westlake +westlife +westlife1 +westminster +westpoint +westport +westside +westside! +westside1 +westside10 +westside11 +westside12 +westside13 +westside14 +westside18 +westside2 +westside21 +westside23 +westside3 +westside4 +westside5 +westside6 +westside69 +westside7 +westwest +westwind +westwood +westwood1 +wethebest +wethebest1 +wethepeople +wetpussy +wetpussy1 +wetpussy69 +wetwilly +wewewewe +weyersheim +weymouth +wg8e3wjf +what1234 +what3v3r +whateva1 +whatever +whatever! +whatever. +whatever0 +whatever01 +whatever08 +whatever09 +whatever1 +whatever10 +whatever11 +whatever12 +whatever123 +whatever13 +whatever14 +whatever2 +whatever21 +whatever22 +whatever23 +whatever3 +whatever4 +whatever5 +whatever6 +whatever69 +whatever7 +whatever8 +whatever9 +whatisit +whatislove +whatisthis +whatitdo +whatitdo1 +whatnow1 +whatsup1 +whatsup123 +whatsup2 +whatthe1 +whatthefuc +whatthefuck +whatthehel +whatthehell +whatthezor +whatwhat +whatwhat1 +wheelchair +wheeler1 +wheeling +whiplash +whiskers +whiskers1 +whiskey1 +whisper1 +whistler +whistler1 +white123 +whiteangel +whiteboy +whiteboy1 +whitecat +whitedog +whitefang +whitegirl +whitegirl1 +whitehead +whitehorse +whitehouse +whiteman +whiteout +whitepower +whiterabbit +whiterose +whitesnake +whitesox +whitesox05 +whitesox1 +whitetail +whitetail1 +whitetiger +whitewater +whitewolf +whitewolf1 +whitley1 +whitney1 +whitney12 +whitney2 +whitney7 +whittier +whoareyou +whoareyou1 +whocares +whocares1 +whoknows +whoknows1 +wholefoo +wholesale +whoopwhoop +whopper1 +whore123 +whorebag1 +whosyourdaddy +whyme123 +whysoserious +wibsh56kec +wicked12 +wicked123 +wicked13 +wicked69 +widescreen +widzew1910 +wiggles1 +wiktoria +wiktoria1 +wilbert1 +wildbill +wildcard +wildcat1 +wildcat2 +wildcat7 +wildcats +wildcats! +wildcats1 +wildcats10 +wildcats11 +wildcats12 +wildcats14 +wildcats2 +wildcats3 +wildcats7 +wildchild +wildchild1 +wilderness +wildfire +wildfire1 +wildflower +wildhorses +wildlife +wildlife1 +wildman1 +wildone1 +wildones +wildrose +wildthing +wildthing1 +wildwest +wildwood +wildwood1 +wilfred1 +wilfredo +wilfredo1 +wilfried +wilhelmina +wilkinson +wilkinson1 +will1234 +willard1 +william! +william. +william0 +william01 +william02 +william03 +william05 +william06 +william07 +william08 +william09 +william1 +william10 +william11 +william12 +william123 +william13 +william14 +william15 +william16 +william17 +william18 +william19 +william2 +william20 +william21 +william22 +william23 +william24 +william25 +william2631 +william3 +william4 +william5 +william6 +william69 +william7 +william77 +william8 +william88 +william9 +william99 +williams +williams1 +williams11 +williams12 +williams2 +williams3 +williamson +willie01 +willie11 +willie12 +willie123 +willie22 +willow01 +willow11 +willow12 +willow123 +willow13 +willpower +willsmith +willsmith1 +willwill +willy123 +willywonka +wilmington +wilson01 +wilson10 +wilson11 +wilson12 +wilson123 +wilson13 +wilson21 +wilson22 +wilson23 +wimbledon +winchester +windmill +windmill1 +window12 +window123 +windows1 +windows12 +windows123 +windows2 +windows2000 +windows7 +windows8 +windows95 +windows98 +windowsvista +windowsxp +windowsxp1 +windsong +windsor1 +windstar +windsurf +winfield +winfixer +wingchun +wingman1 +wingnut1 +wingwing +wingzero +wingzero1 +winifred +winner01 +winner11 +winner12 +winner123 +winners1 +winnie01 +winnie11 +winnie12 +winnie123 +winniepooh +winniethep +winniethepooh +winnipeg +winnipeg2612 +winslow1 +winston01 +winston1 +winston12 +winston123 +winston2 +winston3 +winston7 +winter00 +winter01 +winter02 +winter04 +winter05 +winter06 +winter07 +winter08 +winter09 +winter10 +winter11 +winter12 +winter123 +winter13 +winter2008 +winter2009 +winter2010 +winter2011 +winter21 +winter22 +winter23 +winter77 +winter98 +winter99 +winters1 +winthrop +winwinwin +winxclub +wipro@123 +wireless +wireless1 +wisconsin +wisconsin1 +wisdom12 +wisdom123 +wiseman1 +wishbone +wishbone1 +wishmaster +wisteria +witchcraft +withlove +withoutu +witspass1234 +wizard01 +wizard101 +wizard12 +wizard123 +wizard13 +wizards1 +wizkhalifa +wkgmkjh623 +wkgmmjh623 +wladimir +wmtmufc1 +wo123456 +woailaopo +woaimama +woaini123 +woaini1314 +woaini520 +woaini521 +woainima +woaiwojia +woaiwoziji +wobuzhidao +wocao5201314 +wocaonima +wodemima +woe45byzry +wojiushiwo +wolf1234 +wolfenstein +wolfgang +wolfgang1 +wolfman1 +wolfpack +wolfpack1 +wolfteam +wolfwolf +wolverin +wolverine +wolverine1 +wolverine2 +wolverine3 +wolverine7 +wolverines +wolves11 +wolves12 +wolves123 +womanizer +wonder123 +wonderboy +wonderboy1 +wonderful +wonderful1 +wonderful2 +wonderfull +wondergirl +wonderland +wonderman2 +wonderwall +wonderwoma +wonderwoman +woodbine +woodbury +woodchuck +woodduck +woodland +woodland1 +woodlands +woodlawn +woodman1 +woodpecker +woodrow1 +woodside +woodside1 +woodstock +woodstock1 +woodward +woodward1 +woodwind +woodwork +woody123 +woofwoof +woofwoof1 +woopwoop +wootwoot +wootwoot1 +worcester +wordlife +wordlife1 +wordpass +wordpass1 +wordpass12 +wordpass2 +worinima +work1234 +workhard +working1 +workout1 +workshop +worksucks +workwork +world123 +worldcup +worldofwarcraft +worldpeace +worldwar +worldwar2 +worldwide +worldwide1 +wormwood +worship1 +woshishei +woshishei319 +woshishen +woshishui +woshiyazi +woshizhu +wow12345 +wpcakir264 +wqer1314 +wrangler +wrangler1 +wrasloco11 +wrestle1 +wrestlemania +wrestler +wrestler1 +wrestling +wrestling1 +wrestling2 +wrestling3 +wrestling7 +wrigley1 +wrinkle1 +wrinkles +wrinkles1 +ws123456 +wsadwsad +wsbe279qsg +wsky0o0o0o +wsx123456 +wsydcig761 +wtpmjgda +wubin007 +wulandari +wumeiyun123 +wunderbar +wutang36 +wutangclan +ww111111 +ww123456 +ww651118 +wwe12345 +wwe4life +www.ivan-18 +www12345 +www123456 +wwwaaabbb +wwwamador91 +wwwksenechkawww +wwwooo1234 +wwwwwww1 +wwwwwwww +wwwwwwwww +wwwwwwwwww +wxcvbn123 +wy1000000 +wyatt123 +wybe4591 +wyoming1 +wz362308 +wzf2sme498 +wzq8xcfxqm +wzr8ycfxrm +x1234567 +x123456789 +x123456x +x15piq8snj +x1x2x3x4 +x3luym2mmj +x4ivyga51f +x60zay0468 +x72jhhu3za +x7bktntlez +x7vs8mxg +x870624x +x8axspumez +x8coqx1f1zh +x99qomx561 +xalitova1988 +xantria10315 +xavier01 +xavier04 +xavier05 +xavier06 +xavier07 +xavier08 +xavier09 +xavier10 +xavier11 +xavier12 +xavier123 +xavier13 +xavier14 +xavier21 +xavier22 +xavier23 +xblhintb9w +xbox3600 +xboxlive +xboxlive1 +xcountry +xdf65b6666 +xdl65b6666 +xdqwerty +xenogears +xenosaga1234 +xexeylhf +xfactor1 +xfk3bxezqj +xfx3ayfjrk +xgx39zgisl +xh246aigun +xh247ahgum +xh248zhhtm +xhh787qpcd +xi345bifvn +xi345bjfvp +xiang123456 +xiaofeng +xiaolong +xiaoqiang +xiaoxiao +xige5516726 +xingxing +xiomara1 +xj453cxdxq +xjcri66kfd +xk45xdxcyr +xk55xdxcyr +xkhnmki633 +xlf65b6666 +xlsl9963 +xm55xexbzs +xpeygeh934 +xpr4bf29ux +xpressmusic +xred4654 +xsplit123 +xsw21qaz +xsw23edc +xsw2zaq1 +xt97794xt +xthtgfirf +xtkjdtrgfer +xtseo2011tdx +xuanxuan +xup6xup6 +xx123456 +xxkk01234 +xxx12345 +xxx123xxx +xxxx1234 +xxxxxxx1 +xxxxxxxx +xxxxxxxxx +xxxxxxxxxx +xxxxxxxxxxxx +xyj44pe3gv +xyq7xcewqk +xyxy159753 +xyz12345 +xzsawq21 +y123456789 +y3p32ftrqj +y6p67ftrqj +y6p68ftrqj +ya623349 +ya_nochka86 +yaalimadad +yagjecc816 +yagjecc826 +yahnox75 +yahoo.com +yahoo.com1 +yahoo100 +yahoo123 +yahoo1234 +yahoo12345 +yahoocom +yahoomail +yahoomail1 +yahooyahoo +yamaha01 +yamaha11 +yamaha12 +yamaha123 +yamaha125 +yamaha13 +yamaha135 +yamaha22 +yamaha250 +yamaha450 +yamaha46 +yamaha69 +yamaha85 +yamahar1 +yamahar6 +yamakasi +yamamoto +yamazaki +yana.kolomoets +yanaluch +yanayana +yanchikchmoki +yandex.ru +yandi20080527 +yangyang +yankee11 +yankee12 +yankee123 +yankee13 +yankee23 +yankees! +yankees01 +yankees02 +yankees07 +yankees08 +yankees09 +yankees1 +yankees10 +yankees11 +yankees12 +yankees123 +yankees13 +yankees15 +yankees2 +yankees21 +yankees22 +yankees23 +yankees24 +yankees25 +yankees26 +yankees27 +yankees3 +yankees4 +yankees5 +yankees7 +yankees8 +yankees9 +yannick1 +yanochka +yansubina +yaoiisgrand +yaorqw12334 +yaq12wsx +yaroslav +yasmeen1 +yasmin12 +yasmin123 +yasmine1 +ybnkoia569 +ybrbnbyf +ybrjkftd +ybrjkftdbx +ybrjkftdf +ybrjkftdyf +yc6abqsfjo +ycei62p395 +ye123456 +yeahbaby +yeahbaby1 +yeahboy1 +yeahright +yeahright1 +yeahyeah +yeahyeah1 +year2000 +year2007 +year2008 +year2009 +year2010 +year3000 +yearbook +yegbpltw2012lol +yellow00 +yellow01 +yellow02 +yellow07 +yellow08 +yellow09 +yellow10 +yellow11 +yellow12 +yellow123 +yellow1234 +yellow13 +yellow14 +yellow15 +yellow16 +yellow17 +yellow18 +yellow19 +yellow20 +yellow21 +yellow22 +yellow23 +yellow24 +yellow25 +yellow27 +yellow33 +yellow44 +yellow45 +yellow55 +yellow66 +yellow69 +yellow77 +yellow88 +yellow99 +yellowbird +yellowcard +yellowdog +yellowrose +yellowstone +yemi19900911 +yes90125 +yesenia1 +yessenia +yesterday +yesterday1 +yeswecan +yesyesyes +yeuemnhieu +yfcn.irf +yfcnfcmz +yfcntymrf +yfcntyrf +yfcnz123 +yfcnzyfcnz +yfdbufnjh +yfdbufnjh10305070 +yfdbufnjh63 +yfdctulf +yfgjktjy +yfltymrf +yfnfitymrf +yggdrasil +yggdrasil4 +yh3hnr4869 +yingyang +yingyang1 +yingying +yinyang1 +yjdbrjdf +yjdsqgfhjkm +yjdsqujl +yjwfn73j +ykdpj67mgd +ykvpoia569 +ylik1911 +yluy1981 +ymhpnmj733 +yniqnmk733 +yo123456 +yodayoda +yogibear +yogibear1 +yogyakarta +yokohama +yolanda1 +yomama12 +yomama123 +yomamma1 +yomomma! +yomomma1 +yomomma2 +yondaime +yonkers1 +yorkshire +yorkshire1 +yorktown +yosemite +yosemite1 +yoshi123 +youaifa569 +youandme +youandme1 +youandme2 +youaregay1 +youaremine +youbye123 +youbye1231 +youknow1 +youknowit +youkofa569 +youloveme +young123 +youngblood +youngbuck +youngbuck1 +younglove1 +youngluwe +youngman +youngmoney +yourface +yourface1 +yourgay! +yourgay1 +yourgay2 +yourlove +yourmama +yourmama1 +yourmom! +yourmom. +yourmom1 +yourmom11 +yourmom12 +yourmom123 +yourmom13 +yourmom2 +yourmom22 +yourmom3 +yourmom4 +yourmom5 +yourmom6 +yourmom69 +yourmom7 +yourmom8 +yourmomma +yourmomma1 +yourmother +yourmum1 +yourname +yourname1 +yourock1 +yourself +yourspace1 +yousmell +yousuck! +yousuck. +yousuck1 +yousuck12 +yousuck123 +yousuck2 +yousuck3 +yousuck69 +youtube1 +youtube12 +youtube123 +youtube2 +youwish1 +youyouyou +yoville1 +yoyo1234 +yoyoyo12 +yoyoyo123 +yoyoyoyo +yoyoyoyo1 +yozgat66 +ypfu2vl856 +ytgfhjkm +ytngfhjkz +ytrewq123 +ytrewq321 +ytrhjvfyn +ytyfdb:e +ytyfdb;e +ytyfdbcnm +yu-gi-oh +yu5l97wk8q +yuantuo2012 +yuanyuan +yugioh12 +yugioh123 +yukiyuki +yulia-dubrovina +yulia_yulia_13 +yulianaz85 +yuliasha87 +yulyasik2002 +yummy123 +yungmoney1 +yunusemre +yushinazena2009 +yusuf123 +yv3bcdaq +yvonne12 +yvonne123 +yvonne90 +yx12345678 +yxcvbnm1 +yxcvbnm123 +yxp7wbewpk +yy.tt.67 +yy123456 +yygjmy1984 +yygjmy333 +yyxthh8j9k +yyyyyyyy +yyyyyyyyyy +yyz59gtp100 +yzerman19 +z0102030405 +z1122334455 +z1234567 +z12345678 +z123456789 +z123456z +z19721226 +z1x1c1v1 +z1x2c3v4 +z1x2c3v4b5 +z1x2c3v4b5n6 +z1x2c3v4b5n6m7 +z1z1z1z1 +z1z2z3z4 +z1z2z3z4z5 +z28camaro +z7777777 +z7895123 +zabelina12391 +zabelinaalena +zabihullin99 +zabirov2 +zabloczkaya2012 +zabludshaya +zabolotneva_ira +zabolotniy.a +zabolotnov1968 +zabolotnova31337 +zabor.hut2 +zaborov_t +zaborskiy80 +zabotin_sasha +zacarias +zacatecas +zacatecas1 +zacefron +zacefron1 +zacefron12 +zacefron14 +zach1234 +zachariah +zachary! +zachary01 +zachary1 +zachary10 +zachary11 +zachary12 +zachary123 +zachary13 +zachary2 +zachary3 +zachary4 +zachary5 +zachary6 +zachary7 +zachary8 +zachary9 +zachery1 +zachodnio +zack1234 +zackary1 +zackery1 +zag12wsx +zaharova +zakopane +zamorano +zanessa1 +zangetsu +zanzibar +zanzibar1 +zapatero +zaq!2wsx +zaq11qaz +zaq12345 +zaq123456 +zaq123edc +zaq123wsx +zaq12wsx +zaq12wsxcde3 +zaq1@wsx +zaq1xsw2 +zaq1xsw2cde3 +zaq1zaq1 +zaqwerty +zaqwsx12 +zaqwsx123 +zaqwsxcde +zaqwsxcderfv +zaqxsw12 +zaqxsw123 +zaqxswcde +zaqxswcde123 +zaqxswcdevfr +zaqzaqzaq +zaragoza +zaratustra +zarazara +zarina_loves +zarina_sabirova +zarina_zhasan +zarinaismailova +zarinalin87 +zarinka1111 +zarinochka_b +zarygalina +zasranec +zaxarov-1976 +zaxscdvf +zaxscdvfbg +zaynmalik +zazazaza +zbychlas +zcfvfzkexifz +zcfvfzrhfcbdfz +zcxfcnkbdf +zebra123 +zelda123 +zenit-talnah +zeppelin +zeppelin1 +zepplin1 +zero0000 +zero1234 +zerocool +zerocool1 +zerozero +zesh1412 +zezina80 +zgmfx10a +zgmfx20a +zh8o9ly3gi +zhang123 +zhanghao +zhangjian +zhangjie +zhanglei +zhangqiang +zhangwei +zhangyan +zhd741220 +zhenyu2012 +zhimakaimen +zhjckfdf +zhongguo +zhou1980 +zidane10 +zigazaga +ziggy123 +zildjian +zildjian1 +zimbabwe +zimbabwe1 +zimmer483 +zimmerman +zimmerman1 +zimmermann33 +zinedine +ziomek123 +zippy123 +zk.,k.nt,z +zkmxbrbcbkf +zlenk77nge +zmf1704c +zmx870919123 +zniqpnk733 +znirpnl744 +znt,zk.,k. +zoey1234 +zoidberg +zolotarev08 +zolushka +zombie12 +zombie123 +zombie13 +zombie666 +zombie69 +zombies1 +zonnebloem +zoolander +zoolander1 +zoom1234 +zoomzoom +zoomzoom1 +zoosk.com +zoosk123 +zoosk2010 +zooyork1 +zorro123 +zpaqrt2963 +zrjdktdf +zrszd9p238 +zse45rdx +zse4xdr5 +zsxdcfvg +zucchero +zuewamarija +zv_!80lo +zw5a1u5evw +zwilling +zwjbvhy184 +zwn6vbdvpj +zx123456 +zx12cv34 +zxasqw12 +zxasqw123 +zxc123123 +zxc12345 +zxc123456 +zxc123456789 +zxc123zxc +zxc841219 +zxcasd123 +zxcasdqwe +zxcasdqwe1 +zxcasdqwe123 +zxcdsaqwe +zxcqwe123 +zxcv0987 +zxcv1234 +zxcv12345 +zxcv123456 +zxcv4321 +zxcvasdf +zxcvb123 +zxcvb1234 +zxcvb12345 +zxcvbasdfg +zxcvbbvcxz +zxcvbn12 +zxcvbn123 +zxcvbn123456 +zxcvbn2m +zxcvbnm, +zxcvbnm,. +zxcvbnm,./ +zxcvbnm. +zxcvbnm0 +zxcvbnm1 +zxcvbnm11 +zxcvbnm12 +zxcvbnm123 +zxcvbnm1234 +zxcvbnm12345 +zxcvbnm123456 +zxcvbnm1234567 +zxcvbnm123456789 +zxcvbnm2 +zxcvbnm3 +zxcvbnm5 +zxcvbnm7 +zxcvbnm8 +zxcvbnm9 +zxcvbnm: +zxcvbnma +zxcvbnmasd +zxcvbnmasdfghjkl +zxcvbnmm +zxcvbnmmnbvcxz +zxcvbnmzxcvbnm +zxcvfdsa +zxcvvcxz +zxcvzxcv +zxczxc123 +zxczxczxc +zxzxzxzx +zy19791201 +zz123456 +zz8807zpl +zzaaqq11 +zzs000000 +zzxxccvv +zzzxxxccc +zzzz1111 +zzzzxxxx +zzzzzzz1 +zzzzzzzz +zzzzzzzzz +zzzzzzzzzx +zzzzzzzzzz +любовь +наташа +пароль +привет +максим +марина +йцукен +александр +алексей +анастасия +андрей +вероника +виктория +вконтакте +дмитрий +екатерина +иришка +йфяцыч +йфяцычувс +йцукен +йцукенг +йцукенгшщз +йцукенгшщзхъ +какашка +карина +катюша +кирилл +контакт +котенок +красотка +кристина +леночка +любимая +любимый +люблю +люблютебя +любовь +максим +максимка +малышка +мамочка +мамуля +марина +маруся +надежда +наташа +ненавижу +никита +оксана +пароль +полина +привет +приветик +просто +пїЅпїЅпїЅпїЅпїЅпїЅ@mail.ru +ранетки +ромашка +руслан +сашенька +светлана +сергей +солнце +солнышко +счастье +татьяна +телефон +ялюблютебя +ятебялюблю +ячсмит +ячсмить diff --git a/internal/pkg/crypt/validation.go b/internal/pkg/crypt/validation.go index c7ffbb3d6..9516628e2 100644 --- a/internal/pkg/crypt/validation.go +++ b/internal/pkg/crypt/validation.go @@ -1,7 +1,12 @@ package crypt import ( + "bufio" + "bytes" + _ "embed" "regexp" + "strings" + "sync" ) var uuidRegex = regexp.MustCompile(`^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$`) @@ -14,7 +19,75 @@ func IsValidHexColor(s string) bool { return regexp.MustCompile(`^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$`).MatchString(s) } +// PasswordRejection says why a password was refused, so the caller can tell the +// person which rule they hit rather than restating the length rule at someone +// whose password is long but breached. +type PasswordRejection int + +const ( + PasswordOK PasswordRejection = iota + PasswordTooShort + PasswordTooLong + PasswordBreached +) + +const ( + passwordMinLength = 8 + passwordMaxLength = 128 +) + +// breachedList is the NCSC top-100k breached passwords, reduced to the entries +// long enough to pass the length rule. See the README next to it. +// +//go:embed passwords/breached.txt +var breachedList []byte + +var ( + breachedOnce sync.Once + breachedSet map[string]struct{} +) + +// loadBreached builds the lookup set on first use. Parsing ~46k lines costs a +// few milliseconds and only happens on the first password anyone sets. +func loadBreached() { + breachedSet = make(map[string]struct{}, 48000) + sc := bufio.NewScanner(bytes.NewReader(breachedList)) + sc.Buffer(make([]byte, 0, 1024), 1024) + for sc.Scan() { + if line := strings.TrimSpace(sc.Text()); line != "" { + breachedSet[line] = struct{}{} + } + } +} + +// IsBreachedPassword reports whether the password appears in the embedded list +// of commonly breached passwords. The comparison is case-insensitive, because +// capitalising the first letter of a breached password does not make it a +// different password to anyone running a cracking list. +func IsBreachedPassword(password string) bool { + breachedOnce.Do(loadBreached) + _, found := breachedSet[strings.ToLower(password)] + return found +} + +// CheckPassword applies the password rules: a length band, and a prohibition on +// passwords known to have been breached (NIST SP 800-63B 5.1.1.2, which asks +// for exactly this rather than composition rules). +func CheckPassword(password string) PasswordRejection { + switch n := len([]rune(password)); { + case n < passwordMinLength: + return PasswordTooShort + case n > passwordMaxLength: + return PasswordTooLong + } + if IsBreachedPassword(password) { + return PasswordBreached + } + return PasswordOK +} + +// ValidatePassword is the boolean form of CheckPassword, kept for callers that +// only need to know whether the password is acceptable. func ValidatePassword(password string) bool { - n := len([]rune(password)) - return n >= 8 && n <= 128 + return CheckPassword(password) == PasswordOK } diff --git a/internal/pkg/crypt/validation_test.go b/internal/pkg/crypt/validation_test.go index bee086de6..4edbc8117 100644 --- a/internal/pkg/crypt/validation_test.go +++ b/internal/pkg/crypt/validation_test.go @@ -2,66 +2,45 @@ package crypt import "testing" -func TestIsValidUUID(t *testing.T) { - tests := []struct { - input string - want bool +func TestCheckPassword(t *testing.T) { + cases := []struct { + name string + password string + want PasswordRejection }{ - // Valid UUIDs (v1, v4, etc.) - {"550e8400-e29b-41d4-a716-446655440000", true}, - {"123e4567-e89b-12d3-a456-426614174000", true}, - - // Invalid: wrong format or missing parts - {"550e8400e29b41d4a716446655440000", false}, // missing dashes - {"550e8400-e29b-41d4-a716-44665544000", false}, // too short - {"550e8400-e29b-41d4-a716-4466554400000", false}, // too long - {"zzze8400-e29b-41d4-a716-446655440000", false}, // invalid hex - {"", false}, // empty string - {"not-a-uuid", false}, // random string + {"too short", "Sh0rt!", PasswordTooShort}, + {"exactly at the floor", "Xj7!qm2Z", PasswordOK}, + {"a long passphrase", "correct horse battery staple", PasswordOK}, + {"breached", "password123", PasswordBreached}, + {"breached, recased", "PassWord123", PasswordBreached}, + {"breached, all caps", "QWERTY123", PasswordBreached}, + {"over the ceiling", string(make([]byte, 129)), PasswordTooLong}, } - - for _, tt := range tests { - got := IsValidUUID(tt.input) - if got != tt.want { - t.Errorf("IsValidUUID(%q) = %v, want %v", tt.input, got, tt.want) - } + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + if got := CheckPassword(tc.password); got != tc.want { + t.Fatalf("CheckPassword(%q) = %v, want %v", tc.password, got, tc.want) + } + }) } } -func TestIsValidHexColor(t *testing.T) { - tests := []struct { - input string - want bool - }{ - // ✅ Valid short hex codes - {"#000", true}, - {"#fff", true}, - {"#abc", true}, - {"#ABC", true}, - - // ✅ Valid long hex codes - {"#000000", true}, - {"#FFFFFF", true}, - {"#123456", true}, - {"#AaBbCc", true}, - - // ❌ Invalid ones - {"000000", false}, - {"#12", false}, - {"#1234", false}, - {"#12345", false}, - {"#1234567", false}, - {"#ZZZ", false}, - {"#12G", false}, - {"#123456789", false}, - {"#", false}, - {"", false}, +// The denylist is only worth carrying if it is actually populated: an empty or +// truncated data file would make every password acceptable and nothing else +// would notice. +func TestBreachedListIsLoaded(t *testing.T) { + breachedOnce.Do(loadBreached) + if len(breachedSet) < 40000 { + t.Fatalf("breached list holds %d entries, expected the full NCSC set", len(breachedSet)) } - - for _, tt := range tests { - got := IsValidHexColor(tt.input) - if got != tt.want { - t.Errorf("IsValidHexColor(%q) = %v, want %v", tt.input, got, tt.want) + for _, p := range []string{"password123", "qwerty123", "letmein1"} { + if !IsBreachedPassword(p) { + t.Errorf("%q should be in the breached list", p) } } + // A password nobody has leaked must not be refused, or the control is just + // an outage. + if IsBreachedPassword("Xj7!qm2Zp9wLv4-unique") { + t.Error("a random passphrase must not be treated as breached") + } } diff --git a/internal/pkg/emailverify/emailverify.go b/internal/pkg/emailverify/emailverify.go index 9cfae7bc2..fead3bed9 100644 --- a/internal/pkg/emailverify/emailverify.go +++ b/internal/pkg/emailverify/emailverify.go @@ -44,6 +44,7 @@ import ( "strings" "time" + "github.com/warmbly/warmbly/internal/pkg/safehttp" "github.com/warmbly/warmbly/internal/pkg/signuprisk" ) @@ -171,6 +172,11 @@ type SMTPVerifier struct { // smtpPort is always "25" in production (MX hosts listen nowhere else); // it exists so tests can point probe() at a local server. smtpPort string + // allowPrivateMX lets probe() dial a non-public address. False everywhere + // but in tests, which run their fake MX on loopback. In production an MX + // that resolves to a private or link-local address is a user-controlled DNS + // record pointing at our own network, which is the whole SSRF shape. + allowPrivateMX bool // domains remembers per-domain facts (no MX, catch-all, undisclosing // provider) so a 50k list at 2k domains costs 2k probes, not 50k. domains *domainCache @@ -410,8 +416,37 @@ type probeResult struct { // that rejects our HELO / sender / IP / relay policy is unknown // 4xx / timeout/ dial error -> unknown (greylist, blocked :25, transient) func (v *SMTPVerifier) probe(ctx context.Context, host, localpart, domain string) probeResult { + // The host is an MX name resolved from an address the user typed, so where + // it points is the user's choice. Publishing `MX 169.254.169.254` or + // `MX 127.0.0.1` for a domain you control turns "verify this address" into + // a connect to the instance's own network. Resolve first, refuse anything + // that is not a public address, then dial the address that was checked so + // a second lookup cannot answer differently. + ips, rerr := net.DefaultResolver.LookupIP(ctx, "ip", host) + if rerr != nil || len(ips) == 0 { + return probeResult{outcome: probeUnknown, sessionFailed: true, reason: "mx lookup failed"} + } + if !v.allowPrivateMX { + for _, ip := range ips { + if safehttp.IsBlockedIP(ip) { + return probeResult{outcome: probeUnknown, sessionFailed: true, reason: "mx resolves to a non-public address"} + } + } + } + + // Try each address rather than only the first. LookupIP returns A and AAAA + // mixed, so on an IPv4-only host a domain whose first record is AAAA would + // always report unknown, which is a silent accuracy loss rather than an + // error anyone would notice. dialer := net.Dialer{Timeout: v.cfg.DialTimeout} - conn, err := dialer.DialContext(ctx, "tcp", net.JoinHostPort(host, v.smtpPort)) + var conn net.Conn + var err error + for _, ip := range ips { + conn, err = dialer.DialContext(ctx, "tcp", net.JoinHostPort(ip.String(), v.smtpPort)) + if err == nil { + break + } + } if err != nil { // Most commonly: outbound :25 blocked by the cloud provider, or the MX is // firewalled/tarpitting. Either way we cannot conclude invalid. diff --git a/internal/pkg/emailverify/probe_smtp_test.go b/internal/pkg/emailverify/probe_smtp_test.go index 67ad0d709..aa8a613b4 100644 --- a/internal/pkg/emailverify/probe_smtp_test.go +++ b/internal/pkg/emailverify/probe_smtp_test.go @@ -92,6 +92,8 @@ func testVerifier(t *testing.T, cfg Config, port string) *SMTPVerifier { t.Helper() v := New(cfg) v.smtpPort = port + // The fake MX listens on loopback, which the production guard refuses. + v.allowPrivateMX = true return v } diff --git a/internal/repository/pg_admin.go b/internal/repository/pg_admin.go index b8b677d79..059ce9e09 100644 --- a/internal/repository/pg_admin.go +++ b/internal/repository/pg_admin.go @@ -27,6 +27,9 @@ type AdminRepository interface { GetUserDetail(ctx context.Context, userID uuid.UUID) (*models.AdminUserDetail, error) GetUserPreview(ctx context.Context, userID uuid.UUID) (*models.AdminUserPreview, error) UpdateUserAdminPermissions(ctx context.Context, userID uuid.UUID, permissions uint32, grantedBy uuid.UUID) error + // CountSuperAdmins reports how many users hold every live admin + // permission, so the last one cannot be revoked through the API. + CountSuperAdmins(ctx context.Context) (int, error) BanUser(ctx context.Context, userID, bannedBy uuid.UUID, reason string, scope uint32) error UnbanUser(ctx context.Context, userID, unbannedBy uuid.UUID, reason string) error GetUserBans(ctx context.Context, userID uuid.UUID) ([]models.UserBan, error) @@ -2152,3 +2155,12 @@ func itoa(i int) string { func joinStrings(strs []string, sep string) string { return strings.Join(strs, sep) } + +// CountSuperAdmins counts users holding the full live admin mask. +func (r *adminRepository) CountSuperAdmins(ctx context.Context) (int, error) { + var n int + err := r.db.QueryRow(ctx, + `SELECT count(*) FROM users WHERE (admin_permissions & $1) = $1`, + uint32(models.LiveAdminPermissions)).Scan(&n) + return n, err +} diff --git a/internal/repository/pg_advanced_outreach.go b/internal/repository/pg_advanced_outreach.go index c9768df68..93aa4e022 100644 --- a/internal/repository/pg_advanced_outreach.go +++ b/internal/repository/pg_advanced_outreach.go @@ -570,7 +570,7 @@ func (r *advancedOutreachRepository) CreateDeliverabilityEvent(ctx context.Conte recipient_email, reason, idempotency_key, metadata, created_at ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, NOW()) - ON CONFLICT (idempotency_key) DO NOTHING + ON CONFLICT (organization_id, idempotency_key) DO NOTHING ` _, err = r.db.Exec(ctx, query, event.OrganizationID, diff --git a/internal/repository/pg_campaign.go b/internal/repository/pg_campaign.go index 8d9841f23..a28d36a11 100644 --- a/internal/repository/pg_campaign.go +++ b/internal/repository/pg_campaign.go @@ -17,6 +17,7 @@ import ( "github.com/warmbly/warmbly/internal/infrastructure/db" "github.com/warmbly/warmbly/internal/models" "github.com/warmbly/warmbly/internal/pkg/mailhtml" + "github.com/warmbly/warmbly/internal/utils" "github.com/warmbly/warmbly/internal/utils/paging" "github.com/warmbly/warmbly/internal/utils/validate" ) @@ -1109,8 +1110,16 @@ func (r *campaignRepository) Update(ctx context.Context, orgID, campaignID strin argPos++ } if data.ContactOrderField != nil { + // This is the order field that reaches an ORDER BY expression, so it is + // validated on the way in like the two allowlisted ones above. It is a + // custom-field key, so it answers to the same rule as every other + // custom-field key in the product. + field := utils.NormalizeJSONKey(*data.ContactOrderField) + if field != "" && !utils.IsValidJSONKey(field) { + return nil, errx.ErrInvalid + } setClauses = append(setClauses, fmt.Sprintf("%s = $%d", "contact_order_field", argPos)) - args = append(args, *data.ContactOrderField) + args = append(args, field) argPos++ } diff --git a/internal/repository/pg_campaign_progress.go b/internal/repository/pg_campaign_progress.go index f19f48a58..4ef0ea3fd 100644 --- a/internal/repository/pg_campaign_progress.go +++ b/internal/repository/pg_campaign_progress.go @@ -1307,6 +1307,14 @@ func (r *campaignProgressRepository) FindRoutedPairs(ctx context.Context, campai } // 2. Ordered candidate contacts + their last-sent step (with engagement) + sent set. + // + // args carries the query's bound parameters. The custom-field key is one of + // them: it is the only part of this ORDER BY that comes from a customer, so + // it is bound rather than written into the SQL text. This query runs on the + // scheduler rather than in a request, which is the worst place to learn that + // an identifier was not what it claimed. + args := []any{campaignID, config.CampaignSendMaxAttempts} + var contactOrder string switch orderBy { case "email": @@ -1315,7 +1323,8 @@ func (r *campaignProgressRepository) FindRoutedPairs(ctx context.Context, campai contactOrder = "c.first_name, c.last_name" case "custom_field": if orderField != "" { - contactOrder = "c.custom_fields->>'" + orderField + "'" + args = append(args, orderField) + contactOrder = fmt.Sprintf("c.custom_fields->>$%d", len(args)) } else { contactOrder = "c.created_at" } @@ -1385,7 +1394,7 @@ func (r *campaignProgressRepository) FindRoutedPairs(ctx context.Context, campai ORDER BY ` + orderPrefix + contactOrder + ` ` + dir + ` ` - rows, err := r.db.Query(ctx, query, campaignID, config.CampaignSendMaxAttempts) + rows, err := r.db.Query(ctx, query, args...) if err != nil { return nil, nil, false, err } diff --git a/internal/repository/pg_contact.go b/internal/repository/pg_contact.go index c49474581..87ec5c8ee 100644 --- a/internal/repository/pg_contact.go +++ b/internal/repository/pg_contact.go @@ -95,7 +95,7 @@ type ContactRepository interface { // GetDetail supports user-only reads with nil orgID and skips organization-scoped joins. GetDetail(ctx context.Context, userID uuid.UUID, orgID *uuid.UUID, contactID uuid.UUID) (*models.ContactDetail, *errx.Error) - ListSentEmails(ctx context.Context, userID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) + ListSentEmails(ctx context.Context, orgID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) // ListTimeline is always scoped to the selected organization. ListTimeline(ctx context.Context, orgID, contactID uuid.UUID, limit int, cursor *models.ContactTimelineKey) (*models.ContactTimelineResult, *errx.Error) // ListCampaignStates returns the contact's campaigns with their flow, @@ -3309,20 +3309,22 @@ func (r *contactRepository) GetDetail(ctx context.Context, userID uuid.UUID, org // pagination on (created_at, task_id) so we can scroll through the // full history without blowing up offset. // -// We deliberately scope by the contact's owning user via the -// campaign join — this keeps multi-tenant safety even though the -// tasks table itself has no user_id column. +// We deliberately scope by the owning organization via the campaign join — +// this keeps multi-tenant safety even though the tasks table itself has no +// organization_id column. It was the campaign's user_id until the rest of the +// contact 360 moved to org scope, which both showed one member their own sends +// only and, for someone in two workspaces, mixed the other one's in. // // opened_at is a person's open, as it is in campaign analytics and the // contact's engagement summary: a fetch by a mail client's prefetch or a // security gateway is reported separately as machine_opened_at, so this list // never claims a recipient read mail they never opened (issue #392). -func (r *contactRepository) ListSentEmails(ctx context.Context, userID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) { +func (r *contactRepository) ListSentEmails(ctx context.Context, orgID, contactID uuid.UUID, limit int, beforeSentAt *time.Time, beforeTaskID *uuid.UUID) (*models.ContactSentEmailsResult, *errx.Error) { if limit <= 0 || limit > 200 { limit = 50 } - args := []any{userID, contactID} + args := []any{orgID, contactID} cursorClause := "" if beforeSentAt != nil && beforeTaskID != nil { cursorClause = "AND (t.created_at, t.id) < ($3, $4)" @@ -3351,7 +3353,7 @@ func (r *contactRepository) ListSentEmails(ctx context.Context, userID, contactI AND ccp.contact_id = ct.contact_id AND ccp.sequence_id = ct.sequence_id WHERE ct.contact_id = $2 - AND cam.user_id = $1 + AND cam.organization_id = $1 %s ORDER BY t.created_at DESC, t.id DESC LIMIT $%d diff --git a/internal/repository/pg_crm.go b/internal/repository/pg_crm.go index 67b7505d3..ba77495b8 100644 --- a/internal/repository/pg_crm.go +++ b/internal/repository/pg_crm.go @@ -79,6 +79,10 @@ func NewCRMRepository(db *pgxpool.Pool) CRMRepository { // ===================== func (r *crmRepository) CreateNote(ctx context.Context, orgID, contactID, userID uuid.UUID, content string) (*models.ContactNote, error) { + if err := r.verifyRefs(ctx, orgID, crmRefs{ContactID: &contactID}); err != nil { + return nil, err + } + query := ` INSERT INTO contact_notes (contact_id, organization_id, user_id, content) VALUES ($1, $2, $3, $4) @@ -330,7 +334,7 @@ func (r *crmRepository) GetPipeline(ctx context.Context, orgID, pipelineID uuid. SELECT ps.id, ps.pipeline_id, ps.name, ps.color, ps.position, ps.created_at, ps.updated_at, COUNT(d.id) AS deal_count FROM pipeline_stages ps - LEFT JOIN deals d ON d.stage_id = ps.id AND d.status = 'open' + LEFT JOIN deals d ON d.stage_id = ps.id AND d.pipeline_id = ps.pipeline_id AND d.status = 'open' WHERE ps.pipeline_id = $1 GROUP BY ps.id ORDER BY ps.position ASC @@ -405,7 +409,7 @@ func (r *crmRepository) ListPipelines(ctx context.Context, orgID uuid.UUID) ([]m SELECT ps.id, ps.pipeline_id, ps.name, ps.color, ps.position, ps.created_at, ps.updated_at, COUNT(d.id) AS deal_count FROM pipeline_stages ps - LEFT JOIN deals d ON d.stage_id = ps.id AND d.status = 'open' + LEFT JOIN deals d ON d.stage_id = ps.id AND d.pipeline_id = ps.pipeline_id AND d.status = 'open' WHERE ps.pipeline_id = ANY($1) GROUP BY ps.id ORDER BY ps.position ASC @@ -554,11 +558,70 @@ func (r *crmRepository) DeleteStage(ctx context.Context, orgID, stageID uuid.UUI return nil } +// crmRefs names the foreign rows a deal, task or note can point at. Every one +// of them arrives in the request body, and the read path joins them back onto +// the row and returns their fields, so each has to be proven to live in the +// caller's organization before it is stored. The joins carry the tenant +// predicate as well: a stored reference and a read of it are two separate +// chances to get this wrong. +type crmRefs struct { + PipelineID *uuid.UUID + StageID *uuid.UUID + ContactID *uuid.UUID + DealID *uuid.UUID + AssignedTo *uuid.UUID + AssignedTeamID *uuid.UUID + CampaignID *uuid.UUID + SourceMailboxID *uuid.UUID +} + +// verifyRefs answers ErrNotFound for a reference outside the organization, so a +// probe cannot tell an id that exists elsewhere from one that exists nowhere. +func (r *crmRepository) verifyRefs(ctx context.Context, orgID uuid.UUID, refs crmRefs) error { + checks := []struct { + id *uuid.UUID + sql string + }{ + {refs.PipelineID, `SELECT EXISTS(SELECT 1 FROM pipelines WHERE id = $1 AND organization_id = $2)`}, + {refs.StageID, `SELECT EXISTS(SELECT 1 FROM pipeline_stages ps JOIN pipelines p ON p.id = ps.pipeline_id WHERE ps.id = $1 AND p.organization_id = $2)`}, + {refs.ContactID, `SELECT EXISTS(SELECT 1 FROM contacts WHERE id = $1 AND organization_id = $2)`}, + {refs.DealID, `SELECT EXISTS(SELECT 1 FROM deals WHERE id = $1 AND organization_id = $2)`}, + {refs.AssignedTo, `SELECT EXISTS(SELECT 1 FROM organization_members WHERE user_id = $1 AND organization_id = $2)`}, + {refs.AssignedTeamID, `SELECT EXISTS(SELECT 1 FROM teams WHERE id = $1 AND organization_id = $2)`}, + {refs.CampaignID, `SELECT EXISTS(SELECT 1 FROM campaigns WHERE id = $1 AND organization_id = $2)`}, + {refs.SourceMailboxID, `SELECT EXISTS(SELECT 1 FROM email_accounts WHERE id = $1 AND organization_id = $2)`}, + } + for _, c := range checks { + if c.id == nil || *c.id == uuid.Nil { + continue + } + var ok bool + if err := r.db.QueryRow(ctx, c.sql, *c.id, orgID).Scan(&ok); err != nil { + return err + } + if !ok { + return errx.ErrNotFound + } + } + return nil +} + // ===================== // Deals // ===================== func (r *crmRepository) CreateDeal(ctx context.Context, orgID uuid.UUID, data *models.CreateDeal) (*models.Deal, error) { + if err := r.verifyRefs(ctx, orgID, crmRefs{ + PipelineID: &data.PipelineID, + StageID: &data.StageID, + ContactID: data.ContactID, + AssignedTo: data.AssignedTo, + CampaignID: data.CampaignID, + SourceMailboxID: data.SourceMailboxID, + }); err != nil { + return nil, err + } + currency := data.Currency if currency == "" { currency = "USD" @@ -682,6 +745,14 @@ func (r *crmRepository) ListDeals(ctx context.Context, orgID uuid.UUID, pipeline } func (r *crmRepository) UpdateDeal(ctx context.Context, orgID, dealID uuid.UUID, data *models.UpdateDeal) (*models.Deal, error) { + if err := r.verifyRefs(ctx, orgID, crmRefs{ + StageID: data.StageID, + ContactID: data.ContactID, + AssignedTo: data.AssignedTo, + }); err != nil { + return nil, err + } + setClauses := []string{} args := []any{orgID, dealID} argPos := 3 @@ -927,9 +998,9 @@ func (r *crmRepository) SearchDeals(ctx context.Context, orgID uuid.UUID, filter ps.name, ps.color, ps.position, cam.name FROM deals d - LEFT JOIN contacts co ON co.id = d.contact_id - LEFT JOIN pipeline_stages ps ON ps.id = d.stage_id - LEFT JOIN campaigns cam ON cam.id = d.campaign_id + LEFT JOIN contacts co ON co.id = d.contact_id AND co.organization_id = d.organization_id + LEFT JOIN pipeline_stages ps ON ps.id = d.stage_id AND ps.pipeline_id = d.pipeline_id + LEFT JOIN campaigns cam ON cam.id = d.campaign_id AND cam.organization_id = d.organization_id WHERE %s ORDER BY %s %s NULLS LAST, d.id DESC LIMIT $%d OFFSET $%d @@ -1069,6 +1140,15 @@ func (r *crmRepository) DealsSummary(ctx context.Context, orgID uuid.UUID, filte // ===================== func (r *crmRepository) CreateCRMTask(ctx context.Context, orgID, userID uuid.UUID, data *models.CreateCRMTask) (*models.CRMTask, error) { + if err := r.verifyRefs(ctx, orgID, crmRefs{ + ContactID: data.ContactID, + DealID: data.DealID, + AssignedTo: data.AssignedTo, + AssignedTeamID: data.AssignedTeamID, + }); err != nil { + return nil, err + } + priority := data.Priority if priority == "" { priority = "medium" @@ -1558,6 +1638,13 @@ func (r *crmRepository) BulkUpdateCRMTasks(ctx context.Context, orgID uuid.UUID, } func (r *crmRepository) UpdateCRMTask(ctx context.Context, orgID, taskID uuid.UUID, data *models.UpdateCRMTask) (*models.CRMTask, error) { + if err := r.verifyRefs(ctx, orgID, crmRefs{ + AssignedTo: data.AssignedTo, + AssignedTeamID: data.AssignedTeamID, + }); err != nil { + return nil, err + } + setClauses := []string{} args := []any{orgID, taskID} argPos := 3 diff --git a/internal/repository/pg_email.go b/internal/repository/pg_email.go index 6ee9c2837..bfa7cb148 100644 --- a/internal/repository/pg_email.go +++ b/internal/repository/pg_email.go @@ -139,10 +139,16 @@ type EmailRepository interface { // domains. It returns the mailboxes that entered the failing state on THIS // call, which is what the sweep notifies on. UpdateDomainAuthState(ctx context.Context, domain, state string, spf, dkim, dmarc bool, dmarcPolicy, reason string, checkedAt time.Time) ([]models.EmailAuthTransition, *errx.Error) + // UpdateDomainAuthStateForOrg is the same write confined to one + // organization's mailboxes. The user-facing "check again" button uses it: + // the verdict comes from public DNS so it cannot be poisoned, but one + // workspace pressing a button must not rewrite rows belonging to every + // other workspace that happens to send from the same domain. + UpdateDomainAuthStateForOrg(ctx context.Context, orgID uuid.UUID, domain, state string, spf, dkim, dmarc bool, dmarcPolicy, reason string, checkedAt time.Time) ([]models.EmailAuthTransition, *errx.Error) // Delete removes a mailbox and refunds workerLoadRefund of its worker's // load in the same transaction, so a deleted mailbox can never leave a // worker permanently charged for it. - Delete(ctx context.Context, emailAccountID string, workerLoadRefund float64) *errx.Error + Delete(ctx context.Context, userID, emailAccountID string, workerLoadRefund float64) *errx.Error NewOauthAccount(ctx context.Context, userID string, data models.NewOauthAccount) (*models.Email, *errx.Error) // NewManagedAccount creates an OAuth mailbox whose credential lives on Warmbly Cloud, so no token row is written. @@ -1300,16 +1306,28 @@ func (r *emailRepository) ListAuthCheckDue(ctx context.Context, staleBefore time } func (r *emailRepository) UpdateDomainAuthState(ctx context.Context, domain, state string, spf, dkim, dmarc bool, dmarcPolicy, reason string, checkedAt time.Time) ([]models.EmailAuthTransition, *errx.Error) { + return r.updateDomainAuthState(ctx, nil, domain, state, spf, dkim, dmarc, dmarcPolicy, reason, checkedAt) +} + +func (r *emailRepository) UpdateDomainAuthStateForOrg(ctx context.Context, orgID uuid.UUID, domain, state string, spf, dkim, dmarc bool, dmarcPolicy, reason string, checkedAt time.Time) ([]models.EmailAuthTransition, *errx.Error) { + return r.updateDomainAuthState(ctx, &orgID, domain, state, spf, dkim, dmarc, dmarcPolicy, reason, checkedAt) +} + +func (r *emailRepository) updateDomainAuthState(ctx context.Context, orgID *uuid.UUID, domain, state string, spf, dkim, dmarc bool, dmarcPolicy, reason string, checkedAt time.Time) ([]models.EmailAuthTransition, *errx.Error) { // Only 'passing' clears the grace clock; 'unknown' preserves it so a domain // cannot flap through a transient DNS error to escape the gate. // `before` keys on auth_failing_since, not auth_state, or that same flap // would re-report every mailbox on the domain as newly failing. + // $9 confines the write to one workspace when the caller named one, and is + // NULL for the background sweep, which is meant to cover every mailbox on + // the domain. query := ` WITH before AS ( SELECT id FROM email_accounts WHERE status = 'active' AND lower(split_part(email, '@', 2)) = $8 + AND ($9::uuid IS NULL OR organization_id = $9::uuid) AND auth_failing_since IS NOT NULL ), updated AS ( @@ -1323,6 +1341,7 @@ func (r *emailRepository) UpdateDomainAuthState(ctx context.Context, domain, sta ELSE auth_failing_since END WHERE status = 'active' AND lower(split_part(email, '@', 2)) = $8 + AND ($9::uuid IS NULL OR organization_id = $9::uuid) RETURNING id, email, organization_id, auth_state ) SELECT u.id, u.email, u.organization_id @@ -1340,6 +1359,7 @@ func (r *emailRepository) UpdateDomainAuthState(ctx context.Context, domain, sta reason, checkedAt, strings.ToLower(strings.TrimSpace(domain)), + orgID, } rows, err := r.DB.Query(ctx, query, params...) @@ -1385,18 +1405,16 @@ const deleteDeadlockAttempts = 3 // that side is this one. Nothing is wrong when it happens and the work is // entirely redoable, so surfacing it meant someone clicking Disconnect got an // error for an operation that would have succeeded a moment later. -func (r *emailRepository) Delete(ctx context.Context, emailAccountID string, workerLoadRefund float64) *errx.Error { +func (r *emailRepository) Delete(ctx context.Context, userID, emailAccountID string, workerLoadRefund float64) *errx.Error { for attempt := 1; ; attempt++ { - xerr, deadlocked := r.deleteOnce(ctx, emailAccountID, workerLoadRefund) + xerr, deadlocked := r.deleteOnce(ctx, userID, emailAccountID, workerLoadRefund) if !deadlocked || attempt >= deleteDeadlockAttempts { return xerr } } } -// deleteOnce deletes by id alone: the service has already proved the mailbox -// belongs to the caller's workspace, and no other scope is narrower than that. -func (r *emailRepository) deleteOnce(ctx context.Context, emailAccountID string, workerLoadRefund float64) (*errx.Error, bool) { +func (r *emailRepository) deleteOnce(ctx context.Context, userID, emailAccountID string, workerLoadRefund float64) (*errx.Error, bool) { tx, err := r.DB.Begin(ctx) if err != nil { db.CaptureError(err, "", nil, "begin") @@ -1412,11 +1430,11 @@ func (r *emailRepository) deleteOnce(ctx context.Context, emailAccountID string, UPDATE warmup_reputation_ledger l SET recorded_at = now() FROM email_accounts a - WHERE a.id = $1 + WHERE a.user_id = $1 AND a.id = $2 AND l.organization_id = a.organization_id AND l.email = lower(btrim(a.email)) ` - bumpParams := []any{emailAccountID} + bumpParams := []any{userID, emailAccountID} if _, err := tx.Exec(ctx, bump, bumpParams...); err != nil { if isDeadlock(err) { return errx.InternalError(), true @@ -1429,23 +1447,23 @@ func (r *emailRepository) deleteOnce(ctx context.Context, emailAccountID string, // sealed refresh token lives in email_accounts_oauth, which cascades away // with the mailbox, so reading it afterwards is impossible and the grant // would stay live at the provider forever. - const scope = `a.id = $1` - if _, err := EnqueueMailboxErasures(ctx, tx, scope, emailAccountID); err != nil { + const scope = `a.user_id = $1 AND a.id = $2` + if _, err := EnqueueMailboxErasures(ctx, tx, scope, userID, emailAccountID); err != nil { return errx.InternalError(), isDeadlock(err) } // The threads this mailbox holds messages in, read while they still exist. - threads, err := CollectMailboxThreadState(ctx, tx, scope, emailAccountID) + threads, err := CollectMailboxThreadState(ctx, tx, scope, userID, emailAccountID) if err != nil { return errx.InternalError(), isDeadlock(err) } query := ` DELETE FROM email_accounts - WHERE id = $1 + WHERE user_id = $1 AND id = $2 RETURNING worker_id ` - params := []any{emailAccountID} + params := []any{userID, emailAccountID} var workerID *uuid.UUID if err := tx.QueryRow(ctx, query, params...).Scan(&workerID); err != nil { diff --git a/internal/repository/pg_token.go b/internal/repository/pg_token.go index 2a97df1f1..cdec39664 100644 --- a/internal/repository/pg_token.go +++ b/internal/repository/pg_token.go @@ -14,6 +14,8 @@ import ( type TokenRepository interface { GenerateSession(ctx context.Context, tx pgx.Tx, session *models.Session) *errx.Error + // StampReauth records that this session just re-proved the account holder. + StampReauth(ctx context.Context, sessionID uuid.UUID, at time.Time) error GetSession(ctx context.Context, sessionID uuid.UUID) (*models.Session, *errx.Error) ListSessionsByUser(ctx context.Context, userID uuid.UUID) ([]*models.Session, *errx.Error) RefreshToken(ctx context.Context, sessionID uuid.UUID, oldRefreshNonce, refreshNonce, accessNonce string, issuedAt time.Time) *errx.Error @@ -47,13 +49,13 @@ func (r *tokenRepository) GenerateSession(ctx context.Context, tx pgx.Tx, sessio created_at, expires_at, last_refreshed_at, revoked_at, access_nonce, refresh_nonce, location_city, location_region, location_country, location_country_code, location_postal_code, - os_name, browser_name, auth_provider + os_name, browser_name, auth_provider, mfa_verified ) VALUES ( $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, - $15, $16, $17 + $15, $16, $17, $18 ) ` @@ -62,7 +64,7 @@ func (r *tokenRepository) GenerateSession(ctx context.Context, tx pgx.Tx, sessio session.CreatedAt, session.ExpiresAt, session.LastRefreshedAt, session.RevokedAt, session.AccessNonce, session.RefreshNonce, session.LocationCity, session.LocationRegion, session.LocationCountry, session.LocationCountryCode, session.LocationPostalCode, - session.OSName, session.BrowserName, session.AuthProvider, + session.OSName, session.BrowserName, session.AuthProvider, session.MFAVerified, } _, err := tx.Exec( @@ -84,7 +86,7 @@ func (r *tokenRepository) GetSession(ctx context.Context, sessionID uuid.UUID) ( created_at, expires_at, last_refreshed_at, revoked_at, access_nonce, refresh_nonce, location_city, location_region, location_country, location_country_code, location_postal_code, - os_name, browser_name, auth_provider + os_name, browser_name, auth_provider, mfa_verified, reauth_at FROM sessions WHERE id = $1 ` @@ -104,7 +106,7 @@ func (r *tokenRepository) GetSession(ctx context.Context, sessionID uuid.UUID) ( &sess.CreatedAt, &sess.ExpiresAt, &sess.LastRefreshedAt, &sess.RevokedAt, &sess.AccessNonce, &sess.RefreshNonce, &sess.LocationCity, &sess.LocationRegion, &sess.LocationCountry, &sess.LocationCountryCode, &sess.LocationPostalCode, - &sess.OSName, &sess.BrowserName, &sess.AuthProvider, + &sess.OSName, &sess.BrowserName, &sess.AuthProvider, &sess.MFAVerified, &sess.ReauthAt, ) if err != nil { // A missing session row is an expected auth outcome, not a server @@ -132,7 +134,7 @@ func (r *tokenRepository) ListSessionsByUser(ctx context.Context, userID uuid.UU created_at, expires_at, last_refreshed_at, revoked_at, access_nonce, refresh_nonce, location_city, location_region, location_country, location_country_code, location_postal_code, - os_name, browser_name, auth_provider + os_name, browser_name, auth_provider, mfa_verified, reauth_at FROM sessions WHERE user_id = $1 AND revoked_at IS NULL @@ -157,7 +159,7 @@ func (r *tokenRepository) ListSessionsByUser(ctx context.Context, userID uuid.UU &sess.CreatedAt, &sess.ExpiresAt, &sess.LastRefreshedAt, &sess.RevokedAt, &sess.AccessNonce, &sess.RefreshNonce, &sess.LocationCity, &sess.LocationRegion, &sess.LocationCountry, &sess.LocationCountryCode, &sess.LocationPostalCode, - &sess.OSName, &sess.BrowserName, &sess.AuthProvider, + &sess.OSName, &sess.BrowserName, &sess.AuthProvider, &sess.MFAVerified, &sess.ReauthAt, ); err != nil { db.CaptureError(err, "", nil, "scan") return nil, errx.InternalError() @@ -427,3 +429,11 @@ func (r *tokenRepository) DefaultOrganization(ctx context.Context, userID uuid.U } return &orgID, nil } + +// StampReauth records a successful re-authentication on the session. +func (r *tokenRepository) StampReauth(ctx context.Context, sessionID uuid.UUID, at time.Time) error { + _, err := r.DB.Exec(ctx, + `UPDATE sessions SET reauth_at = $2 WHERE id = $1 AND revoked_at IS NULL`, + sessionID, at) + return err +} diff --git a/internal/repository/pg_totp.go b/internal/repository/pg_totp.go index a4d91f035..7e283257b 100644 --- a/internal/repository/pg_totp.go +++ b/internal/repository/pg_totp.go @@ -20,6 +20,10 @@ type TOTPRepository interface { InsertRecoveryCodes(ctx context.Context, userID uuid.UUID, hashes []string) error ListUnusedRecoveryCodes(ctx context.Context, userID uuid.UUID) ([]models.RecoveryCode, error) ConsumeRecoveryCode(ctx context.Context, codeID uuid.UUID) error + // ConsumeTOTPStep records that this time step has been spent, and reports + // whether it was still available. It is compare-and-swap so two requests + // racing with the same code cannot both win. + ConsumeTOTPStep(ctx context.Context, userID uuid.UUID, step uint64) (bool, error) } type totpRepository struct { @@ -128,3 +132,18 @@ func (r *totpRepository) ConsumeRecoveryCode(ctx context.Context, codeID uuid.UU } return nil } + +// ConsumeTOTPStep retires a TOTP time step for a user. +// +// The guard is in the WHERE clause rather than a read-then-write, so two +// sign-ins presenting the same code at the same moment cannot both pass: only +// the statement that actually updates a row returns true. +func (r *totpRepository) ConsumeTOTPStep(ctx context.Context, userID uuid.UUID, step uint64) (bool, error) { + tag, err := r.db.Exec(ctx, + `UPDATE user_totp_settings SET last_used_step = $2 WHERE user_id = $1 AND last_used_step < $2`, + userID, int64(step)) + if err != nil { + return false, err + } + return tag.RowsAffected() == 1, nil +} diff --git a/internal/repository/pg_webhook.go b/internal/repository/pg_webhook.go index 85baf738c..3561801ac 100644 --- a/internal/repository/pg_webhook.go +++ b/internal/repository/pg_webhook.go @@ -11,6 +11,7 @@ import ( "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" + "github.com/warmbly/warmbly/internal/pkg/encrypt" "github.com/warmbly/warmbly/internal/models" ) @@ -78,12 +79,50 @@ type WebhookRepository interface { type webhookRepository struct { db *pgxpool.Pool + // enc seals the endpoint signing secret at rest under the instance key + // (CREDENTIALS_ENCRYPTION_KEY). The secret is what a receiver uses to + // prove a delivery came from us, so a read-only copy of the database was + // enough to forge one. Nil is tolerated so a deployment without the key + // keeps booting; rows are then read and written in the clear exactly as + // before, which is the pre-existing behaviour rather than a new failure. + enc *encrypt.Encrypter } func NewWebhookRepository(db *pgxpool.Pool) WebhookRepository { return &webhookRepository{db: db} } +// NewWebhookRepositorySealed is NewWebhookRepository with secret sealing on. +func NewWebhookRepositorySealed(db *pgxpool.Pool, enc *encrypt.Encrypter) WebhookRepository { + return &webhookRepository{db: db, enc: enc} +} + +// sealSecret encrypts a signing secret for storage. Without an encrypter it +// stores what it was given, matching the behaviour before sealing existed. +func (r *webhookRepository) sealSecret(plain string) (string, error) { + if r.enc == nil || plain == "" { + return plain, nil + } + return r.enc.Encrypt(plain) +} + +// openSecret returns the plaintext signing secret, reporting whether the row +// was still in the pre-sealing plaintext format. +// +// Rows written before sealing hold a "whsec_"-prefixed token, which is not +// valid hex, so a decrypt failure identifies a legacy row rather than +// corruption. Those are returned as they are: the alternative is breaking every +// webhook that already works. +func (r *webhookRepository) openSecret(stored string) (string, bool) { + if r.enc == nil || stored == "" { + return stored, false + } + if plain, err := r.enc.Decrypt(stored); err == nil { + return plain, false + } + return stored, true +} + // endpointCols is the shared column projection so every read scans identically. const endpointCols = `id, organization_id, url, description, event_types, enabled, last_success_at, last_failure_at, last_failure_reason, consecutive_failures, @@ -111,6 +150,11 @@ func (r *webhookRepository) CreateEndpoint(ctx context.Context, endpoint *models // returns it instead of echoing a null filter. endpoint.EventTypes = textArray(endpoint.EventTypes) + sealed, serr := r.sealSecret(secret) + if serr != nil { + return serr + } + _, err := r.db.Exec(ctx, ` INSERT INTO webhook_endpoints ( id, organization_id, url, description, secret, event_types, @@ -119,7 +163,7 @@ func (r *webhookRepository) CreateEndpoint(ctx context.Context, endpoint *models ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $11) `, endpoint.ID, endpoint.OrganizationID, endpoint.URL, endpoint.Description, - secret, endpoint.EventTypes, endpoint.Enabled, + sealed, endpoint.EventTypes, endpoint.Enabled, endpoint.OAuthApplicationID, endpoint.CreatedBy, verificationToken, endpoint.CreatedAt, ) @@ -147,9 +191,13 @@ func (r *webhookRepository) UpdateEndpoint(ctx context.Context, endpoint *models } func (r *webhookRepository) RotateSecret(ctx context.Context, orgID, endpointID uuid.UUID, newSecret string) error { + sealed, serr := r.sealSecret(newSecret) + if serr != nil { + return serr + } cmd, err := r.db.Exec(ctx, `UPDATE webhook_endpoints SET secret = $1, updated_at = NOW() WHERE id = $2 AND organization_id = $3`, - newSecret, endpointID, orgID, + sealed, endpointID, orgID, ) if err != nil { return err @@ -212,7 +260,23 @@ func (r *webhookRepository) GetEndpointSecret(ctx context.Context, endpointID uu if errors.Is(err, pgx.ErrNoRows) || errors.Is(err, sql.ErrNoRows) { return "", errors.New("webhook endpoint not found") } - return secret, err + if err != nil { + return "", err + } + + plain, legacy := r.openSecret(secret) + if legacy { + // Re-seal on first read, the same way mailbox credentials convert, so + // the plaintext window closes on its own rather than waiting for the + // owner to rotate. Best effort: a failure here still returns a working + // secret, and the next delivery tries again. + if sealed, serr := r.sealSecret(plain); serr == nil && sealed != plain { + _, _ = r.db.Exec(ctx, + `UPDATE webhook_endpoints SET secret = $2 WHERE id = $1 AND secret = $3`, + endpointID, sealed, secret) + } + } + return plain, nil } func (r *webhookRepository) GetVerificationToken(ctx context.Context, endpointID uuid.UUID) (string, error) { @@ -287,6 +351,10 @@ func (r *webhookRepository) ListEndpointsForOrg(ctx context.Context, orgID uuid. // and the URL is inside the app's allowed domains), so it receives events // immediately. event_types is the scope-filtered set the org's grant allows. func (r *webhookRepository) UpsertAppEndpoint(ctx context.Context, orgID, appID uuid.UUID, url, secret string, eventTypes []string) error { + sealed, serr := r.sealSecret(secret) + if serr != nil { + return serr + } _, err := r.db.Exec(ctx, ` INSERT INTO webhook_endpoints ( id, organization_id, url, description, secret, event_types, enabled, @@ -297,7 +365,7 @@ func (r *webhookRepository) UpsertAppEndpoint(ctx context.Context, orgID, appID DO UPDATE SET url = EXCLUDED.url, secret = EXCLUDED.secret, event_types = EXCLUDED.event_types, enabled = true, auto_disabled_at = NULL, disabled_reason = NULL, updated_at = NOW() - `, orgID, url, "Managed by OAuth app", secret, textArray(eventTypes), appID) + `, orgID, url, "Managed by OAuth app", sealed, textArray(eventTypes), appID) return err } diff --git a/internal/repository/routed_pairs_order_test.go b/internal/repository/routed_pairs_order_test.go new file mode 100644 index 000000000..7637e6171 --- /dev/null +++ b/internal/repository/routed_pairs_order_test.go @@ -0,0 +1,66 @@ +package repository + +import ( + "fmt" + "regexp" + "strconv" + "testing" +) + +// The custom-field sort key is the one part of this ORDER BY that comes from a +// customer. It used to be concatenated into the SQL text inside a quoted +// literal; it is now a bound parameter, appended to the args slice. That makes +// the placeholder number depend on how many arguments precede it, so this +// asserts the two stay in step: a mismatch is either an injection (too few +// args) or a bind error at runtime (too many). +func TestRoutedPairsOrderPlaceholderMatchesArgs(t *testing.T) { + cases := []struct { + name string + orderBy string + orderField string + wantArgs int + }{ + {"default ordering binds nothing extra", "created_at", "", 2}, + {"email ordering binds nothing extra", "email", "", 2}, + {"custom field with no key falls back", "custom_field", "", 2}, + {"custom field binds the key", "custom_field", "Company Mobile", 3}, + } + + for _, tc := range cases { + t.Run(tc.name, func(t *testing.T) { + // Mirrors the construction in FindRoutedPairs. + args := []any{"campaign", 3} + var contactOrder string + switch tc.orderBy { + case "email": + contactOrder = "c.email" + case "custom_field": + if tc.orderField != "" { + args = append(args, tc.orderField) + contactOrder = fmt.Sprintf("c.custom_fields->>$%d", len(args)) + } else { + contactOrder = "c.created_at" + } + default: + contactOrder = "c.created_at" + } + + if len(args) != tc.wantArgs { + t.Fatalf("args = %d, want %d", len(args), tc.wantArgs) + } + + // The key must never appear as SQL text, only as a placeholder. + if tc.orderField != "" && regexp.MustCompile(regexp.QuoteMeta(tc.orderField)).MatchString(contactOrder) { + t.Fatalf("the sort key reached the SQL text: %q", contactOrder) + } + + // Any placeholder used must be within the args that exist. + for _, m := range regexp.MustCompile(`\$(\d+)`).FindAllStringSubmatch(contactOrder, -1) { + n, _ := strconv.Atoi(m[1]) + if n > len(args) { + t.Fatalf("placeholder $%d exceeds %d bound args", n, len(args)) + } + } + }) + } +} diff --git a/internal/repository/warmup_reputation_ledger_live_test.go b/internal/repository/warmup_reputation_ledger_live_test.go index b8c59f886..352ce7b6b 100644 --- a/internal/repository/warmup_reputation_ledger_live_test.go +++ b/internal/repository/warmup_reputation_ledger_live_test.go @@ -96,9 +96,9 @@ func (f *ledgerFixture) penalise(t *testing.T, id uuid.UUID, score float64, stat WHERE email_account_id = $1`, id, score, state, until) } -func (f *ledgerFixture) remove(t *testing.T, id uuid.UUID) { +func (f *ledgerFixture) remove(t *testing.T, user, id uuid.UUID) { t.Helper() - if xerr := f.emails.Delete(context.Background(), id.String(), 0); xerr != nil { + if xerr := f.emails.Delete(context.Background(), user.String(), id.String(), 0); xerr != nil { t.Fatalf("Delete: %v", xerr) } } @@ -176,7 +176,7 @@ func TestLiveReputationMirrorFollowsTheAddressAcrossRemoval(t *testing.T) { written := m.recordedAt time.Sleep(20 * time.Millisecond) - f.remove(t, first) + f.remove(t, f.user, first) m = f.mirrorRow(t) if m == nil { t.Fatal("removing the mailbox lost its standing") @@ -203,7 +203,7 @@ func TestLiveReputationMirrorLeavesNothingForGoodStanding(t *testing.T) { f := newLedgerFixture(t) first := f.addMailbox(t, f.user) f.join(t, first) - f.remove(t, first) + f.remove(t, f.user, first) if m := f.mirrorRow(t); m != nil { t.Fatalf("a mailbox in good standing left a mirror row: %+v", m) } @@ -273,7 +273,7 @@ func TestLiveReputationMirrorNeverLapsesAReviewBlock(t *testing.T) { if m == nil || m.standing != nil { t.Fatalf("a review block must mirror with no standing_until: %+v", m) } - f.remove(t, id) + f.remove(t, f.user, id) f.exec(t, `UPDATE warmup_reputation_ledger SET recorded_at = now() - interval '400 days' WHERE organization_id = $1`, f.org) if _, err := f.warmups.PurgeExpiredReputationLedger(context.Background()); err != nil { t.Fatalf("purge: %v", err) @@ -308,7 +308,7 @@ func TestLiveReputationMirrorLapsesOnlyWithoutALiveRow(t *testing.T) { } // Removed and lapsed: forgotten, and reported. - f.remove(t, id) + f.remove(t, f.user, id) age() purged, err := f.warmups.PurgeExpiredReputationLedger(context.Background()) if err != nil { @@ -326,7 +326,7 @@ func TestLiveReputationMirrorDoesNotInheritALapsedStanding(t *testing.T) { id := f.addMailbox(t, f.user) f.join(t, id) f.penalise(t, id, 40, "quarantined", ptr(time.Now().Add(7*24*time.Hour))) - f.remove(t, id) + f.remove(t, f.user, id) f.exec(t, `UPDATE warmup_reputation_ledger SET standing_until = now() - interval '200 days', recorded_at = now() - interval '200 days' WHERE organization_id = $1`, f.org) again := f.addMailbox(t, f.user) diff --git a/internal/scheduler/service.go b/internal/scheduler/service.go index 11a80733d..8bbe39785 100644 --- a/internal/scheduler/service.go +++ b/internal/scheduler/service.go @@ -16,10 +16,6 @@ import ( type SchedulerService interface { // Warmup scheduling CalculateNextWarmupTime(ctx context.Context, accountID uuid.UUID) (time.Time, error) - // WarmupDailyBudget is today's warmup target and what has gone out against - // it, read again at send time so a target cut after the send was placed - // still holds. - WarmupDailyBudget(ctx context.Context, accountID uuid.UUID) (WarmupBudget, error) // Campaign scheduling CalculateNextCampaignTime(ctx context.Context, campaignID uuid.UUID) (time.Time, *repository.ContactSequencePair, uuid.UUID, error) diff --git a/internal/scheduler/warmup_scheduler.go b/internal/scheduler/warmup_scheduler.go index 57caaea38..572d27f64 100644 --- a/internal/scheduler/warmup_scheduler.go +++ b/internal/scheduler/warmup_scheduler.go @@ -188,20 +188,74 @@ func (s *schedulerService) CalculateNextWarmupTime(ctx context.Context, accountI } } - // STEP 2: Today's budget. The send-time gate resolves it through the same - // code, so a send is never placed on one number and checked against another. - day, err := s.resolveWarmupBudget(ctx, account, activelyWarming, inCampaign) - if err != nil { - return time.Time{}, err + // STEP 2: One shared resolve, so this target and the one the mailbox + // drawer reports cannot drift apart. + healthState := s.resolveHealthState(ctx, accountID) + rampAnchor := time.Now() + if account.Warmup != nil { + rampAnchor = *account.Warmup } - if day.NoPartners { - return recipientRecheckTime(), nil + plan := warmupramp.Resolve(ctx, s.warmupRepo, warmupramp.Input{ + AccountID: accountID, + WarmupStart: rampAnchor, + ActivelyWarming: activelyWarming, + Base: account.WarmupBase, + Increase: account.WarmupIncrease, + Max: account.WarmupMax, + InCampaign: inCampaign, + Health: healthState, + Now: time.Now(), + }) + targetVolume := plan.Target + if plan.Cut() { + log.Info(). + Str("email_account_id", accountID.String()). + Int("placements_48h", plan.Placements). + Int("sends_48h", plan.Sends). + Int("target", targetVolume). + Msg("warmup volume cut on an early placement signal; ramp held") + } + + // Vary the day's target so a mailbox doesn't send an identical count every + // day. Deterministic per (account, local day) so it's stable across the + // day's reschedules. Actively-warming mailboxes keep a floor of WarmupBase. + if activelyWarming && targetVolume > 0 { + factor := dailyVolumeFactor(accountID, time.Now().In(loadLocation(account.Timezone))) + varied := int(float64(targetVolume)*factor + 0.5) + if varied < account.WarmupBase { + varied = account.WarmupBase + } + if varied < 1 { + varied = 1 + } + if varied < targetVolume { + targetVolume = varied + } + } + + // STEP 2.1: Cap per-mailbox volume to actual recipient capacity. The + // sender should not send multiple warmup messages to the same recipient + // in a single day just to hit an arbitrary target; that creates obvious + // pool loops when membership is small. Recipient-only participants count + // here, so operators can add inbound capacity without making those + // mailboxes warmup senders. + if s.warmupRepo != nil { + poolType := s.warmupPoolTypeForAccount(ctx, account) + // The set the selector draws from, so the cap never exceeds what a send can reach. + candidates, err := s.warmupRepo.WarmupPartnerCandidates(ctx, poolType, accountID) + if err == nil { + eligibleRecipients := len(candidates) + if eligibleRecipients <= 0 { + return recipientRecheckTime(), nil + } + if targetVolume > eligibleRecipients { + targetVolume = eligibleRecipients + } + } } - targetVolume := day.Target - emailsSentToday := day.Sent // Resolve owns the band's volume half; only its spacing half applies here. - adj := adjustmentFor(day.health) + adj := adjustmentFor(healthState) // Spacing: a drawn gap from the profile when one is enabled, otherwise the // mailbox's fixed min gap. The health-state multiplier still applies on top, @@ -211,8 +265,14 @@ func (s *schedulerService) CalculateNextWarmupTime(ctx context.Context, accountI minWaitSeconds = int(float64(minWaitSeconds)*adj.minWaitMultiplier + 0.5) } + // STEP 3: Count emails already sent today + emailsSentToday, err := s.taskRepo.CountWarmupEmailsSentToday(ctx, accountID) + if err != nil { + return time.Time{}, err + } + // STEP 4: Check if we've hit today's limit - if day.Reached() { + if emailsSentToday >= targetVolume { // Move to tomorrow's first slot return s.snapWarmupToBehavior(bhv, calculateFirstSlotTomorrowAt(account.Timezone, warmupStart)), nil } @@ -310,138 +370,6 @@ func (s *schedulerService) CalculateNextWarmupTime(ctx context.Context, accountI return s.snapWarmupToBehavior(bhv, candidateTime), nil } -// WarmupBudget is today's warmup volume for one mailbox and what has already -// gone out against it, resolved by the scheduler when it places a send and -// again when the send executes. The mailbox drawer does not read it: it shows -// the plan before daily variation and the recipient cap. -type WarmupBudget struct { - // Target is the day's volume after ramp, early cut, health band, daily - // variation and recipient capacity. - Target int - // Sent is the completed warmup sends counted against today. - Sent int - // NoPartners is set when the pool offers this mailbox nobody to write to. - // Target and Sent are not resolved then, and the partner draw rather than - // the cap is what stops the send, so Reached deliberately reports false. - NoPartners bool -} - -// Reached reports whether today has no volume left. -func (b WarmupBudget) Reached() bool { - return !b.NoPartners && b.Sent >= b.Target -} - -// warmupDay is the budget plus the health band the scheduler still needs for -// spacing. -type warmupDay struct { - WarmupBudget - health models.WarmupHealthState -} - -// WarmupDailyBudget resolves today's budget for the send-time check. The -// scheduler counts today's sends only when it places the NEXT send, so a -// signal that cuts the target between placing a send and executing it (an -// early placement, a health band, a partner leaving the pool) used to leave -// that send going out over the cut number. Reading the budget again at -// execution closes that window. -func (s *schedulerService) WarmupDailyBudget(ctx context.Context, accountID uuid.UUID) (WarmupBudget, error) { - account, xerr := s.emailRepo.GetByID(ctx, accountID) - if xerr != nil { - return WarmupBudget{}, xerr - } - activelyWarming := account.IsWarmingActive() - inCampaign := s.accountInActiveCampaign(ctx, accountID) - if !activelyWarming && !inCampaign { - return WarmupBudget{}, ErrWarmupNotEnabled - } - day, err := s.resolveWarmupBudget(ctx, account, activelyWarming, inCampaign) - if err != nil { - return WarmupBudget{}, err - } - return day.WarmupBudget, nil -} - -// resolveWarmupBudget is the one place today's target is computed: the shared -// ramp policy, the per-day variation, the recipient cap, then the count of -// what has already been sent against it. -func (s *schedulerService) resolveWarmupBudget(ctx context.Context, account *models.Email, activelyWarming, inCampaign bool) (warmupDay, error) { - accountID := account.ID - healthState := s.resolveHealthState(ctx, accountID) - rampAnchor := time.Now() - if account.Warmup != nil { - rampAnchor = *account.Warmup - } - plan := warmupramp.Resolve(ctx, s.warmupRepo, warmupramp.Input{ - AccountID: accountID, - WarmupStart: rampAnchor, - ActivelyWarming: activelyWarming, - Base: account.WarmupBase, - Increase: account.WarmupIncrease, - Max: account.WarmupMax, - InCampaign: inCampaign, - Health: healthState, - Now: time.Now(), - }) - targetVolume := plan.Target - if plan.Cut() { - log.Info(). - Str("email_account_id", accountID.String()). - Int("placements_48h", plan.Placements). - Int("sends_48h", plan.Sends). - Int("target", targetVolume). - Msg("warmup volume cut on an early placement signal; ramp held") - } - - // Vary the day's target so a mailbox doesn't send an identical count every - // day. Deterministic per (account, local day) so it's stable across the - // day's reschedules. Actively-warming mailboxes keep a floor of WarmupBase. - if activelyWarming && targetVolume > 0 { - factor := dailyVolumeFactor(accountID, time.Now().In(loadLocation(account.Timezone))) - varied := int(float64(targetVolume)*factor + 0.5) - if varied < account.WarmupBase { - varied = account.WarmupBase - } - if varied < 1 { - varied = 1 - } - if varied < targetVolume { - targetVolume = varied - } - } - - day := warmupDay{health: healthState} - - // Cap per-mailbox volume to actual recipient capacity. The sender should - // not send multiple warmup messages to the same recipient in a single day - // just to hit an arbitrary target; that creates obvious pool loops when - // membership is small. Recipient-only participants count here, so - // operators can add inbound capacity without making those mailboxes - // warmup senders. - if s.warmupRepo != nil { - poolType := s.warmupPoolTypeForAccount(ctx, account) - // The set the selector draws from, so the cap never exceeds what a send can reach. - candidates, err := s.warmupRepo.WarmupPartnerCandidates(ctx, poolType, accountID) - if err == nil { - eligibleRecipients := len(candidates) - if eligibleRecipients <= 0 { - day.NoPartners = true - return day, nil - } - if targetVolume > eligibleRecipients { - targetVolume = eligibleRecipients - } - } - } - day.Target = targetVolume - - sent, err := s.taskRepo.CountWarmupEmailsSentToday(ctx, accountID) - if err != nil { - return day, err - } - day.Sent = sent - return day, nil -} - // snapWarmupToBehavior moves a warmup candidate onto the mailbox's rolled // workday and randomises its sub-minute component. A profile with no reachable // window leaves the candidate untouched: warmup should degrade to its own diff --git a/internal/scheduler/warmup_scheduler_test.go b/internal/scheduler/warmup_scheduler_test.go index 8cc3d82b8..e170a193d 100644 --- a/internal/scheduler/warmup_scheduler_test.go +++ b/internal/scheduler/warmup_scheduler_test.go @@ -62,23 +62,3 @@ func TestWarmupRampTarget(t *testing.T) { }) } } - -func TestWarmupBudgetReached(t *testing.T) { - tests := []struct { - name string - budget WarmupBudget - want bool - }{ - {"under target", WarmupBudget{Target: 10, Sent: 8}, false}, - {"at target", WarmupBudget{Target: 8, Sent: 8}, true}, - {"over target after a cut", WarmupBudget{Target: 8, Sent: 9}, true}, - {"nobody to write to is the partner draw's call, not the cap's", WarmupBudget{NoPartners: true}, false}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - if got := tt.budget.Reached(); got != tt.want { - t.Errorf("Reached() = %v, want %v", got, tt.want) - } - }) - } -} diff --git a/internal/tasks/email_task.go b/internal/tasks/email_task.go index a98e2ff0d..56fd9dca3 100644 --- a/internal/tasks/email_task.go +++ b/internal/tasks/email_task.go @@ -14,7 +14,6 @@ import ( "github.com/warmbly/warmbly/internal/models" "github.com/warmbly/warmbly/internal/observability/errs" "github.com/warmbly/warmbly/internal/repository" - "github.com/warmbly/warmbly/internal/scheduler" "github.com/warmbly/warmbly/internal/tasks/proto" ) @@ -186,12 +185,7 @@ func (s *tasksService) HandleEmailTask(task *proto.ProcessTask) *errx.Error { // same domains, so leaving it running would keep spending the reputation // the suspension exists to protect. if s.orgBlocksSending(ctx, account.OrganizationID) { - // Discarding this error hid a status the enum did not have for months, - // with the task left pending for the dispatcher to fire again. - if err := s.taskRepo.UpdateTaskStatus(ctx, taskID, "skipped_org_suspended"); err != nil { - errs.CaptureException(err) - return errx.InternalError() - } + _ = s.taskRepo.UpdateTaskStatus(ctx, taskID, "skipped_org_suspended") executionStatus = "completed" return nil } @@ -213,53 +207,6 @@ func (s *tasksService) HandleEmailTask(task *proto.ProcessTask) *errx.Error { } } - // STEP 3.8: Today's target, read again now rather than trusted from when - // this send was placed. The scheduler counts the day only when it places - // the NEXT send, so a placement recorded in between cut the target for the - // drawer and the scheduler but not for the send already waiting, and the - // mailbox ended the day one over its own cut number (#592). A reply-back - // pulled forward from tomorrow lands here too. - // - // The aim is read first: it is what makes the successor still a reply, and - // the read is cheap next to being wrong about it. - var aim *uuid.UUID - if warmupTask, aimErr := s.taskRepo.GetWarmupTask(ctx, taskID); aimErr != nil { - log.Warn().Err(aimErr).Str("task_id", taskID.String()).Msg("warmup task aim unreadable; a held reply-back would go out as a fresh message") - } else if warmupTask != nil { - aim = warmupTask.TargetAccountID - } - - budget, budgetErr := s.scheduler.WarmupDailyBudget(ctx, account.ID) - switch { - case budgetErr != nil: - // Not knowing how many have gone out today is exactly when a send must - // not go out: failing open here would reopen #592 whenever the database - // is struggling. The task is still pending, so this retries. That covers - // ErrWarmupNotEnabled too, which a failed campaign read can produce: if - // the mailbox really stopped warming, the retry's own check above winds - // the chain down. - if !errors.Is(budgetErr, scheduler.ErrWarmupNotEnabled) { - errs.CaptureException(budgetErr) - } - return errx.InternalError() - case budget.Reached(): - log.Info(). - Str("task_id", taskID.String()). - Str("email_account_id", account.ID.String()). - Int("sent_today", budget.Sent). - Int("target", budget.Target). - Msg("warmup send skipped: today's target is already reached") - // Acknowledged only once the task is marked, or the row stays pending - // and blocks the successor this chain needs. - if err := s.taskRepo.UpdateTaskStatus(ctx, taskID, "skipped_daily_limit"); err != nil { - errs.CaptureException(err) - return errx.InternalError() - } - s.rescheduleWarmupAfterCap(ctx, account.ID, aim) - executionStatus = "completed" - return nil - } - // STEP 4: Mark task as active (with advisory lock) if err := s.taskRepo.UpdateTaskStatusWithLock(ctx, taskID, "active"); err != nil { errs.CaptureException(err) @@ -894,30 +841,8 @@ func (s *tasksService) EnsureWarmupScheduled(ctx context.Context, accountID uuid return s.createWarmupTask(ctx, accountID, nextTime) } -// rescheduleWarmupAfterCap parks the chain at the scheduler's next slot, which -// is tomorrow's opening once today is spent. A send that was aimed at one -// partner (a reply-back) keeps its aim, so the answer goes out first thing -// rather than being lost to the cap. A failure here is logged rather than -// returned: the task is already marked, and the reconciler re-seeds a mailbox -// that ends up with no pending task. -func (s *tasksService) rescheduleWarmupAfterCap(ctx context.Context, accountID uuid.UUID, aim *uuid.UUID) { - nextTime, err := s.scheduler.CalculateNextWarmupTime(ctx, accountID) - if err != nil { - nextTime = warmupPartnerRecheckTime() - } - if err := s.createWarmupTaskAimedAt(ctx, accountID, nextTime, aim); err != nil { - log.Warn().Err(err).Str("email_account_id", accountID.String()).Msg("Failed to reschedule warmup task after the daily target") - } -} - -// createWarmupTask creates the mailbox's next warmup wakeup. +// createWarmupTask creates a new warmup task in GCP Cloud Tasks func (s *tasksService) createWarmupTask(ctx context.Context, accountID uuid.UUID, scheduleTime time.Time) error { - return s.createWarmupTaskAimedAt(ctx, accountID, scheduleTime, nil) -} - -// createWarmupTaskAimedAt is createWarmupTask with the send pointed at one -// partner, the way a reply-back points it. -func (s *tasksService) createWarmupTaskAimedAt(ctx context.Context, accountID uuid.UUID, scheduleTime time.Time, target *uuid.UUID) error { // Create task in database newTaskID := uuid.New() newTask := &Task{ @@ -930,8 +855,7 @@ func (s *tasksService) createWarmupTaskAimedAt(ctx context.Context, accountID uu // Create warmup task entry warmupTask := &WarmupTask{ - TaskID: newTaskID, - TargetAccountID: target, + TaskID: newTaskID, } created, err := s.taskRepo.CreateWarmupTaskWithLock(ctx, newTask, warmupTask) diff --git a/internal/tasks/warmup_cut_cap_live_test.go b/internal/tasks/warmup_cut_cap_live_test.go deleted file mode 100644 index 980bab699..000000000 --- a/internal/tasks/warmup_cut_cap_live_test.go +++ /dev/null @@ -1,392 +0,0 @@ -package tasks - -import ( - "context" - "errors" - "testing" - "time" - - "github.com/google/uuid" - "github.com/jackc/pgx/v5/pgxpool" - - warmupapp "github.com/warmbly/warmbly/internal/app/warmup" - "github.com/warmbly/warmbly/internal/models" - "github.com/warmbly/warmbly/internal/pkg/encrypt" - "github.com/warmbly/warmbly/internal/repository" - "github.com/warmbly/warmbly/internal/scheduler" - "github.com/warmbly/warmbly/internal/tasks/proto" -) - -// The day's target is enforced at the moment a warmup send executes, not only -// when the next one is placed (#592). Run with WARMBLY_TEST_DB on a scratch -// database; the premium pool must be empty so the recipient cap is known. - -type capFixture struct { - pool *pgxpool.Pool - svc *tasksService - sender *recordingSender - user uuid.UUID - org uuid.UUID - mailbox uuid.UUID - partners []uuid.UUID -} - -const capFixturePartners = 10 - -func newCapFixture(t *testing.T) *capFixture { - t.Helper() - handle := liveCampaignDB(t) - pool := handle.Pool - requireEmptyPool(t, pool, models.WarmupPoolPremiumID) - requireEmptyPool(t, pool, models.WarmupPoolFreeID) - - f := &capFixture{pool: pool, sender: &recordingSender{}, user: uuid.New(), org: uuid.New(), mailbox: uuid.New()} - t.Cleanup(func() { - c := context.Background() - for _, step := range []struct { - sql string - arg any - }{ - {`DELETE FROM warmup_tokens WHERE sender_account_id = $1`, f.mailbox}, - {`DELETE FROM warmup_spam_reports WHERE reported_account_id = $1`, f.mailbox}, - {`DELETE FROM warmup_statistics WHERE email_account_id = $1`, f.mailbox}, - {`DELETE FROM warmup_tasks WHERE task_id IN (SELECT id FROM tasks WHERE email_account_id = $1)`, f.mailbox}, - {`DELETE FROM task_failures WHERE task_id IN (SELECT id FROM tasks WHERE email_account_id = $1)`, f.mailbox}, - {`DELETE FROM tasks WHERE email_account_id = $1`, f.mailbox}, - {`DELETE FROM warmup_pool_participants WHERE email_account_id IN (SELECT id FROM email_accounts WHERE organization_id = $1)`, f.org}, - {`DELETE FROM email_accounts WHERE organization_id = $1`, f.org}, - {`DELETE FROM organizations WHERE id = $1`, f.org}, - {`DELETE FROM users WHERE id = $1`, f.user}, - } { - if _, err := pool.Exec(c, step.sql, step.arg); err != nil { - t.Errorf("cleanup %q: %v", step.sql, err) - } - } - }) - - f.exec(t, `INSERT INTO users (id, email, first_name, last_name) VALUES ($1, $2, 'Cap', 'Test')`, - f.user, "cap-"+f.user.String()[:8]+"@test.local") - f.exec(t, `INSERT INTO organizations (id, name, slug, owner_user_id) VALUES ($1, 'Cap Test', $2, $3)`, - f.org, "cap-"+f.org.String()[:8], f.user) - // Day one of a base-10 ramp, anchored with the database clock the way the - // app anchors it. An always-open window keeps the clock out of the result. - f.exec(t, `INSERT INTO email_accounts (id, user_id, organization_id, email, name, signature_plain, signature_html, - provider, status, campaign_limit, min_wait_time, timezone, warmup, warmup_base, warmup_increase, - warmup_max, warmup_reply_rate, warmup_pool_type, warmup_start_time, warmup_end_time) - VALUES ($1, $2, $3, $4, 'Cap', '', '', 'smtp_imap', 'active', 50, 0, 'UTC', now(), 10, 1, 40, 0, - 'premium', '00:00', '23:59')`, - f.mailbox, f.user, f.org, "cap-"+f.mailbox.String()[:8]+"@test.local") - // Enough recipients that the recipient cap sits above the ramp target. - for i := 0; i < capFixturePartners; i++ { - id := uuid.New() - f.partners = append(f.partners, id) - f.exec(t, `INSERT INTO email_accounts (id, user_id, organization_id, email, name, signature_plain, signature_html, - provider, status, campaign_limit, min_wait_time, timezone, warmup_pool_type) - VALUES ($1, $2, $3, $4, 'Cap', '', '', 'smtp_imap', 'active', 50, 600, 'UTC', 'premium')`, - id, f.user, f.org, "cap-"+id.String()[:8]+"@partner.test") - f.exec(t, `INSERT INTO warmup_pool_participants (pool_id, email_account_id, participant_role, health_state) - VALUES ($1, $2, 'recipient_only', 'healthy')`, models.WarmupPoolPremiumID, id) - } - - enc, err := encrypt.NewEncrypter([]byte("0123456789abcdef0123456789abcdef")) - if err != nil { - t.Fatalf("encrypter: %v", err) - } - taskRepo := repository.NewTaskRepository(pool) - warmupRepo := repository.NewWarmupRepository(pool) - emailRepo := repository.NewEmailRepostory(handle, enc) - campaignRepo := repository.NewCampaignRepostory(handle) - f.svc = &tasksService{ - tasksClient: noopTaskScheduler{}, - scheduler: scheduler.NewSchedulerService(taskRepo, warmupRepo, nil, emailRepo, campaignRepo, nil, nil), - emailSender: f.sender, - warmupHealth: warmupapp.NewService(warmupRepo), - taskRepo: taskRepo, - warmupRepo: warmupRepo, - emailRepo: emailRepo, - campaignRepo: campaignRepo, - } - return f -} - -func (f *capFixture) exec(t *testing.T, sql string, args ...any) { - t.Helper() - if _, err := f.pool.Exec(context.Background(), sql, args...); err != nil { - t.Fatalf("fixture %q: %v", sql[:min(60, len(sql))], err) - } -} - -// sentToday records n warmup sends already completed against today. -func (f *capFixture) sentToday(t *testing.T, n int) { - t.Helper() - for i := 0; i < n; i++ { - f.exec(t, `INSERT INTO tasks (id, task_type, email_account_id, status, message_id, scheduled_at, completed_at) - VALUES ($1, 'warmup', $2, 'completed', $3, now(), now())`, - uuid.New(), f.mailbox, "") - } -} - -func (f *capFixture) placement(t *testing.T) { - t.Helper() - f.exec(t, `INSERT INTO warmup_spam_reports (id, reporter_account_id, reported_account_id, message_id, report_type, created_at) - VALUES (gen_random_uuid(), $1, $1, $2, 'spam_placement', now())`, - f.mailbox, "msg-"+uuid.New().String()) -} - -// pending places the mailbox's one warmup wakeup at the given time and -// returns its id. -func (f *capFixture) pending(t *testing.T, at time.Time) uuid.UUID { - t.Helper() - if err := f.svc.createWarmupTask(context.Background(), f.mailbox, at); err != nil { - t.Fatalf("create pending warmup task: %v", err) - } - id, _ := f.pendingTask(t) - return id -} - -// pendingTask is the mailbox's pending wakeup with its aim, or uuid.Nil. -func (f *capFixture) pendingTask(t *testing.T) (uuid.UUID, *uuid.UUID) { - t.Helper() - rows, err := f.pool.Query(context.Background(), ` - SELECT t.id, wt.target_account_id - FROM tasks t LEFT JOIN warmup_tasks wt ON wt.task_id = t.id - WHERE t.email_account_id = $1 AND t.task_type = 'warmup' AND t.status = 'pending'`, f.mailbox) - if err != nil { - t.Fatalf("pending tasks: %v", err) - } - defer rows.Close() - var id uuid.UUID - var target *uuid.UUID - n := 0 - for rows.Next() { - if err := rows.Scan(&id, &target); err != nil { - t.Fatalf("scan: %v", err) - } - n++ - } - if n > 1 { - t.Fatalf("%d pending warmup tasks; the chain must hold exactly one", n) - } - return id, target -} - -func (f *capFixture) status(t *testing.T, id uuid.UUID) string { - t.Helper() - var status string - if err := f.pool.QueryRow(context.Background(), `SELECT status FROM tasks WHERE id = $1`, id).Scan(&status); err != nil { - t.Fatalf("task status: %v", err) - } - return status -} - -func (f *capFixture) run(t *testing.T, id uuid.UUID) { - t.Helper() - if xerr := f.svc.HandleEmailTask(&proto.ProcessTask{TaskId: id.String()}); xerr != nil { - t.Fatalf("HandleEmailTask: %v", xerr.Message) - } -} - -func (f *capFixture) budget(t *testing.T) scheduler.WarmupBudget { - t.Helper() - b, err := f.svc.scheduler.WarmupDailyBudget(context.Background(), f.mailbox) - if err != nil { - t.Fatalf("budget: %v", err) - } - return b -} - -// budgetFailingScheduler is the real scheduler with the send-time budget read -// broken, which is what a database blip looks like at that moment. -type budgetFailingScheduler struct { - scheduler.SchedulerService - err error -} - -func (s budgetFailingScheduler) WarmupDailyBudget(context.Context, uuid.UUID) (scheduler.WarmupBudget, error) { - return scheduler.WarmupBudget{}, s.err -} - -// Not knowing the day's count is exactly when a send must not go out: failing -// open there would reopen the bug whenever the database is struggling. A failed -// campaign read surfaces as "not warming", so that sentinel holds the send too. -func TestLiveWarmupUnreadableBudgetHoldsTheSendForRetry(t *testing.T) { - for _, tc := range []struct { - name string - err error - }{ - {"read failed", errors.New("budget read failed")}, - {"campaign read failed and reported not warming", scheduler.ErrWarmupNotEnabled}, - } { - t.Run(tc.name, func(t *testing.T) { - f := newCapFixture(t) - f.sentToday(t, 8) - task := f.pending(t, time.Now()) - f.svc.scheduler = budgetFailingScheduler{SchedulerService: f.svc.scheduler, err: tc.err} - - if xerr := f.svc.HandleEmailTask(&proto.ProcessTask{TaskId: task.String()}); xerr == nil { - t.Fatal("an unreadable budget was reported as success; the task would be acknowledged and never retried") - } - if f.sender.sent != 0 { - t.Fatalf("%d send(s) dispatched without knowing today's count", f.sender.sent) - } - if got := f.status(t, task); got != "pending" { - t.Fatalf("task status = %q, want pending so the retry picks it up", got) - } - }) - } -} - -func TestLiveWarmupPendingSendRespectsTargetCutAfterScheduling(t *testing.T) { - f := newCapFixture(t) - f.sentToday(t, 8) - if b := f.budget(t); b.Target != 10 || b.Sent != 8 || b.Reached() { - t.Fatalf("before the placement: budget %+v, want target 10 with 8 sent", b) - } - task := f.pending(t, time.Now()) - - // The placement lands while the send is waiting; the day is now 8. - f.placement(t) - if b := f.budget(t); b.Target != 8 || !b.Reached() { - t.Fatalf("after the placement: budget %+v, want the cut target of 8, reached", b) - } - - f.run(t, task) - - if f.sender.sent != 0 { - t.Fatalf("target was cut to 8 but the pending send still went out: %d send(s) dispatched", f.sender.sent) - } - if got := f.status(t, task); got != "skipped_daily_limit" { - t.Fatalf("task status = %q, want skipped_daily_limit", got) - } - next, _ := f.pendingTask(t) - if next == uuid.Nil { - t.Fatal("the chain was not rescheduled; the mailbox would never warm again") - } - var at time.Time - if err := f.pool.QueryRow(context.Background(), `SELECT scheduled_at FROM tasks WHERE id = $1`, next).Scan(&at); err != nil { - t.Fatal(err) - } - if at.Before(time.Now().Add(time.Hour)) { - t.Fatalf("rescheduled for %s; a spent day parks the chain at the next opening, not now", at) - } -} - -func TestLiveWarmupSendUnderTargetStillGoesOut(t *testing.T) { - f := newCapFixture(t) - f.sentToday(t, 8) - task := f.pending(t, time.Now()) - - f.run(t, task) - - if f.sender.sent != 1 { - t.Fatalf("%d send(s) dispatched, want 1: the gate must only hold a spent day", f.sender.sent) - } - if got := f.status(t, task); got != "completed" { - t.Fatalf("task status = %q, want completed", got) - } - if b := f.budget(t); b.Sent != 9 { - t.Fatalf("sent today = %d after the send, want 9", b.Sent) - } -} - -// A reply-back re-points the pending send and pulls it earlier, including -// out of tomorrow into a day that is already spent. The cap holds it, and the -// aim survives so the answer goes out at the next opening instead of being -// dropped. -func TestLiveWarmupReplyBackPulledIntoASpentDayKeepsItsAim(t *testing.T) { - f := newCapFixture(t) - f.sentToday(t, 10) - task := f.pending(t, time.Now().Add(6*time.Hour)) - writer := f.partners[0] - moved, err := f.svc.taskRepo.DirectPendingWarmupTask(context.Background(), f.mailbox, writer, time.Now()) - if err != nil || !moved { - t.Fatalf("direct pending task: moved=%v err=%v", moved, err) - } - - f.run(t, task) - - if f.sender.sent != 0 { - t.Fatalf("%d send(s) dispatched over a spent day", f.sender.sent) - } - if got := f.status(t, task); got != "skipped_daily_limit" { - t.Fatalf("task status = %q, want skipped_daily_limit", got) - } - next, target := f.pendingTask(t) - if next == uuid.Nil { - t.Fatal("no successor task") - } - if target == nil || *target != writer { - t.Fatalf("successor aimed at %v, want the reply-back's writer %s", target, writer) - } -} - -// A suspended workspace's send is held under a status the enum carries, so the -// row leaves pending. It used to write a value the enum lacked, the write -// failed silently, and the dispatcher fired the task again every tick. -func TestLiveWarmupSuspendedWorkspaceMarksTheTask(t *testing.T) { - f := newCapFixture(t) - handle := liveCampaignDB(t) - f.exec(t, `UPDATE organizations SET risk_state = 'suspended' WHERE id = $1`, f.org) - f.svc.orgRiskRepo = repository.NewOrgRiskRepository(handle) - task := f.pending(t, time.Now()) - - f.run(t, task) - - if f.sender.sent != 0 { - t.Fatalf("%d send(s) dispatched from a suspended workspace", f.sender.sent) - } - if got := f.status(t, task); got != "skipped_org_suspended" { - t.Fatalf("task status = %q, want skipped_org_suspended", got) - } -} - -// statusFailingRepo is the real repository with one status write refused, -// which is what a database blip looks like at that write. -type statusFailingRepo struct { - repository.TaskRepository - refuse string -} - -func (r statusFailingRepo) UpdateTaskStatus(ctx context.Context, taskID uuid.UUID, status string) error { - if status == r.refuse { - return errors.New("status write failed") - } - return r.TaskRepository.UpdateTaskStatus(ctx, taskID, status) -} - -// A hold whose status write fails must not be reported as handled: the row -// stays pending, and acknowledging it would leave it blocking the successor -// until the overdue sweep. Discarding this error is what hid a status the enum -// did not carry for months. -func TestLiveWarmupHoldIsNotAcknowledgedUntilTheTaskIsMarked(t *testing.T) { - for _, tc := range []struct { - name string - status string - arrange func(t *testing.T, f *capFixture) - }{ - {"daily target reached", "skipped_daily_limit", func(t *testing.T, f *capFixture) { - f.sentToday(t, 10) - }}, - {"workspace suspended", "skipped_org_suspended", func(t *testing.T, f *capFixture) { - f.exec(t, `UPDATE organizations SET risk_state = 'suspended' WHERE id = $1`, f.org) - f.svc.orgRiskRepo = repository.NewOrgRiskRepository(liveCampaignDB(t)) - }}, - } { - t.Run(tc.name, func(t *testing.T) { - f := newCapFixture(t) - tc.arrange(t, f) - task := f.pending(t, time.Now()) - f.svc.taskRepo = statusFailingRepo{TaskRepository: f.svc.taskRepo, refuse: tc.status} - - if xerr := f.svc.HandleEmailTask(&proto.ProcessTask{TaskId: task.String()}); xerr == nil { - t.Fatal("the hold was reported as handled although its status write failed") - } - if f.sender.sent != 0 { - t.Fatalf("%d send(s) dispatched", f.sender.sent) - } - if got := f.status(t, task); got != "pending" { - t.Fatalf("task status = %q, want pending so the retry picks it up", got) - } - }) - } -} diff --git a/realtime/config/runtime.exs b/realtime/config/runtime.exs index 14083f991..57be4a96b 100644 --- a/realtime/config/runtime.exs +++ b/realtime/config/runtime.exs @@ -6,6 +6,13 @@ if config_env() == :prod do System.get_env("JWT_SECRET") || raise "JWT_SECRET environment variable is required" + # Same floor the backend applies to AUTH_SECRET, which is this same value. + # HS256 keys shorter than the hash output can be recovered offline from any + # token the service has issued. + if byte_size(jwt_secret) < 32 do + raise "JWT_SECRET must be at least 32 bytes: it verifies every session token. Generate one with: make gen-key" + end + secret_key_base = System.get_env("SECRET_KEY_BASE") || raise "SECRET_KEY_BASE environment variable is required" @@ -59,6 +66,12 @@ if config_env() == :prod do rate_limit_ws_join: String.to_integer(System.get_env("RATE_LIMIT_WS_JOIN") || "30"), rate_limit_ws_event: String.to_integer(System.get_env("RATE_LIMIT_WS_EVENT") || "60") + check_origin = + case System.get_env("CHECK_ORIGIN_HOSTS", "") |> String.split(",", trim: true) do + [] -> System.get_env("CHECK_ORIGIN", "false") == "true" + origins -> Enum.map(origins, &String.trim/1) + end + config :realtime, RealtimeWeb.Endpoint, url: [host: host, port: 443, scheme: "https"], http: [ @@ -66,7 +79,17 @@ if config_env() == :prod do port: port ], secret_key_base: secret_key_base, - check_origin: System.get_env("CHECK_ORIGIN", "false") == "true" + # The browser's Origin on a websocket upgrade is the DASHBOARD's origin, + # not this service's. check_origin: true compares against url: [host: ...], + # which is PHX_HOST, which is the websocket host, so it refuses every real + # connection. The transport used to hardcode check_origin: false, which hid + # that; now that the setting actually applies, it has to be given the right + # answer rather than a boolean. + # + # CHECK_ORIGIN_HOSTS is a comma-separated list of allowed origins, e.g. + # "https://app.example.com". Set it and the check is real. CHECK_ORIGIN=true + # without it keeps the old host-based behaviour for anyone relying on it. + check_origin: check_origin # Postgrex verifies the server against the system CA store, which has no # Amazon RDS root in it, so an RDS database needs DATABASE_SSL_CA_FILE @@ -114,7 +137,9 @@ if config_env() == :prod do url: database_url, ssl: database_ssl, pool_size: String.to_integer(System.get_env("DATABASE_POOL_SIZE") || "10"), - show_sensitive_data_on_connection_error: true + # Left off deliberately: this prints the whole Repo config, password + # included, into the logs the first time Postgres is unreachable. + show_sensitive_data_on_connection_error: false # Error reporting. An env var that is present but empty must behave as unset: # compose passes every optional variable through as "" so a single .env can diff --git a/realtime/lib/realtime/auth.ex b/realtime/lib/realtime/auth.ex index 2383b118e..8a5bdc770 100644 --- a/realtime/lib/realtime/auth.ex +++ b/realtime/lib/realtime/auth.ex @@ -109,6 +109,7 @@ defmodule Realtime.Auth do def error_code(:token_expired), do: 4004 def error_code(:invalid_claims), do: 4004 def error_code(:missing_subject), do: 4004 + def error_code(:wrong_token_purpose), do: 4004 def error_code(:invalid_key), do: 4004 def error_code(:key_inactive), do: 4004 def error_code(:key_expired), do: 4004 @@ -133,6 +134,10 @@ defmodule Realtime.Auth do def error_message(:token_expired), do: "Token expired" def error_message(:invalid_claims), do: "Invalid token claims" def error_message(:missing_subject), do: "Invalid token claims" + # Deliberately indistinguishable from any other authentication failure: a + # caller presenting the wrong kind of token learns nothing about which + # kinds exist. + def error_message(:wrong_token_purpose), do: "Authentication failed" def error_message(:invalid_key), do: "Invalid API key" def error_message(:key_inactive), do: "API key inactive" def error_message(:key_expired), do: "API key expired" @@ -407,7 +412,18 @@ defmodule Realtime.Auth do JOSE.JWK.from_oct(secret) end - defp validate_claims(%{"sub" => user_id, "exp" => exp}) do + # The backend signs every one of its tokens with this same key: the session + # access token, the refresh token, the challenge token issued after a password + # but before the emailed code, the 2FA pending token, and the password-reset + # link token. They share a claim shape, so checking only `sub` and `exp` + # accepted all of them here. The backend is safe because each is separately + # bound to a Redis nonce or a `sessions` row; this service checks neither. + # + # So the socket takes exactly one kind: the short-lived ticket minted by + # POST /v1/getaway for this purpose. Anything else is refused. + @ws_purpose "ws" + + defp validate_claims(%{"sub" => user_id, "exp" => exp} = claims) do now = System.system_time(:second) cond do @@ -417,13 +433,20 @@ defmodule Realtime.Auth do exp < now -> {:error, :token_expired} + Map.get(claims, "purpose") != @ws_purpose -> + {:error, :wrong_token_purpose} + true -> {:ok, user_id} end end - defp validate_claims(%{"user_id" => user_id, "exp" => exp}) do - validate_claims(%{"sub" => user_id, "exp" => exp}) + defp validate_claims(%{"user_id" => user_id, "exp" => exp} = claims) do + validate_claims( + claims + |> Map.put("sub", user_id) + |> Map.put("exp", exp) + ) end defp validate_claims(_) do diff --git a/realtime/lib/realtime_web/endpoint.ex b/realtime/lib/realtime_web/endpoint.ex index 7428080b2..14e534f88 100644 --- a/realtime/lib/realtime_web/endpoint.ex +++ b/realtime/lib/realtime_web/endpoint.ex @@ -8,11 +8,14 @@ defmodule RealtimeWeb.Endpoint do use Phoenix.Endpoint, otp_app: :realtime + # check_origin is deliberately absent here. A transport-level value takes + # precedence over the endpoint's, so hardcoding one made the CHECK_ORIGIN + # environment variable, and the installer flag that sets it, do nothing. + # The endpoint config in runtime.exs governs it now. socket("/socket", RealtimeWeb.UserSocket, websocket: [ timeout: 60_000, compress: true, - check_origin: false, # Client frames are small (joins, presence, live cursor/select/patch); # without a cap cowboy accepts unbounded frames, which compress makes # cheap to send and the org fan-out makes expensive to receive. diff --git a/scripts/casa-evidence.sh b/scripts/casa-evidence.sh new file mode 100644 index 000000000..cc98238b0 --- /dev/null +++ b/scripts/casa-evidence.sh @@ -0,0 +1,86 @@ +#!/usr/bin/env bash +# Generate the CASA dependency-scan artifacts. +# +# Everything here is read-only against the tree: it runs scanners and writes +# their output under compliance/casa/artifacts/. Two artifacts cannot come from +# this repository and are attached by hand before submission: the Qualys SSL +# Labs report per hostname, and the authenticated Burp Suite scan. +# +# A scanner that is not installed is recorded as not run rather than silently +# skipped. An evidence pack with a gap in it is honest; one that hides the gap +# is not. +set -uo pipefail + +cd "$(dirname "$0")/.." +OUT="compliance/casa/artifacts" +mkdir -p "$OUT" +STAMP="$(date -u '+%Y-%m-%dT%H:%M:%SZ')" +COMMIT="$(git rev-parse HEAD)" + +header() { + printf '# %s\n\nGenerated: %s\nCommit: %s\n\n' "$1" "$STAMP" "$COMMIT" +} + +echo "==> govulncheck (default build)" +{ + header "govulncheck, default build" + go run golang.org/x/vuln/cmd/govulncheck@latest ./... 2>&1 || true +} >"$OUT/govulncheck.txt" + +echo "==> govulncheck (kafka build)" +{ + header "govulncheck, kafka build variant" + printf 'The Avro codec is behind a build tag, so the default scan never compiles it.\n\n' + go run golang.org/x/vuln/cmd/govulncheck@latest -tags kafka ./... 2>&1 || true +} >"$OUT/govulncheck-kafka.txt" + +echo "==> pnpm audit per tree" +{ + header "Node production dependencies" + for tree in web admin site docs forms; do + printf '\n## %s\n\n```\n' "$tree" + (cd "$tree" && pnpm audit --audit-level=high --prod 2>&1) || true + printf '```\n' + done +} >"$OUT/node-audit.txt" + +echo "==> cargo audit" +{ + header "Rust dependencies" + if command -v cargo-audit >/dev/null 2>&1; then + (cd tracking && cargo audit 2>&1) || true + else + printf 'cargo-audit is not installed on this machine, so this scan did not run here.\n' + printf 'CI runs it on every dependency change: see the rust job in .github/workflows/security.yml.\n' + fi +} >"$OUT/rust-audit.txt" + +echo "==> mix hex.audit" +{ + header "Elixir dependencies" + if command -v mix >/dev/null 2>&1 && [ -d realtime/deps ]; then + (cd realtime && mix hex.audit 2>&1) || true + else + printf 'mix is unavailable or dependencies are not fetched, so this scan did not run here.\n' + printf 'Run: cd realtime && mix deps.get && mix hex.audit\n' + fi +} >"$OUT/elixir-audit.txt" + +echo "==> trivy" +{ + header "Trivy filesystem scan" + if command -v trivy >/dev/null 2>&1; then + trivy fs --scanners vuln --severity HIGH,CRITICAL . 2>&1 || true + else + printf 'trivy is not installed on this machine, so this scan did not run here.\n' + printf 'CI runs it on every dependency change: see the trivy job in .github/workflows/security.yml.\n' + fi +} >"$OUT/trivy.txt" + +echo +echo "Wrote:" +ls -1 "$OUT" +echo +echo "Still to attach by hand before submission:" +echo " - Qualys SSL Labs report per hostname in compliance/casa/scope.md" +echo " - Authenticated Burp Suite scan using the ADA scan configuration" diff --git a/site/public/_headers b/site/public/_headers new file mode 100644 index 000000000..f2b459a65 --- /dev/null +++ b/site/public/_headers @@ -0,0 +1,9 @@ +# Security response headers for the marketing site. Static pages, no +# credentials, but the site serves install.sh and cli.sh, so framing and +# content-type sniffing are both switched off. +/* + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() + Strict-Transport-Security: max-age=31536000; includeSubDomains diff --git a/site/public/install.sh b/site/public/install.sh index 88dae0466..f9f1c1939 100644 --- a/site/public/install.sh +++ b/site/public/install.sh @@ -1017,7 +1017,10 @@ derive() { URL_APP="https://$H_APP"; URL_API="https://$H_API"; URL_ADMIN="https://$H_ADMIN" URL_WS="wss://$H_WS/socket/websocket" TRACKING_DOMAIN="$H_TRACK"; FORMS_DOMAIN="$H_FORMS" - PHX_HOST="$H_WS"; CHECK_ORIGIN=true + PHX_HOST="$H_WS" + # The origins a browser connects FROM, which are the dashboard and + # the admin panel, not this service's own host. + CHECK_ORIGIN_HOSTS="$URL_APP,$URL_ADMIN" # Caddy sits on the same compose network, so the private ranges are # the honest answer here rather than a single container address that # changes on every recreate. @@ -1034,7 +1037,7 @@ derive() { TRACKING_DOMAIN="${WARMBLY_TRACKING_DOMAIN:-track.$HOSTNAME_ANSWER}" FORMS_DOMAIN="${WARMBLY_FORMS_DOMAIN:-forms.$HOSTNAME_ANSWER}" PHX_HOST=$(printf '%s' "$URL_WS" | sed -e 's|^wss\{0,1\}://||' -e 's|/.*$||') - CHECK_ORIGIN=true + CHECK_ORIGIN_HOSTS="$URL_APP,$URL_ADMIN" TRUSTED="$PROXY_CIDRS" BIND="127.0.0.1:" ;; @@ -1047,7 +1050,10 @@ derive() { TRACKING_DOMAIN="$HOSTNAME_ANSWER:$PORT_TRACKING" FORMS_DOMAIN="$HOSTNAME_ANSWER:$PORT_FORMS" PHX_HOST="$HOSTNAME_ANSWER" - CHECK_ORIGIN=false + # Plain HTTP on a LAN: the origin is whatever host the person typed, + # which this install cannot know, so the check stays off. The socket + # still requires a short-lived ticket, which is the actual control. + CHECK_ORIGIN_HOSTS="" # Nothing in front, so nothing may set X-Forwarded-For. Trusting a # proxy that is not there is how a rate limit gets bypassed. TRUSTED="" @@ -1113,7 +1119,7 @@ API_PUBLIC_URL=$URL_API CORS_ALLOW_ORIGINS=$CORS WEBSOCKET_URL=$URL_WS PHX_HOST=$PHX_HOST -CHECK_ORIGIN=$CHECK_ORIGIN +CHECK_ORIGIN_HOSTS=$CHECK_ORIGIN_HOSTS # Unset means campaign mail ships with no open pixel and unwrapped links. A # workspace that verifies its own domain against this one also serves its # recipients' unsubscribe link there; otherwise it stays on API_PUBLIC_URL. @@ -1566,33 +1572,52 @@ render_caddyfile() { } } +# Applied to every site below. HSTS is set here rather than per service +# because Caddy is the only thing terminating TLS: whatever it proxies to +# speaks plain HTTP on the compose network and cannot know the request +# arrived over TLS. Server header removed so the version is not advertised. +(warmbly_headers) { + header { + Strict-Transport-Security "max-age=31536000; includeSubDomains" + X-Content-Type-Options "nosniff" + Referrer-Policy "strict-origin-when-cross-origin" + -Server + } +} + $H_APP { + import warmbly_headers reverse_proxy web:80 } $H_ADMIN { + import warmbly_headers reverse_proxy admin:80 } $H_API { + import warmbly_headers reverse_proxy backend:8080 } CADDYFILE [ "$WANT_REALTIME" = 1 ] && cat < -

- Warmbly scales your B2B outreach so your business can grow bigger. You reach more of the right people, win more clients, and every month brings more conversations than the last. +

+ Warmbly warms your mailboxes, sends your campaigns, and triages every reply. Run it on our cloud or self-host the whole thing on yours.

@@ -192,22 +192,10 @@ const softwareJsonLd = { scaled, sitting straight on the sky. Below md the same desktop shot bleeds off the right edge instead of shrinking to a thumbnail. -->
-
+
- -
+
- -
-
- {plans.map((p, idx) => ( -
- {p.highlight && ( - - )} +
+ {plans.map((p) => ( +
-
-
-

{p.name}

- {p.highlight && ( - - Most popular - - )} + {p.highlight && ( + <> +
+
-

{p.summary}

+
+ Most popular +
+ + )} -
- +
+ {p.name} +
+

+ {p.summary} +

+ +
+ {p.price !== null ? ( + <> + + $ - {p.annual} + {p.annual} - {p.save && ( - {p.price} - )} -
-

- {p.save ? ( - / month · billed yearly - ) : ( - volume-based · contact sales - )} -

- {/* Rendered even when empty so every card's CTA sits on the - same line; Enterprise has no yearly saving to show. */} -

- {p.save && ( - Save {p.save} a year - )} -

- - {/* Daily send volume, the thing each tier actually buys. */} -
-
- - {p.sendsPerDay === Infinity ? '15,000+' : p.sendsPerDay.toLocaleString()} - - sends / day -
-
- -
-
- - - {p.cta} - - -
-
    - {p.features.map((f) => ( -
  • - - - - {f} -
  • - ))} -
-
+ / mo + + ) : ( + + Custom + + )} +
+
+ {p.price !== null ? ( + billed annually · 20% off + ) : ( + 'volume-based · contact sales' + )}
- ))} -
- -
-
- Free - $0 + + {p.cta} + + +
+
    + {p.features.map((f) => ( +
  • + + + + {f} +
  • + ))} +
+
-

- A hosted workspace with up to 10 mailboxes and warmup. No card, no time limit. Sending, the inbox and CRM unlock when you pick a plan. -

- - Start free - -
+ ))}
-

+

Applicable taxes are calculated from your billing address and shown before you pay. Where supported, business buyers can add their legal name and tax ID at checkout.

+ +

+ Rather run it yourself? Self-hosting is free, forever. Once Warmbly Cloud launches, link your instance and we run the + warmup for your mailboxes in the shared pool, free for up to 10 mailboxes and $15 a month for unlimited. + Everything else, sending, inbox, campaigns and data, stays on your server. +

-
-
- -
-
-
- - - Self-hosted - Apache 2.0 - - -

- Free to run.
We handle the warmup. -

-

- The whole platform costs nothing to self-host. When Warmbly Cloud launches, link your instance from Settings and the - mailboxes you choose warm up in the shared pool, with thousands of real mailboxes sending, replying and rescuing from spam. - Campaigns, contacts and inbox never leave your server. -

- -
- {selfHostFacts.map((f, i) => ( -
0 && 'sm:border-l sm:border-[color:var(--border)] sm:pl-4']}> -
{f.value}
-
{f.label}
-
- ))} -
- -
    -
  • - - Link in about a minute with a one-time code -
  • -
  • - - Only the mailbox credential travels, encrypted, for warmup -
  • -
  • - - Unenroll or disconnect any time; the cloud forgets it immediately -
  • -
- - -
- -
-
-
-
-
Warmup pool link
-
Free to start. Pay for the premium pool and better deliverability.
-
- - - Arrives with Warmbly Cloud - +
+
+
+
+
+
Self-hosted
+

+ Free to run. We handle the warmup. +

+

+ The whole platform is Apache 2.0 and costs nothing to self-host. When Warmbly Cloud launches, link your instance + from Settings and the mailboxes you choose warm up in the shared pool, with thousands of real mailboxes sending, + replying and rescuing from spam, while campaigns, contacts and inbox never leave your server. +

+
    +
  • Unlimited mailboxes, campaigns and contacts on your instance
  • +
  • Link in about a minute with a one-time code
  • +
  • Only the mailbox credential travels, encrypted, for warmup
  • +
  • Unenroll or disconnect any time; the cloud forgets it immediately
  • +
- -
- {poolTiers.map((t, idx) => ( -
0 && 'border-t sm:border-t-0 sm:border-l', - ]} - > - {t.highlight && ( - - )} -
-

{t.name}

- {t.highlight && ( - - Recommended - - )} -
-

{t.summary}

-
- {t.price} - {t.cadence} -
-
-
    - {t.features.map((f) => ( -
  • - - - - {f} -
  • - ))} -
+
+
+
+
Warmup pool · Free
+
$0
+
Up to 10 mailboxes warming in the pool.
+
+
+
Warmup pool · Unlimited
+
$15 / month
+
Unlimited mailboxes, paid tier partners first.
- ))} -
- - -
-
- - - - self-host - no clone · no compiler
-
-
$ curl -fsSL https://warmbly.com/install.sh | sh
-
- - Dashboard on http://localhost:8080 · link it from Settings -
+
@@ -606,7 +424,7 @@ const gh = ' { + // Swap text and drop it in from below inner.style.transition = 'none'; inner.style.transform = 'translateY(100%)'; inner.textContent = newValue; - inner.offsetHeight; // reflow + // Force reflow + inner.offsetHeight; inner.style.transition = 'transform 320ms cubic-bezier(0.34,1.56,0.64,1), opacity 220ms ease-out'; inner.style.transform = 'translateY(0)'; inner.style.opacity = '1'; @@ -742,47 +564,38 @@ const gh = ' { - const next = el.getAttribute(`data-${mode}`) || ''; - el.textContent = next; - el.classList.toggle('hidden', next === ''); - }); - - // Cadence text gets a soft fade-swap so it never just snaps. - document.querySelectorAll('.cadence').forEach((el) => { - const next = el.getAttribute(`data-${mode}`) || ''; - if (!next) return; - el.style.transition = 'opacity 180ms ease-out'; - el.style.opacity = '0'; + // Animate the small note line with a subtle fade + document.querySelectorAll('.plan-note').forEach((n) => { + const m = n.getAttribute('data-monthly-note'); + const a = n.getAttribute('data-annual-note'); + n.style.transition = 'opacity 180ms ease-out'; + n.style.opacity = '0'; setTimeout(() => { - el.textContent = next; - el.style.opacity = '1'; + n.textContent = mode === 'annual' ? a : m; + n.style.opacity = '1'; }, 180); }); } diff --git a/skills/warmbly-api/SKILL.md b/skills/warmbly-api/SKILL.md index 2cefc979d..dec7aefb8 100644 --- a/skills/warmbly-api/SKILL.md +++ b/skills/warmbly-api/SKILL.md @@ -20,6 +20,9 @@ export WARMBLY_API_URL=https://api.your-instance.com # omit for the hosted serv Keys are created in the dashboard under Settings > API keys, or with `warmblyctl apikey create` if you already hold a key with the API_KEYS scope. +Creating one in the dashboard asks you to confirm your password or a two-factor +code first; creating one with an existing key does not, because the key's scope +is already that grant. Everything you can do is bounded by the key's scopes; `warmblyctl me` shows who the key is and what it holds. On the local dev stack the seeded full-access key is `wmbly_seed_acme_owner_full_access_0000000000` with diff --git a/web/Dockerfile b/web/Dockerfile index 70c1d599d..67b0eae2a 100644 --- a/web/Dockerfile +++ b/web/Dockerfile @@ -49,6 +49,7 @@ RUN --mount=type=secret,id=sentry_auth_token,required=false \ # entrypoint renders /config.js from container env at startup. FROM nginx:1.27-alpine COPY nginx.conf /etc/nginx/conf.d/default.conf +COPY nginx-security-headers.conf /etc/nginx/warmbly-security-headers.conf RUN nginx -t COPY --from=build /app/dist /usr/share/nginx/html # public/ files keep their checkout mode through the build; on a filesystem diff --git a/web/nginx-security-headers.conf b/web/nginx-security-headers.conf new file mode 100644 index 000000000..280c2ea58 --- /dev/null +++ b/web/nginx-security-headers.conf @@ -0,0 +1,19 @@ +# Security response headers for the dashboard shell and its assets. +# +# This file is included once per location rather than set once at the server +# level, because nginx only inherits add_header from an outer block when the +# inner block declares none of its own. Every location here sets Cache-Control, +# so a server-level declaration would be silently dropped in exactly the places +# that serve the app. +# +# No script-src or connect-src: the API origin, the analytics host and the +# billing host are runtime configuration (config.js is rewritten by the +# container entrypoint), so an allowlist compiled into the image would break a +# self-host that points the dashboard somewhere else. What is pinned here is +# everything that does not depend on that configuration. +add_header X-Content-Type-Options "nosniff" always; +add_header X-Frame-Options "DENY" always; +add_header Referrer-Policy "strict-origin-when-cross-origin" always; +add_header Permissions-Policy "camera=(), microphone=(), geolocation=(), interest-cohort=()" always; +add_header Content-Security-Policy "frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self'" always; +add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; diff --git a/web/nginx.conf b/web/nginx.conf index f420e4bf7..271837d30 100644 --- a/web/nginx.conf +++ b/web/nginx.conf @@ -7,16 +7,24 @@ server { # SPA history fallback: unknown paths serve the app shell so client-side # routing works on hard reloads and deep links. location / { + include /etc/nginx/warmbly-security-headers.conf; try_files $uri $uri/ /index.html; } # Never cache the shell or the runtime config, so a redeploy or an env # change is picked up on the next load. The hashed assets they point to are # cached immutably below. - location = /index.html { add_header Cache-Control "no-store"; } - location = /config.js { add_header Cache-Control "no-store"; } + location = /index.html { + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "no-store" always; + } + location = /config.js { + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "no-store" always; + } location /assets/ { - add_header Cache-Control "public, max-age=31536000, immutable"; + include /etc/nginx/warmbly-security-headers.conf; + add_header Cache-Control "public, max-age=31536000, immutable" always; } } diff --git a/web/package.json b/web/package.json index fe3cb68e7..2b046aaee 100644 --- a/web/package.json +++ b/web/package.json @@ -85,6 +85,7 @@ "clsx": "^2.1.1", "cmdk": "^1.1.1", "date-fns": "^4.1.0", + "dompurify": "^3.4.15", "framer-motion": "^12.23.24", "html-to-image": "^1.11.13", "immer": "^11.1.3", @@ -98,7 +99,7 @@ "react-dom": "^19.1.1", "react-hook-form": "^7.71.1", "react-hot-toast": "^2.6.0", - "react-router-dom": "^7.18.1", + "react-router-dom": "^7.18.4", "react-turnstile": "^1.1.4", "sonner": "^2.0.7", "tailwind-merge": "^3.4.0", diff --git a/web/pnpm-lock.yaml b/web/pnpm-lock.yaml index d04944cec..5eaf104ff 100644 --- a/web/pnpm-lock.yaml +++ b/web/pnpm-lock.yaml @@ -215,6 +215,9 @@ importers: date-fns: specifier: ^4.1.0 version: 4.1.0 + dompurify: + specifier: ^3.4.15 + version: 3.4.15 framer-motion: specifier: ^12.23.24 version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -255,8 +258,8 @@ importers: specifier: ^2.6.0 version: 2.6.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react-router-dom: - specifier: ^7.18.1 - version: 7.18.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^7.18.4 + version: 7.18.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) react-turnstile: specifier: ^1.1.4 version: 1.1.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -2361,8 +2364,8 @@ packages: dom-accessibility-api@0.6.3: resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - dompurify@3.4.14: - resolution: {integrity: sha512-dVoH9z+MY+C9IilgGCk3YfFqjLi3fChm2OiKJMzh6axrJ5qwxqWaZamgmHrpv22CN/KdbZJuGEGgfQoL00LTdg==} + dompurify@3.4.15: + resolution: {integrity: sha512-EUBjM+B+lkDE41iE82DDSCfkoPGfXx8IxFxPMjNzm/Uk4xDet77rTN9wqlxlVg71kK7XGuUMv6wUxJUwwv+Xyw==} dotenv@17.4.2: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} @@ -3177,15 +3180,15 @@ packages: '@types/react': optional: true - react-router-dom@7.18.1: - resolution: {integrity: sha512-KaZh+X/6UtEp28x51AUYZDMg9NGoz2ja3dNHa+ta/tk40vCzKhQ/RypCWBMLbmDr6//E24Vv5uPsrqXFozdkAg==} + react-router-dom@7.18.4: + resolution: {integrity: sha512-yrfmJHIpDG7taCpqKjT1G5B6q3O2K+RN8/fgNf0lTjCwiPbQ0ei6vXX9ZjQR+7ld8Tr7Z5xmyMnZ8YJrphWQUw==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' react-dom: '>=18' - react-router@7.18.1: - resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} + react-router@7.18.4: + resolution: {integrity: sha512-PUPQcMhMGRAslLcvtlPz/kmzBEWPhLdgLFrL7pLNepBL6dX0lWj4WD2cUYVgYCuT3jxvghYFg81cDTj44DhetQ==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -5567,7 +5570,7 @@ snapshots: dom-accessibility-api@0.6.3: {} - dompurify@3.4.14: + dompurify@3.4.15: optionalDependencies: '@types/trusted-types': 2.0.7 @@ -6211,7 +6214,7 @@ snapshots: '@posthog/core': 1.50.5 '@posthog/types': 1.409.0 core-js: 3.50.0 - dompurify: 3.4.14 + dompurify: 3.4.15 fflate: 0.4.9 preact: 10.29.8 query-selector-shadow-dom: 1.0.1 @@ -6360,13 +6363,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.7 - react-router-dom@7.18.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + react-router-dom@7.18.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - react-router: 7.18.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react-router: 7.18.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react-router@7.18.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + react-router@7.18.4(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: cookie: 1.1.1 react: 19.2.0 diff --git a/web/public/_headers b/web/public/_headers new file mode 100644 index 000000000..33bbf28ba --- /dev/null +++ b/web/public/_headers @@ -0,0 +1,15 @@ +# Security response headers for the Cloudflare Pages deployment of the +# dashboard. The nginx image carries the same set in +# nginx-security-headers.conf; both exist because the hosted service serves the +# frontends from Pages while a self-host serves them from the image. +# +# No script-src or connect-src: the API origin is runtime configuration +# (config.js), so an allowlist fixed at build time would break an instance that +# points the dashboard elsewhere. +/* + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + Referrer-Policy: strict-origin-when-cross-origin + Permissions-Policy: camera=(), microphone=(), geolocation=(), interest-cohort=() + Content-Security-Policy: frame-ancestors 'none'; object-src 'none'; base-uri 'none'; form-action 'self' + Strict-Transport-Security: max-age=31536000; includeSubDomains diff --git a/web/src/app/app/emails/page.tsx b/web/src/app/app/emails/page.tsx index 4b0eee382..39f6bff81 100644 --- a/web/src/app/app/emails/page.tsx +++ b/web/src/app/app/emails/page.tsx @@ -525,12 +525,9 @@ function bulkRevocationNote(providers: Set): string { } // removeErrorMessage pulls the API's own explanation out of a failed request. -// The client's interceptor has already flattened the axios error into an -// AppError, so the message sits at the top; reading `response.data` here found -// nothing and every refusal showed as "couldn't be disconnected". function removeErrorMessage(err: unknown): string | undefined { - const message = (err as AppError | undefined)?.message; - return message || undefined; + const e = err as { response?: { data?: { message?: string } } }; + return e?.response?.data?.message; } function MailboxRow({ diff --git a/web/src/app/app/layout.tsx b/web/src/app/app/layout.tsx index 7654e9abc..3a8c38871 100644 --- a/web/src/app/app/layout.tsx +++ b/web/src/app/app/layout.tsx @@ -17,6 +17,7 @@ import AddEmailModal from "@/components/app/modals/AddEmailModal"; import ComposeWindow from "@/components/app/unibox/compose/ComposeWindow"; import PasskeyEnrollPrompt from "@/components/app/modals/PasskeyEnrollPrompt"; import PermissionDeniedModal from "@/components/app/modals/PermissionDeniedModal"; +import ReauthModal from "@/components/app/modals/ReauthModal"; export default function RootAppLayout() { const token = getToken(); @@ -57,6 +58,7 @@ export default function RootAppLayout() { + diff --git a/web/src/components/app/EmailEditor.tsx b/web/src/components/app/EmailEditor.tsx index 1efd403f1..bb8030aa4 100644 --- a/web/src/components/app/EmailEditor.tsx +++ b/web/src/components/app/EmailEditor.tsx @@ -25,6 +25,7 @@ import { RiText, RiCodeView, } from "@remixicon/react"; +import DOMPurify, { type Config as DOMPurifyConfig } from "dompurify"; import { useEffect, useRef, useState } from "react"; import { RiEyeLine } from "@remixicon/react"; import { cn } from "@/lib/utils"; @@ -68,6 +69,28 @@ function needsSource(html: string): boolean { return UNHOSTABLE_TAG.test(html) || EVENT_HANDLER.test(html); } +// needsSource decides which editing surface to show. It must not be the only +// thing standing between a signature and script execution, because a regex +// does not tokenise HTML the way the parser does: `` +// separates the attribute with a slash rather than whitespace, and +// `` hides the handler behind a `>` inside a +// quoted value. The parser accepts both; the pattern above matches neither. +// +// A signature is organisation data one teammate writes and another renders, so +// that is stored cross-user script in the dashboard. Everything assigned to a +// live element goes through the parser-based sanitizer instead. +const SIGNATURE_SANITIZE_CONFIG: DOMPurifyConfig = { + FORBID_TAGS: ["script", "style", "iframe", "object", "embed", "form", "base", "meta", "link"], + FORBID_ATTR: ["srcdoc", "formaction", "ping"], + ALLOW_DATA_ATTR: false, +}; + +function sanitizeForEditing(html: string): string { + // String(...) because the Trusted Types overload widens the return type; + // RETURN_TRUSTED_TYPE is not set, so this is already a string at runtime. + return String(DOMPurify.sanitize(html, SIGNATURE_SANITIZE_CONFIG)); +} + interface EmailEditorProps { id: string; htmlText: string; @@ -104,7 +127,10 @@ export default function EmailEditor({ useEffect(() => { if (sourceView || activeTab !== "html") return; const el = editorRef.current; - if (el && el.innerHTML !== htmlText) el.innerHTML = htmlText; + // Sanitized on the way in, not merely inspected: this is the assignment + // that would execute a handler the source-view heuristic missed. + const safe = sanitizeForEditing(htmlText); + if (el && el.innerHTML !== safe) el.innerHTML = safe; }, [htmlText, activeTab, sourceView]); const [urlPopover, setUrlPopover] = useState<"link" | "image" | null>(null); const [url, setUrl] = useState(""); diff --git a/web/src/components/app/modals/ReauthModal.tsx b/web/src/components/app/modals/ReauthModal.tsx new file mode 100644 index 000000000..ccafa0090 --- /dev/null +++ b/web/src/components/app/modals/ReauthModal.tsx @@ -0,0 +1,163 @@ +// Global "confirm it is you" prompt. +// +// Some changes need a fresh proof of identity, not just a live session: +// minting an API key, registering or removing a passkey, handing a workspace +// to someone else, scheduling a deletion. The backend answers those with +// `reauth_required` until the session has re-authenticated in the last few +// minutes. +// +// The API client dispatches a `reauth-required` event carrying resolve and +// reject, waits for one of them, and retries the original request on success. +// That way every gated action gets the prompt without each call site knowing +// about it. + +import React from "react"; +import { AnimatePresence, motion } from "framer-motion"; +import { ShieldCheckIcon, XIcon } from "lucide-react"; + +import reauth from "@/lib/api/client/auth/reauth"; + +interface ReauthDetail { + resolve: () => void; + reject: () => void; +} + +export default function ReauthModal() { + const [pending, setPending] = React.useState(null); + const [password, setPassword] = React.useState(""); + const [code, setCode] = React.useState(""); + const [error, setError] = React.useState(""); + const [busy, setBusy] = React.useState(false); + + React.useEffect(() => { + const handler = (e: Event) => { + setPassword(""); + setCode(""); + setError(""); + setBusy(false); + setPending((e as CustomEvent).detail); + }; + window.addEventListener("reauth-required", handler); + return () => window.removeEventListener("reauth-required", handler); + }, []); + + const cancel = React.useCallback(() => { + pending?.reject(); + setPending(null); + }, [pending]); + + async function submit(e: React.FormEvent) { + e.preventDefault(); + if (busy || !pending) return; + setBusy(true); + setError(""); + try { + await reauth({ password: password || undefined, code: code || undefined }); + pending.resolve(); + setPending(null); + } catch (err) { + const code = (err as { code?: string } | undefined)?.code; + if (code === "reauth_no_factor") { + // An account created through Google, Apple or SSO has nothing + // to confirm with until it adds one. Say what to do; the + // generic message below would be a dead end. + setError( + (err as { message?: string }).message ?? + "This account has nothing to confirm with yet. Turn on two-factor authentication under Settings > Security.", + ); + } else { + // Otherwise one message: which factor matched is not something + // to spell out to whoever is sitting at the keyboard. + setError("That did not match. Try again."); + } + setBusy(false); + } + } + + return ( + + {pending && ( + { + if (e.target === e.currentTarget) cancel(); + }} + > + e.stopPropagation()} + className="w-full max-w-sm rounded-lg border border-slate-200 bg-white p-5 shadow-xl" + > +
+
+ +
+
+

Confirm it is you

+

+ This change needs a fresh check. Enter your password, or a code from + your authenticator. +

+
+ +
+ +
+ setPassword(e.target.value)} + placeholder="Password" + autoComplete="current-password" + autoFocus + className="h-9 w-full rounded-md border border-slate-200 px-2.5 text-[12.5px] outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100" + /> + setCode(e.target.value)} + placeholder="Two-factor or recovery code" + inputMode="text" + autoComplete="one-time-code" + data-ph-mask="" + className="h-9 w-full rounded-md border border-slate-200 px-2.5 text-[12.5px] outline-none focus:border-sky-400 focus:ring-2 focus:ring-sky-100" + /> +
+ + {error &&

{error}

} + +
+ + +
+
+
+ )} +
+ ); +} diff --git a/web/src/components/layout/ErrorBoundary.tsx b/web/src/components/layout/ErrorBoundary.tsx index d8017f3f7..045a91c41 100644 --- a/web/src/components/layout/ErrorBoundary.tsx +++ b/web/src/components/layout/ErrorBoundary.tsx @@ -72,7 +72,7 @@ function BoundaryFallback({ error, info, reset }: { error: Error; info: React.Er
- This page couldn't be displayed. Your data is safe. + {error.message || "Something broke while rendering this page"}
- {/* A render fault has no fix the reader can apply, and the - exception's own text ("Cannot read properties of - undefined") describes our bug in our words. So the panel - says what is true of their work and what to try, and the - exact error stays one click away under Stack for anyone - who wants it. It has already been reported either way. */} -

- Nothing you were working on was lost, and the rest of Warmbly is unaffected. - Retry redraws this page; if it keeps failing, go back and open it again. +

+ {error.message || "No message provided."}

-

- The fault was reported to our team automatically. -

-
- - Stack - -
-                            {/* A stack normally opens with "Name: message", but
-                                not in every browser, so the pair is printed
-                                whenever the stack does not carry it. It is the
-                                one thing worth copying. */}
-                            {error.stack?.startsWith(error.name)
-                                ? error.stack
-                                : `${error.name || "Error"}: ${error.message || "no message"}\n${error.stack || ""}`}
-                            {info?.componentStack ? `\n\nComponent stack:${info.componentStack}` : ""}
-                        
-
+ {(error.stack || info?.componentStack) && ( +
+ + Stack + +
+                                {error.stack || ""}
+                                {info?.componentStack ? `\n\nComponent stack:${info.componentStack}` : ""}
+                            
+
+ )}
diff --git a/web/src/components/ui/input-otp.tsx b/web/src/components/ui/input-otp.tsx index 4e8ca53a9..290d2aff2 100644 --- a/web/src/components/ui/input-otp.tsx +++ b/web/src/components/ui/input-otp.tsx @@ -51,6 +51,12 @@ function InputOTPSlot({
{ }, [queryClient]); if (error?.redirect) { - clearTokens(); + // Same teardown as an explicit sign-out: being signed out must not + // leave the previous person's drafts and workspace selection behind. + clearClientSession(queryClient); return ; } diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 0a251a733..2f70134a6 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -55,6 +55,9 @@ export const refreshToken = async () => { }) if (!resp.ok) { const { error } = await resp.json() + // The server has refused this pair, so keeping it only means every later + // call retries a token that is already revoked. + deleteTokens(); if (resp.status === 400) { throw new UnauthorizedError(error) } else { @@ -62,73 +65,25 @@ export const refreshToken = async () => { } } else { const data = await resp.json() - console.log('Refreshed tokens', data); + // Deliberately not logged. Console output is captured into session replay, + // so printing the response put both the access and the refresh token into + // a recording in plaintext. saveTokens(data) } } export class UnauthorizedError extends Error { } - -/** What the API answers a failure with: a title, a sentence written for the - * person reading it, a stable machine-readable code, and the request id an - * operator can find the server-side log line by. */ -export interface APIErrorBody { - error?: string; - message: string; - code?: string; - request_id?: string; -} - -export class APIError extends Error { +export class APIError extends Error { status: number; - /** Always an object with a non-empty `message`, so a caller rendering - * `body.message` as the detail line never shows an empty one. A proxy 502, - * an HTML error page and a dropped connection all answer with no JSON at - * all, and each of those used to reach the user as a blank explanation - * under a bare "Internal Server Error". */ - body: T; - /** Stable condition identifier, for branching rather than display. */ - code?: string; - requestId?: string; - constructor(message: string, status: number, body: T) { + body?: T; + constructor(message: string, status: number, body?: T) { super(message); this.status = status; this.body = body; - this.code = body.code; - this.requestId = body.request_id; } } -/** The sentence to show when the response carried none of its own. Each names - * what the person can do about it rather than restating the status code. */ -function fallbackMessage(status: number): string { - if (status === 0) return "We couldn't reach the server. Check your connection and try again."; - if (status === 401) return "Your session has expired. Sign in again to continue."; - if (status === 403) return "You don't have permission to do that."; - if (status === 404) return "That item no longer exists. It may have been deleted."; - if (status === 409) return "Someone else changed this first. Reload the page and try again."; - if (status === 413) return "That file is too large to upload."; - if (status === 429) return "You're going a little fast. Wait a moment and try again."; - if (status === 503) return "The service is temporarily unavailable. Try again in a moment."; - if (status >= 500) return "Something went wrong on our end. Nothing was changed. Try again in a moment."; - return "The request couldn't be completed. Check the details and try again."; -} - -/** Reads the API's error envelope off a response, whatever it turned out to - * be. A body that is not JSON (a proxy's HTML error page) or that is JSON - * without our envelope both end up with a usable message rather than - * `undefined`. */ -async function errorBody(res: Response): Promise { - const raw: unknown = await res.json().catch(() => null); - const parsed = (raw && typeof raw === "object" ? raw : {}) as Partial; - return { - ...parsed, - error: parsed.error || res.statusText || "Request failed", - message: parsed.message || fallbackMessage(res.status), - }; -} - type FetchMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; export async function Call( @@ -136,10 +91,6 @@ export async function Call( method: FetchMethod = 'GET', body?: object, nocontent = false, - // retried is set by the one 401 retry below. A second 401 after a successful - // refresh means the token is not the problem, and recursing on it spun a tab - // through the endpoint until the user closed it. - retried = false, ) { if (isTokenExpired()) { await refreshToken(); @@ -147,34 +98,23 @@ export async function Call( const token = localStorage.getItem('access_token'); - let res: Response; - try { - res = await fetch(`${API_BASE_URL}${endpoint}`, { - method, - headers: { - 'Content-Type': 'application/json', - ...(token && { Authorization: `Bearer ${token}` }), - }, - ...(body && { body: JSON.stringify(body) }), - }); - } catch { - // fetch only rejects when the request never got an answer: offline, DNS, - // TLS, CORS, or a cancelled navigation. It reached the user as the raw - // "TypeError: Failed to fetch", which reads as a bug in the app rather - // than as a connection that dropped. - throw new APIError('Network Error', 0, { - error: 'Network Error', - message: fallbackMessage(0), - }); - } + const res = await fetch(`${API_BASE_URL}${endpoint}`, { + method, + headers: { + 'Content-Type': 'application/json', + ...(token && { Authorization: `Bearer ${token}` }), + }, + ...(body && { body: JSON.stringify(body) }), + }); if (!res.ok) { - if (res.status === 401 && !retried) { + const msg = await res.json().catch(() => ({})); + + if (res.status === 401) { await refreshToken(); - return await Call(endpoint, method, body, nocontent, true); + return await Call(endpoint, method, body) } - const msg = await errorBody(res); throw new APIError(msg.error || 'Request failed', res.status, msg); } if (!nocontent) { diff --git a/web/src/lib/api/client/Request.ts b/web/src/lib/api/client/Request.ts index 2c8e894b1..0bd025e3d 100644 --- a/web/src/lib/api/client/Request.ts +++ b/web/src/lib/api/client/Request.ts @@ -12,8 +12,54 @@ import type Token from "@/lib/api/models/auth/Token"; interface AuthRequestConfig extends AxiosRequestConfig { authorization?: boolean + // Set on the re-authentication call itself, so a wrong password there + // reaches the caller instead of reopening the prompt that made it. + skipReauthPrompt?: boolean } +// promptForReauth opens the global "confirm it is you" dialog and resolves when +// the person confirms, rejects when they cancel. +// +// Some changes need a proof of identity newer than the session: minting an API +// key, registering a passkey, transferring a workspace, scheduling a deletion. +// Handling it here means every one of those retries automatically once the +// prompt is satisfied, rather than each call site growing its own dialog. +function promptForReauth(): Promise { + if (typeof window === "undefined") return Promise.reject(new Error("no window")); + return new Promise((resolve, reject) => { + let settled = false; + const once = (fn: () => void) => () => { + if (settled) return; + settled = true; + fn(); + }; + + // ReauthModal is mounted under the /app layout. A gated call made from + // outside that tree would otherwise leave this promise pending forever + // and the mutation spinning with nothing on screen, so a listener that + // never answers is treated as a refusal. + const timer = window.setTimeout( + once(() => reject(new Error("no confirmation prompt is available here"))), + REAUTH_PROMPT_TIMEOUT_MS, + ); + const finish = (fn: () => void) => + once(() => { + window.clearTimeout(timer); + fn(); + }); + + window.dispatchEvent( + new CustomEvent("reauth-required", { + detail: { resolve: finish(resolve), reject: finish(() => reject(new Error("cancelled"))) }, + }), + ); + }); +} + +// Long enough for someone to find their authenticator, short enough that a +// missing prompt surfaces as an error rather than a hang. +const REAUTH_PROMPT_TIMEOUT_MS = 2 * 60 * 1000; + // Refresh lock: only one refresh at a time, others wait for it let refreshPromise: Promise | null = null; @@ -94,6 +140,20 @@ export default async function Request(config: AuthRequestConfig): Promise } } + // A change that needs a fresher proof of identity: prompt, then retry + // once. Checked before the generic 403 branch below so it gets its own + // dialog rather than the permission-denied one. + if ( + appErr?.code === "reauth_required" && + config.authorization && + !config.skipReauthPrompt && + typeof window !== "undefined" + ) { + await promptForReauth(); + const res = await Client.request(config); + return reviveDates(res.data); + } + // A denied WRITE action (edit/save/delete) gets one clear, app-wide // popup explaining the missing permission (or plan). Reads that 403 are // intentionally left to page-level gating (locked surfaces / NoAccess), diff --git a/web/src/lib/api/client/auth/reauth.ts b/web/src/lib/api/client/auth/reauth.ts new file mode 100644 index 000000000..73cfd800c --- /dev/null +++ b/web/src/lib/api/client/auth/reauth.ts @@ -0,0 +1,25 @@ +import Request from "../Request"; + +interface ReauthBody { + password?: string; + code?: string; +} + +interface ReauthResponse { + valid_for_seconds: number; +} + +// Re-prove the account holder behind the current session. The backend stamps +// the session, and the actions that require a fresh check accept it for the +// window it returns. +export default function reauth(body: ReauthBody) { + return Request({ + method: "post", + url: "/auth/reauth", + data: body, + authorization: true, + // Never retried through the reauth prompt: this IS the prompt, and a + // failure here means the credential was wrong. + skipReauthPrompt: true, + }); +} diff --git a/web/src/lib/api/client/normalizeError.ts b/web/src/lib/api/client/normalizeError.ts index 90acf66c2..318d8cf9c 100644 --- a/web/src/lib/api/client/normalizeError.ts +++ b/web/src/lib/api/client/normalizeError.ts @@ -12,49 +12,6 @@ export interface AppError { /** Correlation id the API already returns, so a user can quote it and an * operator can find the matching server-side log line. */ request_id?: string; - /** Seconds the API asked us to wait, from Retry-After on a 429 or 503. - * Surfaced so a message can name the wait instead of guessing at one. */ - retry_after?: number; -} - -/** The API's error envelope, or as much of it as arrived. - * - * A response body is not always ours: a proxy in front of the API answers a - * 502 with an HTML page, a gateway timeout can carry nothing at all, and a - * request for a file gets a Blob. Reading `.error` straight off any of those - * produced either `undefined` in the message or, for a null body, a TypeError - * thrown from inside the error handler itself. */ -function envelope(data: unknown): { error?: string; message?: string; code?: string; request_id?: string } { - if (!data || typeof data !== "object" || Array.isArray(data)) return {}; - return data as { error?: string; message?: string; code?: string; request_id?: string }; -} - -/** What to say when the response carried no message of its own. Each one names - * what the reader can do next rather than restating the status. */ -function fallback(status: number): string { - switch (status) { - case 401: return "Your session has expired. Sign in again to continue."; - case 403: return "You don't have permission to do that."; - case 404: return "That item no longer exists. It may have been deleted."; - case 409: return "Someone else changed this first. Reload the page and try again."; - case 413: return "That file is too large to upload."; - case 429: return "You're going a little fast. Wait a moment and try again."; - case 502: - case 504: return "The server didn't answer in time. Try again in a moment."; - case 503: return "Warmbly is temporarily unavailable. Try again in a moment."; - } - if (status >= 500) return "Something went wrong on our end. Try again in a moment."; - return "The request couldn't be completed. Check the details and try again."; -} - -/** Retry-After is either a number of seconds or an HTTP date. */ -function retryAfter(header: unknown): number | undefined { - if (typeof header !== "string" || header === "") return undefined; - const seconds = Number(header); - if (Number.isFinite(seconds)) return Math.max(0, Math.round(seconds)); - const at = Date.parse(header); - if (Number.isNaN(at)) return undefined; - return Math.max(0, Math.round((at - Date.now()) / 1000)); } export function normalizeError(error: unknown): AppError { @@ -69,59 +26,38 @@ export function normalizeError(error: unknown): AppError { if (axios.isAxiosError(error)) { if (!error.response) { - // No answer at all: offline, DNS, TLS, CORS, a cancelled - // navigation, or a timeout we set ourselves. The browser's own - // wording for all of these is "Network Error", which reads as a - // fault in the app rather than in the connection. - if (error.code === "ECONNABORTED" || error.code === "ETIMEDOUT") { - return { - error: "Timed Out", - message: "That took too long to answer. Try again in a moment.", - }; - } - if (typeof navigator !== "undefined" && navigator.onLine === false) { - return { - error: "Offline", - message: "You're offline. Reconnect and try again; nothing was saved.", - }; - } + // network, CORS, or timeout return { error: "Network Error", - message: "We couldn't reach Warmbly. Check your connection and try again.", + message: "Please check your connection.", }; } const status = error.response.status; - const data = envelope(error.response.data); - const wait = retryAfter(error.response.headers?.["retry-after"]); + const data = error.response.data; - let message = data.message || fallback(status); - // A wait the server named beats one the reader has to guess at. - if (wait !== undefined && !data.message && (status === 429 || status === 503)) { - message = wait > 60 - ? `Too many requests. Try again in about ${Math.ceil(wait / 60)} minutes.` - : `Too many requests. Try again in ${Math.max(wait, 1)} seconds.`; + if (status === 401) { + return { + error: data.error || "Unauthorized", + message: data.message || "Your session is invalid or expired.", + status, + redirect: true, + code: data.code, + request_id: data.request_id, + }; } return { - error: data.error || (status === 401 ? "Unauthorized" : "Unknown Error"), - message, + error: data.error || "Unknown Error", + message: data.message || "Unexpected error occured.", status, - ...(status === 401 ? { redirect: true } : {}), code: data.code, request_id: data.request_id, - ...(wait !== undefined ? { retry_after: wait } : {}), - }; - } - - // Anything that is not an axios failure still reached a catch block that - // has to render something. A thrown Error at least knows what it was. - if (error instanceof Error && error.message) { - return { error: error.name || "Unknown Error", message: error.message }; + } } return { error: "Unknown Error", - message: "Something went wrong. Try again, and reload the page if it keeps happening.", + message: "Unexpected error occurred.", }; } diff --git a/web/src/lib/api/hooks/auth/useLogout.ts b/web/src/lib/api/hooks/auth/useLogout.ts index 48efb1618..596550aaf 100644 --- a/web/src/lib/api/hooks/auth/useLogout.ts +++ b/web/src/lib/api/hooks/auth/useLogout.ts @@ -1,7 +1,6 @@ import { useMutation, useQueryClient } from "@tanstack/react-query"; import logout from "../../client/auth/logout"; -import { clearTokens } from "@/lib/auth"; -import { useAppStore } from "@/stores"; +import { clearClientSession } from "@/lib/session"; // Single source of truth for "log this user out fully". Order matters: // @@ -32,19 +31,8 @@ export default function useLogout() { // the backend hiccuped. } }, - onSettled: () => { - clearTokens(); - queryClient.clear(); - - const store = useAppStore.getState(); - store.logout(); - store.setOrganizations([]); - store.setCurrentOrganization(null); - - // Drop persisted slices (currentOrganization, theme, etc.). - // Theme will re-hydrate from the system preference on next - // mount, which is the right default for a fresh session. - useAppStore.persist.clearStorage(); - }, + // Shared with the session-expiry paths, so signing out and being signed + // out leave the browser in the same state. + onSettled: () => clearClientSession(queryClient), }); } diff --git a/web/src/lib/auth.ts b/web/src/lib/auth.ts index bbf9d534f..5dde2e6d4 100644 --- a/web/src/lib/auth.ts +++ b/web/src/lib/auth.ts @@ -54,7 +54,38 @@ export const saveTokens = (data: Record) => { } } +// Everything written to browser storage that belongs to the signed-in person +// rather than to the browser. Prefix-matched because the keys embed ids. +// +// Reply drafts are the reason this exists: a draft holds the full body, +// subject and recipients of an unsent email, keyed by user, org and thread, and +// it survived signing out on a shared machine. Column widths and dismissed +// banners are deliberately not here; they are not the user's data. +const SESSION_SCOPED_KEY_PREFIXES = [ + "warmbly-reply-draft:", +]; + +const SESSION_SCOPED_KEYS = [ + "sso_binding", +]; + +// clearTokens ends the client's half of the session: the tokens, and the +// content those tokens were used to fetch. Called from logout and from every +// path that discovers the session is gone, so neither leaves the other behind. export const clearTokens = () => { TOKENS.forEach((k) => localStorage.removeItem(k)); + SESSION_SCOPED_KEYS.forEach((k) => { + localStorage.removeItem(k); + sessionStorage.removeItem(k); + }); + + // Collect first, then remove: removing while iterating shifts the indices. + const stale: string[] = []; + for (let i = 0; i < localStorage.length; i++) { + const key = localStorage.key(i); + if (key && SESSION_SCOPED_KEY_PREFIXES.some((p) => key.startsWith(p))) stale.push(key); + } + stale.forEach((k) => localStorage.removeItem(k)); + setToken(null); } diff --git a/web/src/lib/observability.ts b/web/src/lib/observability.ts index 349823e19..b94bcdacf 100644 --- a/web/src/lib/observability.ts +++ b/web/src/lib/observability.ts @@ -83,7 +83,13 @@ export function initErrorReporting(): void { .then((Sentry) => { Sentry.init({ dsn: SENTRY_DSN, - sendDefaultPii: true, + // Off deliberately. The user id, email and name are + // attached below through setUser, which is the identity an + // exception needs. sendDefaultPii adds request headers, + // cookies and bodies on top of that, and an Authorization + // header in a crash report is a session handed to whoever + // can read the project. + sendDefaultPii: false, environment: SENTRY_ENVIRONMENT, // Empty is omitted rather than sent: an event tagged with // the empty release matches no uploaded source map and diff --git a/web/src/lib/posthog.ts b/web/src/lib/posthog.ts index 1997ad28d..dd1310fb7 100644 --- a/web/src/lib/posthog.ts +++ b/web/src/lib/posthog.ts @@ -80,13 +80,20 @@ export function loadPostHog(): Promise { capture_performance: { web_vitals: true, network_timing: true }, disable_session_recording: !POSTHOG_SESSION_REPLAY, session_recording: { - // Only what is typed into a password field is hidden. A - // mailbox's app password and an API secret are both - // password inputs, so that is exactly the credential set. + // Password inputs cover the mailbox app password and the + // API secret. They do not cover the one-time codes, which + // are plain inputs so the browser will autofill them from + // SMS and mail, nor a secret the page has already revealed + // as text. Those carry data-ph-mask / .ph-mask and are + // named here. maskAllInputs: false, maskInputOptions: { password: true }, + maskTextSelector: "[data-ph-mask], .ph-mask, [data-otp-input], input[autocomplete='one-time-code']", }, - enable_recording_console_log: true, + // Console output is replayed alongside the session, so anything + // printed is retained. Off: it is not worth one careless log of + // a token, and exceptions are captured separately below. + enable_recording_console_log: false, respect_dnt: false, capture_exceptions: POSTHOG_ERROR_TRACKING ? { diff --git a/web/src/lib/session.ts b/web/src/lib/session.ts new file mode 100644 index 000000000..d53282eb1 --- /dev/null +++ b/web/src/lib/session.ts @@ -0,0 +1,28 @@ +import type { QueryClient } from "@tanstack/react-query"; + +import { clearTokens } from "./auth"; +import { useAppStore } from "@/stores/useAppStore"; + +// clearClientSession drops everything the signed-in person left in this +// browser: tokens, drafts, the persisted workspace selection, and the fetched +// data in the query cache. +// +// It exists because logout did all of this and the session-expiry paths did +// only the first part, so a 401 left the previous person's workspace id, and +// their unsent reply drafts, on disk for whoever used the machine next. +// +// queryClient is optional: some callers run outside the provider. +export function clearClientSession(queryClient?: QueryClient) { + clearTokens(); + queryClient?.clear(); + + const store = useAppStore.getState(); + store.logout(); + store.setOrganizations([]); + store.setCurrentOrganization(null); + + // Drop persisted slices (currentOrganization, theme, etc.). Theme + // re-hydrates from the system preference on next mount, which is the right + // default for a fresh session. + useAppStore.persist.clearStorage(); +}