From a6727f1232366c0ac35e7867172a185fd8fc58a9 Mon Sep 17 00:00:00 2001 From: dextmorgn Date: Tue, 20 May 2025 14:46:37 +0200 Subject: [PATCH] feat: no supabase dependency --- .env.example | 132 +- backend/.env.example | 135 - backend/.gitignore | 5 - backend/dev/data.sql | 48 - backend/dev/docker-compose.dev.yml | 34 - backend/supabase/.gitignore | 8 - backend/supabase/config.toml | 308 -- .../20250412163409_remote_schema.sql | 2533 ----------------- backend/volumes/api/kong.yml | 241 -- backend/volumes/db/_supabase.sql | 3 - backend/volumes/db/jwt.sql | 5 - backend/volumes/db/logs.sql | 6 - backend/volumes/db/pooler.sql | 6 - backend/volumes/db/realtime.sql | 4 - backend/volumes/db/roles.sql | 8 - backend/volumes/db/webhooks.sql | 208 -- backend/volumes/functions/hello/index.ts | 16 - backend/volumes/functions/main/index.ts | 94 - backend/volumes/logs/vector.yml | 232 -- backend/volumes/pooler/pooler.exs | 30 - docker-compose.override.yml | 130 - docker-compose.yml | 539 +--- flowsint-api/.env.development | 7 + flowsint-api/{app/neo4j => }/__init__.py | 0 flowsint-api/alembic.ini | 38 + flowsint-api/alembic/README | 1 + flowsint-api/alembic/env.py | 61 + flowsint-api/alembic/script.py.mako | 28 + ...dd_email_and_hashed_password_to_profile.py | 38 + ...dd_relationship_between_investigations_.py | 32 + .../965b56353b4c_initial_migration.py | 151 + ...dd_relationship_between_investigations_.py | 32 + flowsint-api/app/api/deps.py | 34 + flowsint-api/app/api/routes/auth.py | 35 + flowsint-api/app/api/routes/investigations.py | 81 + flowsint-api/app/api/routes/sketches.py | 81 +- flowsint-api/app/api/routes/transforms.py | 113 +- .../app/api/schemas/__init__.py | 0 flowsint-api/app/api/schemas/base.py | 6 + flowsint-api/app/api/schemas/feedback.py | 14 + flowsint-api/app/api/schemas/investigation.py | 38 + .../app/api/schemas/investigation_profiles.py | 16 + flowsint-api/app/api/schemas/log.py | 27 + flowsint-api/app/api/schemas/profile.py | 14 + flowsint-api/app/api/schemas/scan.py | 19 + flowsint-api/app/api/schemas/sketch.py | 62 + flowsint-api/app/api/schemas/transform.py | 26 + flowsint-api/app/core/auth.py | 153 +- flowsint-api/app/core/celery.py | 14 +- flowsint-api/app/core/db.py | 19 - .../{neo4j/connector.py => core/graph_db.py} | 13 +- flowsint-api/app/core/logger.py | 68 +- flowsint-api/app/core/postgre_db.py | 21 + flowsint-api/app/main.py | 27 +- flowsint-api/app/models/__init__.py | 0 flowsint-api/app/models/base.py | 4 + flowsint-api/app/models/models.py | 138 + flowsint-api/app/scanners/base.py | 71 +- flowsint-api/app/scanners/domains/resolve.py | 1 - .../app/scanners/domains/subdomains.py | 21 +- flowsint-api/app/scanners/emails/holehe.py | 4 +- .../app/scanners/ips/reverse_resolve.py | 3 +- flowsint-api/app/scanners/orchestrator.py | 35 +- flowsint-api/app/scanners/socials/maigret.py | 3 +- flowsint-api/app/tasks/transform.py | 87 +- flowsint-api/branches.json | 36 - flowsint-api/requirements.txt | 7 +- flowsint-web/middleware.ts | 2 - flowsint-web/package.json | 4 +- .../src/app/api/auth/[...nextauth]/route.ts | 2 + .../[investigation_id]/documents/route.ts | 77 - .../individuals/[individual_id]/route.ts | 37 - .../[investigation_id]/route.ts | 30 - .../sketches/[sketch_id]/route.ts | 32 - .../[sketch_id]/scans/[scan_id]/route.ts | 28 - .../sketches/[sketch_id]/scans/route.ts | 27 - .../sketches/[sketch_id]/sketch/route.ts | 26 - .../[investigation_id]/sketches/route.ts | 27 - .../src/app/api/investigations/route.ts | 24 - .../src/app/api/latest-sketches/route.ts | 27 - .../src/app/api/metrics/global/route.ts | 34 - .../app/api/profiles/[profile_id]/route.ts | 27 - flowsint-web/src/app/api/profiles/route.ts | 25 - flowsint-web/src/app/api/transforms/route.ts | 32 - flowsint-web/src/app/auth/callback/route.ts | 30 - flowsint-web/src/app/auth/confirm/route.ts | 27 - .../[investigation_id]/layout.tsx | 12 +- .../[investigation_id]/page.tsx | 42 +- .../sketches/[sketch_id]/client.tsx | 11 +- .../sketches/[sketch_id]/console-panel.tsx | 92 +- .../sketches/[sketch_id]/page.tsx | 19 +- .../sketches/[sketch_id]/toolbar.tsx | 11 - .../src/app/dashboard/investigations/page.tsx | 17 +- flowsint-web/src/app/dashboard/layout.tsx | 16 +- flowsint-web/src/app/dashboard/page.tsx | 191 +- .../transforms/[transform_id]/page.tsx | 18 +- .../app/dashboard/transforms/editor/page.tsx | 13 +- .../src/app/dashboard/transforms/page.tsx | 14 +- flowsint-web/src/app/login/page.tsx | 10 +- flowsint-web/src/app/page.tsx | 10 +- flowsint-web/src/app/providers.tsx | 9 +- flowsint-web/src/app/register/page.tsx | 16 + flowsint-web/src/auth.ts | 60 + .../src/components/dashboard/feedback.tsx | 6 +- .../dashboard/new-investigation.tsx | 2 - .../components/dashboard/recent-sketches.tsx | 13 +- .../components/dashboard/secondary-nav.tsx | 2 +- .../components/investigations/file-upload.tsx | 215 -- .../investigations/investigation-selector.tsx | 11 +- flowsint-web/src/components/login-form.tsx | 29 +- flowsint-web/src/components/nav-user.tsx | 80 +- flowsint-web/src/components/register-form.tsx | 41 + .../components/sketches/add-contributor.tsx | 21 +- .../src/components/sketches/more-menu.tsx | 9 +- .../sketches/scans-drawer/scan-button.tsx | 152 - .../sketches/scans-drawer/scan-table.tsx | 61 - .../components/sketches/sketch-navigation.tsx | 90 - .../components/sketches/sketch-selector.tsx | 22 +- .../sketches/sketch/launch-transform.tsx | 14 +- .../sketch/nodes/node-notes-editor.tsx | 6 +- .../src/components/transforms/editor.tsx | 66 +- .../transforms/flow-computation-drawer.tsx | 15 +- .../transforms/transform-name-panel.tsx | 8 +- .../src/components/ui/custom-edge.tsx | 126 - flowsint-web/src/components/ui/input.tsx | 2 +- flowsint-web/src/hooks/use-transforms.ts | 17 - flowsint-web/src/lib/actions/auth.ts | 82 +- .../src/lib/actions/investigations.ts | 22 +- flowsint-web/src/lib/actions/sketches.ts | 67 +- flowsint-web/src/lib/actions/transform.ts | 26 +- flowsint-web/src/lib/client-fetch.ts | 41 + flowsint-web/src/lib/hooks/sketches.ts | 34 - flowsint-web/src/lib/server-fetch.ts | 47 + flowsint-web/src/lib/supabase/client.ts | 7 - flowsint-web/src/lib/supabase/middleware.ts | 65 - flowsint-web/src/lib/supabase/server.ts | 43 - flowsint-web/src/middleware.ts | 2 - flowsint-web/yarn.lock | 153 +- package.json | 5 +- 139 files changed, 1852 insertions(+), 7233 deletions(-) delete mode 100644 backend/.env.example delete mode 100644 backend/.gitignore delete mode 100644 backend/dev/data.sql delete mode 100644 backend/dev/docker-compose.dev.yml delete mode 100644 backend/supabase/.gitignore delete mode 100644 backend/supabase/config.toml delete mode 100644 backend/supabase/migrations/20250412163409_remote_schema.sql delete mode 100644 backend/volumes/api/kong.yml delete mode 100644 backend/volumes/db/_supabase.sql delete mode 100644 backend/volumes/db/jwt.sql delete mode 100644 backend/volumes/db/logs.sql delete mode 100644 backend/volumes/db/pooler.sql delete mode 100644 backend/volumes/db/realtime.sql delete mode 100644 backend/volumes/db/roles.sql delete mode 100644 backend/volumes/db/webhooks.sql delete mode 100644 backend/volumes/functions/hello/index.ts delete mode 100644 backend/volumes/functions/main/index.ts delete mode 100644 backend/volumes/logs/vector.yml delete mode 100644 backend/volumes/pooler/pooler.exs delete mode 100644 docker-compose.override.yml create mode 100644 flowsint-api/.env.development rename flowsint-api/{app/neo4j => }/__init__.py (100%) create mode 100644 flowsint-api/alembic.ini create mode 100644 flowsint-api/alembic/README create mode 100644 flowsint-api/alembic/env.py create mode 100644 flowsint-api/alembic/script.py.mako create mode 100644 flowsint-api/alembic/versions/40ece72583b7_add_email_and_hashed_password_to_profile.py create mode 100644 flowsint-api/alembic/versions/76f5436251e3_add_relationship_between_investigations_.py create mode 100644 flowsint-api/alembic/versions/965b56353b4c_initial_migration.py create mode 100644 flowsint-api/alembic/versions/d0a8e5b5a7b9_add_relationship_between_investigations_.py create mode 100644 flowsint-api/app/api/deps.py create mode 100644 flowsint-api/app/api/routes/auth.py create mode 100644 flowsint-api/app/api/routes/investigations.py rename backend/volumes/db/init/data.sql => flowsint-api/app/api/schemas/__init__.py (100%) mode change 100755 => 100644 create mode 100644 flowsint-api/app/api/schemas/base.py create mode 100644 flowsint-api/app/api/schemas/feedback.py create mode 100644 flowsint-api/app/api/schemas/investigation.py create mode 100644 flowsint-api/app/api/schemas/investigation_profiles.py create mode 100644 flowsint-api/app/api/schemas/log.py create mode 100644 flowsint-api/app/api/schemas/profile.py create mode 100644 flowsint-api/app/api/schemas/scan.py create mode 100644 flowsint-api/app/api/schemas/sketch.py create mode 100644 flowsint-api/app/api/schemas/transform.py delete mode 100644 flowsint-api/app/core/db.py rename flowsint-api/app/{neo4j/connector.py => core/graph_db.py} (63%) create mode 100644 flowsint-api/app/core/postgre_db.py create mode 100644 flowsint-api/app/models/__init__.py create mode 100644 flowsint-api/app/models/base.py create mode 100644 flowsint-api/app/models/models.py delete mode 100644 flowsint-api/branches.json create mode 100644 flowsint-web/src/app/api/auth/[...nextauth]/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/documents/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/individuals/[individual_id]/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/sketches/[sketch_id]/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/sketches/[sketch_id]/scans/[scan_id]/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/sketches/[sketch_id]/scans/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/sketches/[sketch_id]/sketch/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/[investigation_id]/sketches/route.ts delete mode 100644 flowsint-web/src/app/api/investigations/route.ts delete mode 100644 flowsint-web/src/app/api/latest-sketches/route.ts delete mode 100644 flowsint-web/src/app/api/metrics/global/route.ts delete mode 100644 flowsint-web/src/app/api/profiles/[profile_id]/route.ts delete mode 100644 flowsint-web/src/app/api/profiles/route.ts delete mode 100644 flowsint-web/src/app/api/transforms/route.ts delete mode 100644 flowsint-web/src/app/auth/callback/route.ts delete mode 100644 flowsint-web/src/app/auth/confirm/route.ts create mode 100644 flowsint-web/src/app/register/page.tsx create mode 100644 flowsint-web/src/auth.ts delete mode 100644 flowsint-web/src/components/investigations/file-upload.tsx create mode 100644 flowsint-web/src/components/register-form.tsx delete mode 100644 flowsint-web/src/components/sketches/scans-drawer/scan-button.tsx delete mode 100644 flowsint-web/src/components/sketches/scans-drawer/scan-table.tsx delete mode 100644 flowsint-web/src/components/sketches/sketch-navigation.tsx delete mode 100644 flowsint-web/src/components/ui/custom-edge.tsx delete mode 100644 flowsint-web/src/hooks/use-transforms.ts create mode 100644 flowsint-web/src/lib/client-fetch.ts delete mode 100644 flowsint-web/src/lib/hooks/sketches.ts create mode 100644 flowsint-web/src/lib/server-fetch.ts delete mode 100644 flowsint-web/src/lib/supabase/client.ts delete mode 100644 flowsint-web/src/lib/supabase/middleware.ts delete mode 100644 flowsint-web/src/lib/supabase/server.ts diff --git a/.env.example b/.env.example index 75c60c1..77dc153 100644 --- a/.env.example +++ b/.env.example @@ -1,127 +1,11 @@ -############ -# Secrets -# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION -############ - -POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password -JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long -ANON_KEY=ANON_KEY -SERVICE_ROLE_KEY=SERVICE_ROLE_KEY -DASHBOARD_USERNAME=supabase -DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated -SECRET_KEY_BASE=SECRET_KEY_BASE -VAULT_ENC_KEY=your-encryption-key-32-chars-min - - -############ -# Database - You can change these to any PostgreSQL database that has logical replication enabled. -############ - -POSTGRES_HOST=db -POSTGRES_DB=postgres -POSTGRES_PORT=5432 -# default user is postgres - - -############ -# Supavisor -- Database pooler -############ -POOLER_PROXY_PORT_TRANSACTION=6543 -POOLER_DEFAULT_POOL_SIZE=20 -POOLER_MAX_CLIENT_CONN=100 -POOLER_TENANT_ID=your-tenant-id - - -############ -# API Proxy - Configuration for the Kong Reverse proxy. -############ - -KONG_HTTP_PORT=8000 -KONG_HTTPS_PORT=8443 - - -############ -# API - Configuration for PostgREST. -############ - -PGRST_DB_SCHEMAS=public,storage,graphql_public - - -############ -# Auth - Configuration for the GoTrue authentication server. -############ - -## General -SITE_URL=http://localhost:3000 -ADDITIONAL_REDIRECT_URLS= -JWT_EXPIRY=3600 -DISABLE_SIGNUP=false -API_EXTERNAL_URL=http://localhost:8000 - -## Mailer Config -MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify" -MAILER_URLPATHS_INVITE="/auth/v1/verify" -MAILER_URLPATHS_RECOVERY="/auth/v1/verify" -MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify" - -## Email auth -ENABLE_EMAIL_SIGNUP=true -ENABLE_EMAIL_AUTOCONFIRM=true -SMTP_ADMIN_EMAIL=admin@example.com -SMTP_HOST=supabase-mail -SMTP_PORT=2500 -SMTP_USER=fake_mail_user -SMTP_PASS=fake_mail_password -SMTP_SENDER_NAME=fake_sender -ENABLE_ANONYMOUS_USERS=false - -## Phone auth -ENABLE_PHONE_SIGNUP=true -ENABLE_PHONE_AUTOCONFIRM=true - - -############ -# Studio - Configuration for the Dashboard -############ - -STUDIO_DEFAULT_ORGANIZATION=Default Organization -STUDIO_DEFAULT_PROJECT=Default Project - -STUDIO_PORT=3000 -# replace if you intend to use Studio outside of localhost -SUPABASE_PUBLIC_URL=http://localhost:8000 - -# Enable webp support -IMGPROXY_ENABLE_WEBP_DETECTION=true - -# Add your OpenAI API key to enable SQL Editor Assistant -OPENAI_API_KEY= - - -############ -# Functions - Configuration for Functions -############ -# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet. -FUNCTIONS_VERIFY_JWT=false - - -############ -# Logs - Configuration for Logflare -# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction -############ - -LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key - -# Change vector.toml sinks to reflect this change -LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key - -# Docker socket location - this value will differ depending on your OS -DOCKER_SOCKET_LOCATION=/var/run/docker.sock - -# Google Cloud Project details -GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID -GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER - +NODE_ENV=production +NEXT_PUBLIC_AUTH_REDIRECT=http://app.flowsint.localhost/auth/callback +HIBP_API_KEY=70b78a3256c84d09b79cd4953d77bdf3 +NEXT_PUBLIC_FLOWSINT_API=https://api.flowsint.localhost/api +NEXT_PUBLIC_DOCKER_FLOWSINT_API=http://flowsint-api:5000/api +NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR5bGhuc2F5eXRhb2FhaXFzZ2RwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzgzMzY3MzAsImV4cCI6MjA1MzkxMjczMH0.iVcpz8RpOgzVSamp_tNQQmjdLL9_Olx6m4LfsLVw1bg +AUTH_SECRET="superscretchangeitplz" # Added by `npx auth`. Read more: https://cli.authjs.dev +AUTH_TRUST_HOST=true NEO4J_URI_BOLT=bolt://neo4j:7687 NEO4J_URI_WEB=https://neo4j.flowsint.localhost NEO4J_USER=neo4j diff --git a/backend/.env.example b/backend/.env.example deleted file mode 100644 index 27eefa0..0000000 --- a/backend/.env.example +++ /dev/null @@ -1,135 +0,0 @@ -############ -# Secrets -# YOU MUST CHANGE THESE BEFORE GOING INTO PRODUCTION -############ - -POSTGRES_PASSWORD=your-super-secret-and-long-postgres-password -JWT_SECRET=your-super-secret-jwt-token-with-at-least-32-characters-long -ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE -SERVICE_ROLE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJzZXJ2aWNlX3JvbGUiLAogICAgImlzcyI6ICJzdXBhYmFzZS1kZW1vIiwKICAgICJpYXQiOiAxNjQxNzY5MjAwLAogICAgImV4cCI6IDE3OTk1MzU2MDAKfQ.DaYlNEoUrrEn2Ig7tqibS-PHK5vgusbcbo7X36XVt4Q -DASHBOARD_USERNAME=supabase -DASHBOARD_PASSWORD=this_password_is_insecure_and_should_be_updated -SECRET_KEY_BASE=UpNVntn3cDxHJpq99YMc1T1AQgQpc8kfYTuRgBiYa15BLrx8etQoXz3gZv1/u2oq -VAULT_ENC_KEY=your-encryption-key-32-chars-min - - -############ -# Database - You can change these to any PostgreSQL database that has logical replication enabled. -############ - -POSTGRES_HOST=db -POSTGRES_DB=postgres -POSTGRES_PORT=5432 -# default user is postgres - - -############ -# Supavisor -- Database pooler -############ -POOLER_PROXY_PORT_TRANSACTION=6543 -POOLER_DEFAULT_POOL_SIZE=20 -POOLER_MAX_CLIENT_CONN=100 -POOLER_TENANT_ID=your-tenant-id - - -############ -# API Proxy - Configuration for the Kong Reverse proxy. -############ - -KONG_HTTP_PORT=8000 -KONG_HTTPS_PORT=8443 - - -############ -# API - Configuration for PostgREST. -############ - -PGRST_DB_SCHEMAS=public,storage,graphql_public - - -############ -# Auth - Configuration for the GoTrue authentication server. -############ - -## General -SITE_URL=http://localhost:3000 -ADDITIONAL_REDIRECT_URLS= -JWT_EXPIRY=3600 -DISABLE_SIGNUP=false -API_EXTERNAL_URL=http://localhost:8000 - -## Mailer Config -MAILER_URLPATHS_CONFIRMATION="/auth/v1/verify" -MAILER_URLPATHS_INVITE="/auth/v1/verify" -MAILER_URLPATHS_RECOVERY="/auth/v1/verify" -MAILER_URLPATHS_EMAIL_CHANGE="/auth/v1/verify" - -## Email auth -ENABLE_EMAIL_SIGNUP=true -ENABLE_EMAIL_AUTOCONFIRM=true -SMTP_ADMIN_EMAIL=admin@example.com -SMTP_HOST=supabase-mail -SMTP_PORT=2500 -SMTP_USER=fake_mail_user -SMTP_PASS=fake_mail_password -SMTP_SENDER_NAME=fake_sender -ENABLE_ANONYMOUS_USERS=false - -## Phone auth -ENABLE_PHONE_SIGNUP=true -ENABLE_PHONE_AUTOCONFIRM=true - - -############ -# Studio - Configuration for the Dashboard -############ - -STUDIO_DEFAULT_ORGANIZATION=Default Organization -STUDIO_DEFAULT_PROJECT=Default Project - -STUDIO_PORT=3000 -# replace if you intend to use Studio outside of localhost -SUPABASE_PUBLIC_URL=http://localhost:8000 - -# Enable webp support -IMGPROXY_ENABLE_WEBP_DETECTION=true - -# Add your OpenAI API key to enable SQL Editor Assistant -OPENAI_API_KEY= - - -############ -# Functions - Configuration for Functions -############ -# NOTE: VERIFY_JWT applies to all functions. Per-function VERIFY_JWT is not supported yet. -FUNCTIONS_VERIFY_JWT=false - - -############ -# Logs - Configuration for Logflare -# Please refer to https://supabase.com/docs/reference/self-hosting-analytics/introduction -############ - -LOGFLARE_LOGGER_BACKEND_API_KEY=your-super-secret-and-long-logflare-key - -# Change vector.toml sinks to reflect this change -LOGFLARE_API_KEY=your-super-secret-and-long-logflare-key - -# Docker socket location - this value will differ depending on your OS -DOCKER_SOCKET_LOCATION=/var/run/docker.sock - -# Google Cloud Project details -GOOGLE_PROJECT_ID=GOOGLE_PROJECT_ID -GOOGLE_PROJECT_NUMBER=GOOGLE_PROJECT_NUMBER - - -## FLOWSINT-API - -SUPABASE_URL=http://localhost:8000 -SUPABASE_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyAgCiAgICAicm9sZSI6ICJhbm9uIiwKICAgICJpc3MiOiAic3VwYWJhc2UtZGVtbyIsCiAgICAiaWF0IjogMTY0MTc2OTIwMCwKICAgICJleHAiOiAxNzk5NTM1NjAwCn0.dc_X5iR_VP_qT0zsiyj_I_OZ2T9FtRU2BBNWN8Bu4GE - -## FLOWSINT-WEB - -NEXT_PUBLIC_AUTH_REDIRECT=http://localhost:3000/auth/callback -NEXT_PUBLIC_SUPABASE_URL=https://tylhnsayytaoaaiqsgdp.supabase.co -NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6InR5bGhuc2F5eXRhb2FhaXFzZ2RwIiwicm9sZSI6ImFub24iLCJpYXQiOjE3MzgzMzY3MzAsImV4cCI6MjA1MzkxMjczMH0.iVcpz8RpOgzVSamp_tNQQmjdLL9_Olx6m4LfsLVw1bg \ No newline at end of file diff --git a/backend/.gitignore b/backend/.gitignore deleted file mode 100644 index a1e9dc6..0000000 --- a/backend/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -volumes/db/data -volumes/storage -.env -test.http -docker-compose.override.yml diff --git a/backend/dev/data.sql b/backend/dev/data.sql deleted file mode 100644 index 2328004..0000000 --- a/backend/dev/data.sql +++ /dev/null @@ -1,48 +0,0 @@ -create table profiles ( - id uuid references auth.users not null, - updated_at timestamp with time zone, - username text unique, - avatar_url text, - website text, - - primary key (id), - unique(username), - constraint username_length check (char_length(username) >= 3) -); - -alter table profiles enable row level security; - -create policy "Public profiles are viewable by the owner." - on profiles for select - using ( auth.uid() = id ); - -create policy "Users can insert their own profile." - on profiles for insert - with check ( auth.uid() = id ); - -create policy "Users can update own profile." - on profiles for update - using ( auth.uid() = id ); - --- Set up Realtime -begin; - drop publication if exists supabase_realtime; - create publication supabase_realtime; -commit; -alter publication supabase_realtime add table profiles; - --- Set up Storage -insert into storage.buckets (id, name) -values ('avatars', 'avatars'); - -create policy "Avatar images are publicly accessible." - on storage.objects for select - using ( bucket_id = 'avatars' ); - -create policy "Anyone can upload an avatar." - on storage.objects for insert - with check ( bucket_id = 'avatars' ); - -create policy "Anyone can update an avatar." - on storage.objects for update - with check ( bucket_id = 'avatars' ); diff --git a/backend/dev/docker-compose.dev.yml b/backend/dev/docker-compose.dev.yml deleted file mode 100644 index ca19a0a..0000000 --- a/backend/dev/docker-compose.dev.yml +++ /dev/null @@ -1,34 +0,0 @@ -version: "3.8" - -services: - studio: - build: - context: .. - dockerfile: studio/Dockerfile - target: dev - ports: - - 8082:8082 - mail: - container_name: supabase-mail - image: inbucket/inbucket:3.0.3 - ports: - - '2500:2500' # SMTP - - '9000:9000' # web interface - - '1100:1100' # POP3 - auth: - environment: - - GOTRUE_SMTP_USER= - - GOTRUE_SMTP_PASS= - meta: - ports: - - 5555:8080 - db: - restart: 'no' - volumes: - # Always use a fresh database when developing - - /var/lib/postgresql/data - # Seed data should be inserted last (alphabetical order) - - ./dev/data.sql:/docker-entrypoint-initdb.d/seed.sql - storage: - volumes: - - /var/lib/storage diff --git a/backend/supabase/.gitignore b/backend/supabase/.gitignore deleted file mode 100644 index ad9264f..0000000 --- a/backend/supabase/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Supabase -.branches -.temp - -# dotenvx -.env.keys -.env.local -.env.*.local diff --git a/backend/supabase/config.toml b/backend/supabase/config.toml deleted file mode 100644 index a8abc5d..0000000 --- a/backend/supabase/config.toml +++ /dev/null @@ -1,308 +0,0 @@ -# For detailed configuration reference documentation, visit: -# https://supabase.com/docs/guides/local-development/cli/config -# A string used to distinguish different Supabase projects on the same host. Defaults to the -# working directory name when running `supabase init`. -project_id = "backend" - -[api] -enabled = true -# Port to use for the API URL. -port = 54321 -# Schemas to expose in your API. Tables, views and stored procedures in this schema will get API -# endpoints. `public` and `graphql_public` schemas are included by default. -schemas = ["public", "graphql_public"] -# Extra schemas to add to the search_path of every request. -extra_search_path = ["public", "extensions"] -# The maximum number of rows returns from a view, table, or stored procedure. Limits payload size -# for accidental or malicious requests. -max_rows = 1000 - -[api.tls] -# Enable HTTPS endpoints locally using a self-signed certificate. -enabled = false - -[db] -# Port to use for the local database URL. -port = 54322 -# Port used by db diff command to initialize the shadow database. -shadow_port = 54320 -# The database major version to use. This has to be the same as your remote database's. Run `SHOW -# server_version;` on the remote database to check. -major_version = 15 - -[db.pooler] -enabled = false -# Port to use for the local connection pooler. -port = 54329 -# Specifies when a server connection can be reused by other clients. -# Configure one of the supported pooler modes: `transaction`, `session`. -pool_mode = "transaction" -# How many server connections to allow per user/database pair. -default_pool_size = 20 -# Maximum number of client connections allowed. -max_client_conn = 100 - -# [db.vault] -# secret_key = "env(SECRET_VALUE)" - -[db.migrations] -# Specifies an ordered list of schema files that describe your database. -# Supports glob patterns relative to supabase directory: "./schemas/*.sql" -schema_paths = [] - -[db.seed] -# If enabled, seeds the database after migrations during a db reset. -enabled = true -# Specifies an ordered list of seed files to load during db reset. -# Supports glob patterns relative to supabase directory: "./seeds/*.sql" -sql_paths = ["./seed.sql"] - -[realtime] -enabled = true -# Bind realtime via either IPv4 or IPv6. (default: IPv4) -# ip_version = "IPv6" -# The maximum length in bytes of HTTP request headers. (default: 4096) -# max_header_length = 4096 - -[studio] -enabled = true -# Port to use for Supabase Studio. -port = 54323 -# External URL of the API server that frontend connects to. -api_url = "http://127.0.0.1" -# OpenAI API Key to use for Supabase AI in the Supabase Studio. -openai_api_key = "env(OPENAI_API_KEY)" - -# Email testing server. Emails sent with the local dev setup are not actually sent - rather, they -# are monitored, and you can view the emails that would have been sent from the web interface. -[inbucket] -enabled = true -# Port to use for the email testing server web interface. -port = 54324 -# Uncomment to expose additional ports for testing user applications that send emails. -# smtp_port = 54325 -# pop3_port = 54326 -# admin_email = "admin@email.com" -# sender_name = "Admin" - -[storage] -enabled = true -# The maximum file size allowed (e.g. "5MB", "500KB"). -file_size_limit = "50MiB" - -# Image transformation API is available to Supabase Pro plan. -# [storage.image_transformation] -# enabled = true - -# Uncomment to configure local storage buckets -# [storage.buckets.images] -# public = false -# file_size_limit = "50MiB" -# allowed_mime_types = ["image/png", "image/jpeg"] -# objects_path = "./images" - -[auth] -enabled = true -# The base URL of your website. Used as an allow-list for redirects and for constructing URLs used -# in emails. -site_url = "http://127.0.0.1:3000" -# A list of *exact* URLs that auth providers are permitted to redirect to post authentication. -additional_redirect_urls = ["https://127.0.0.1:3000"] -# How long tokens are valid for, in seconds. Defaults to 3600 (1 hour), maximum 604,800 (1 week). -jwt_expiry = 3600 -# If disabled, the refresh token will never expire. -enable_refresh_token_rotation = true -# Allows refresh tokens to be reused after expiry, up to the specified interval in seconds. -# Requires enable_refresh_token_rotation = true. -refresh_token_reuse_interval = 10 -# Allow/disallow new user signups to your project. -enable_signup = true -# Allow/disallow anonymous sign-ins to your project. -enable_anonymous_sign_ins = false -# Allow/disallow testing manual linking of accounts -enable_manual_linking = false -# Passwords shorter than this value will be rejected as weak. Minimum 6, recommended 8 or more. -minimum_password_length = 6 -# Passwords that do not meet the following requirements will be rejected as weak. Supported values -# are: `letters_digits`, `lower_upper_letters_digits`, `lower_upper_letters_digits_symbols` -password_requirements = "" - -[auth.rate_limit] -# Number of emails that can be sent per hour. Requires auth.email.smtp to be enabled. -email_sent = 2 -# Number of SMS messages that can be sent per hour. Requires auth.sms to be enabled. -sms_sent = 30 -# Number of anonymous sign-ins that can be made per hour per IP address. Requires enable_anonymous_sign_ins = true. -anonymous_users = 30 -# Number of sessions that can be refreshed in a 5 minute interval per IP address. -token_refresh = 150 -# Number of sign up and sign-in requests that can be made in a 5 minute interval per IP address (excludes anonymous users). -sign_in_sign_ups = 30 -# Number of OTP / Magic link verifications that can be made in a 5 minute interval per IP address. -token_verifications = 30 - -# Configure one of the supported captcha providers: `hcaptcha`, `turnstile`. -# [auth.captcha] -# enabled = true -# provider = "hcaptcha" -# secret = "" - -[auth.email] -# Allow/disallow new user signups via email to your project. -enable_signup = true -# If enabled, a user will be required to confirm any email change on both the old, and new email -# addresses. If disabled, only the new email is required to confirm. -double_confirm_changes = true -# If enabled, users need to confirm their email address before signing in. -enable_confirmations = false -# If enabled, users will need to reauthenticate or have logged in recently to change their password. -secure_password_change = false -# Controls the minimum amount of time that must pass before sending another signup confirmation or password reset email. -max_frequency = "1s" -# Number of characters used in the email OTP. -otp_length = 6 -# Number of seconds before the email OTP expires (defaults to 1 hour). -otp_expiry = 3600 - -# Use a production-ready SMTP server -# [auth.email.smtp] -# enabled = true -# host = "smtp.sendgrid.net" -# port = 587 -# user = "apikey" -# pass = "env(SENDGRID_API_KEY)" -# admin_email = "admin@email.com" -# sender_name = "Admin" - -# Uncomment to customize email template -# [auth.email.template.invite] -# subject = "You have been invited" -# content_path = "./supabase/templates/invite.html" - -[auth.sms] -# Allow/disallow new user signups via SMS to your project. -enable_signup = false -# If enabled, users need to confirm their phone number before signing in. -enable_confirmations = false -# Template for sending OTP to users -template = "Your code is {{ .Code }}" -# Controls the minimum amount of time that must pass before sending another sms otp. -max_frequency = "5s" - -# Use pre-defined map of phone number to OTP for testing. -# [auth.sms.test_otp] -# 4152127777 = "123456" - -# Configure logged in session timeouts. -# [auth.sessions] -# Force log out after the specified duration. -# timebox = "24h" -# Force log out if the user has been inactive longer than the specified duration. -# inactivity_timeout = "8h" - -# This hook runs before a token is issued and allows you to add additional claims based on the authentication method used. -# [auth.hook.custom_access_token] -# enabled = true -# uri = "pg-functions:////" - -# Configure one of the supported SMS providers: `twilio`, `twilio_verify`, `messagebird`, `textlocal`, `vonage`. -[auth.sms.twilio] -enabled = false -account_sid = "" -message_service_sid = "" -# DO NOT commit your Twilio auth token to git. Use environment variable substitution instead: -auth_token = "env(SUPABASE_AUTH_SMS_TWILIO_AUTH_TOKEN)" - -# Multi-factor-authentication is available to Supabase Pro plan. -[auth.mfa] -# Control how many MFA factors can be enrolled at once per user. -max_enrolled_factors = 10 - -# Control MFA via App Authenticator (TOTP) -[auth.mfa.totp] -enroll_enabled = false -verify_enabled = false - -# Configure MFA via Phone Messaging -[auth.mfa.phone] -enroll_enabled = false -verify_enabled = false -otp_length = 6 -template = "Your code is {{ .Code }}" -max_frequency = "5s" - -# Configure MFA via WebAuthn -# [auth.mfa.web_authn] -# enroll_enabled = true -# verify_enabled = true - -# Use an external OAuth provider. The full list of providers are: `apple`, `azure`, `bitbucket`, -# `discord`, `facebook`, `github`, `gitlab`, `google`, `keycloak`, `linkedin_oidc`, `notion`, `twitch`, -# `twitter`, `slack`, `spotify`, `workos`, `zoom`. -[auth.external.apple] -enabled = false -client_id = "" -# DO NOT commit your OAuth provider secret to git. Use environment variable substitution instead: -secret = "env(SUPABASE_AUTH_EXTERNAL_APPLE_SECRET)" -# Overrides the default auth redirectUrl. -redirect_uri = "" -# Overrides the default auth provider URL. Used to support self-hosted gitlab, single-tenant Azure, -# or any other third-party OIDC providers. -url = "" -# If enabled, the nonce check will be skipped. Required for local sign in with Google auth. -skip_nonce_check = false - -# Use Firebase Auth as a third-party provider alongside Supabase Auth. -[auth.third_party.firebase] -enabled = false -# project_id = "my-firebase-project" - -# Use Auth0 as a third-party provider alongside Supabase Auth. -[auth.third_party.auth0] -enabled = false -# tenant = "my-auth0-tenant" -# tenant_region = "us" - -# Use AWS Cognito (Amplify) as a third-party provider alongside Supabase Auth. -[auth.third_party.aws_cognito] -enabled = false -# user_pool_id = "my-user-pool-id" -# user_pool_region = "us-east-1" - -# Use Clerk as a third-party provider alongside Supabase Auth. -[auth.third_party.clerk] -enabled = false -# Obtain from https://clerk.com/setup/supabase -# domain = "example.clerk.accounts.dev" - -[edge_runtime] -enabled = true -# Configure one of the supported request policies: `oneshot`, `per_worker`. -# Use `oneshot` for hot reload, or `per_worker` for load testing. -policy = "oneshot" -# Port to attach the Chrome inspector for debugging edge functions. -inspector_port = 8083 -# The Deno major version to use. -deno_version = 1 - -# [edge_runtime.secrets] -# secret_key = "env(SECRET_VALUE)" - -[analytics] -enabled = true -port = 54327 -# Configure one of the supported backends: `postgres`, `bigquery`. -backend = "postgres" - -# Experimental features may be deprecated any time -[experimental] -# Configures Postgres storage engine to use OrioleDB (S3) -orioledb_version = "" -# Configures S3 bucket URL, eg. .s3-.amazonaws.com -s3_host = "env(S3_HOST)" -# Configures S3 bucket region, eg. us-east-1 -s3_region = "env(S3_REGION)" -# Configures AWS_ACCESS_KEY_ID for S3 bucket -s3_access_key = "env(S3_ACCESS_KEY)" -# Configures AWS_SECRET_ACCESS_KEY for S3 bucket -s3_secret_key = "env(S3_SECRET_KEY)" diff --git a/backend/supabase/migrations/20250412163409_remote_schema.sql b/backend/supabase/migrations/20250412163409_remote_schema.sql deleted file mode 100644 index 86e48ad..0000000 --- a/backend/supabase/migrations/20250412163409_remote_schema.sql +++ /dev/null @@ -1,2533 +0,0 @@ - - -SET statement_timeout = 0; -SET lock_timeout = 0; -SET idle_in_transaction_session_timeout = 0; -SET client_encoding = 'UTF8'; -SET standard_conforming_strings = on; -SELECT pg_catalog.set_config('search_path', '', false); -SET check_function_bodies = false; -SET xmloption = content; -SET client_min_messages = warning; -SET row_security = off; - - -CREATE EXTENSION IF NOT EXISTS "pgsodium"; - - - - - - -COMMENT ON SCHEMA "public" IS 'standard public schema'; - - - -CREATE EXTENSION IF NOT EXISTS "pg_graphql" WITH SCHEMA "graphql"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "pg_stat_statements" WITH SCHEMA "extensions"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "pgcrypto" WITH SCHEMA "extensions"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "pgjwt" WITH SCHEMA "extensions"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "pgmq" WITH SCHEMA "pgmq"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "supabase_vault" WITH SCHEMA "vault"; - - - - - - -CREATE EXTENSION IF NOT EXISTS "uuid-ossp" WITH SCHEMA "extensions"; - - - - - - -CREATE TYPE "public"."investigation_status" AS ENUM ( - 'active', - 'pending', - 'archived' -); - - -ALTER TYPE "public"."investigation_status" OWNER TO "postgres"; - - -COMMENT ON TYPE "public"."investigation_status" IS 'Describes the possible statuses of an investigation.'; - - - -CREATE OR REPLACE FUNCTION "public"."handle_new_investigation"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$BEGIN - INSERT INTO investigations_profiles (investigation_id, profile_id, role) - VALUES (NEW.id, auth.uid(), 'owner'); - RETURN NEW; -END;$$; - - -ALTER FUNCTION "public"."handle_new_investigation"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."handle_new_project"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$begin - insert into projects_profiles (project_id, profile_id) - values (new.id, auth.uid()); - return new; -end;$$; - - -ALTER FUNCTION "public"."handle_new_project"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."handle_new_sketch"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$BEGIN - INSERT INTO sketches_profiles (sketch_id, profile_id, role) - VALUES (NEW.id, auth.uid(), 'owner'); - RETURN NEW; -END;$$; - - -ALTER FUNCTION "public"."handle_new_sketch"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."handle_new_user"() RETURNS "trigger" - LANGUAGE "plpgsql" SECURITY DEFINER - SET "search_path" TO '' - AS $$ -begin - insert into public.profiles (id, first_name, last_name) - values (new.id, new.raw_user_meta_data ->> 'first_name', new.raw_user_meta_data ->> 'last_name'); - return new; -end; -$$; - - -ALTER FUNCTION "public"."handle_new_user"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."sync_investigation_profile_from_sketch"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$ -DECLARE - inv_id UUID; -BEGIN - -- Récupère l'investigation_id associé au sketch_id - SELECT investigation_id INTO inv_id - FROM sketches - WHERE id = NEW.sketch_id; - - -- Vérifie que ce couple n'existe pas déjà (optionnel selon tes contraintes) - IF NOT EXISTS ( - SELECT 1 FROM investigations_profiles - WHERE profile_id = NEW.profile_id AND investigation_id = inv_id - ) THEN - -- Insère le lien dans investigations_profiles - INSERT INTO investigations_profiles(profile_id, investigation_id) - VALUES (NEW.profile_id, inv_id); - END IF; - - RETURN NEW; -END; -$$; - - -ALTER FUNCTION "public"."sync_investigation_profile_from_sketch"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."update_investigation_last_updated"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$BEGIN - -- Si la mise à jour concerne 'investigations', mettre à jour 'projects' uniquement si 10s sont écoulées - IF TG_TABLE_NAME = 'sketches' THEN - IF OLD.last_updated_at IS NULL OR OLD.last_updated_at < NOW() - INTERVAL '10 seconds' THEN - UPDATE investigations - SET last_updated_at = NOW() - WHERE id = NEW.investigation_id; - UPDATE sketches - SET last_updated_at = NOW() - WHERE id = NEW.id; - END IF; - - -- Si la mise à jour concerne une table liée, mettre à jour 'investigations' et 'projects' seulement si 10s sont écoulées - ELSIF TG_TABLE_NAME IN ('emails', 'individuals', 'relationships', 'physical_addresses', 'social_accounts', 'ip_addresses', 'phones') THEN - IF (SELECT last_updated_at FROM sketches WHERE id = NEW.sketch_id) < NOW() - INTERVAL '10 seconds' THEN - UPDATE sketches - SET last_updated_at = NOW() - WHERE id = NEW.sketch_id; - - UPDATE investigations - SET last_updated_at = NOW() - WHERE id = ( - SELECT investigation_id FROM sketches WHERE id = NEW.sketch_id - ); - END IF; - END IF; - - RETURN NEW; -END;$$; - - -ALTER FUNCTION "public"."update_investigation_last_updated"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."update_last_updated_at"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$ -BEGIN - IF TG_TABLE_NAME = 'sketches' THEN - IF OLD.last_updated_at IS NULL OR OLD.last_updated_at < NOW() - INTERVAL '10 seconds' THEN - UPDATE investigations - SET last_updated_at = NOW() - WHERE id = NEW.investigation_id; - - UPDATE sketches - SET last_updated_at = NOW() - WHERE id = NEW.id; - END IF; - - ELSIF TG_TABLE_NAME IN ( - 'emails', 'individuals', 'relationships', - 'physical_addresses', 'social_accounts', - 'ip_addresses', 'phones' - ) THEN - IF (SELECT last_updated_at FROM sketches WHERE id = NEW.sketch_id) IS NULL OR - (SELECT last_updated_at FROM sketches WHERE id = NEW.sketch_id) < NOW() - INTERVAL '10 seconds' THEN - UPDATE sketches - SET last_updated_at = NOW() - WHERE id = NEW.sketch_id; - - UPDATE investigations - SET last_updated_at = NOW() - WHERE id = ( - SELECT investigation_id FROM sketches WHERE id = NEW.sketch_id - ); - END IF; - END IF; - - RETURN NEW; -END; -$$; - - -ALTER FUNCTION "public"."update_last_updated_at"() OWNER TO "postgres"; - - -CREATE OR REPLACE FUNCTION "public"."update_sketch_last_updated"() RETURNS "trigger" - LANGUAGE "plpgsql" - AS $$BEGIN - IF (SELECT last_updated_at FROM sketches WHERE id = NEW.id) IS NULL OR - (SELECT last_updated_at FROM sketches WHERE id = NEW.id) < NOW() - INTERVAL '10 seconds' THEN - UPDATE investigations - SET last_updated_at = NOW() - WHERE id = NEW.investigation_id; - END IF; - - RETURN NEW; -END;$$; - - -ALTER FUNCTION "public"."update_sketch_last_updated"() OWNER TO "postgres"; - -SET default_tablespace = ''; - -SET default_table_access_method = "heap"; - - -CREATE TABLE IF NOT EXISTS "public"."accounts_breaches" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "account" "text", - "breach_id" bigint -); - - -ALTER TABLE "public"."accounts_breaches" OWNER TO "postgres"; - - -ALTER TABLE "public"."accounts_breaches" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."accounts_breaches_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."breaches" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "name" "text" NOT NULL, - "description" "text", - "raw_content" "jsonb" -); - - -ALTER TABLE "public"."breaches" OWNER TO "postgres"; - - -ALTER TABLE "public"."breaches" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."breaches_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."emails" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "individual_id" "uuid", - "sketch_id" "uuid", - "email" "text", - "breach_found" boolean DEFAULT false, - "organization_id" "uuid", - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."emails" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."feedbacks" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "content" "text", - "owner_id" "uuid" DEFAULT "auth"."uid"() -); - - -ALTER TABLE "public"."feedbacks" OWNER TO "postgres"; - - -ALTER TABLE "public"."feedbacks" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."feedbacks_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."groups" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "label" "text", - "sketch_id" "uuid" -); - - -ALTER TABLE "public"."groups" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."individuals" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "sketch_id" "uuid", - "full_name" "text", - "birth_date" "date", - "gender" "text", - "nationality" "text", - "notes" "jsonb", - "image_url" "text", - "group_id" "uuid", - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."individuals" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."individuals_individuals" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "individual_a" "uuid", - "individual_b" "uuid", - "sketch_id" "uuid", - "relation_type" "text", - "confidence_level" integer, - CONSTRAINT "relationships_confidence_level_check" CHECK ((("confidence_level" >= 1) AND ("confidence_level" <= 100))) -); - - -ALTER TABLE "public"."individuals_individuals" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."investigations" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "name" "text", - "description" "text", - "owner_id" "uuid" DEFAULT "auth"."uid"(), - "last_updated_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."investigations" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."investigations_profiles" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "investigation_id" "uuid" NOT NULL, - "profile_id" "uuid" NOT NULL, - "role" "text" DEFAULT 'member'::"text" NOT NULL -); - - -ALTER TABLE "public"."investigations_profiles" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."sketches_profiles" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "profile_id" "uuid", - "sketch_id" "uuid", - "role" "text" DEFAULT 'editor'::"text" -); - - -ALTER TABLE "public"."sketches_profiles" OWNER TO "postgres"; - - -ALTER TABLE "public"."sketches_profiles" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."investigations_profiles_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."ip_addresses" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "individual_id" "uuid", - "sketch_id" "uuid", - "ip_address" "text", - "geolocation" "jsonb", - "last_seen" timestamp without time zone DEFAULT "now"(), - "organization_id" "uuid", - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."ip_addresses" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."organizations" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "registration_number" "text", - "founding_date" "text", - "sketch_id" "uuid", - "name" "text" -); - - -ALTER TABLE "public"."organizations" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."organizations_individuals" ( - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text"), - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "individual_id" "uuid", - "organization_id" "uuid", - "sketch_id" "uuid", - "relation_type" "text" -); - - -ALTER TABLE "public"."organizations_individuals" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."organizations_organizations" ( - "id" bigint NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "organization_a" "uuid", - "organization_b" "uuid", - "relation_type" "text" DEFAULT 'subsidiary'::"text", - "sketch_id" "uuid" -); - - -ALTER TABLE "public"."organizations_organizations" OWNER TO "postgres"; - - -CREATE OR REPLACE VIEW "public"."organization_graph" WITH ("security_invoker"='on') AS - WITH "related_organizations" AS ( - SELECT "o_1"."id" AS "organization_id", - "o_1"."name" - FROM "public"."organizations" "o_1" - UNION - SELECT "oo"."organization_b" AS "organization_id", - "o_1"."name" - FROM ("public"."organizations_organizations" "oo" - JOIN "public"."organizations" "o_1" ON (("oo"."organization_b" = "o_1"."id"))) - ), "related_individuals" AS ( - SELECT "i"."id" AS "individual_id", - "i"."full_name", - "oi"."organization_id" - FROM (("public"."organizations_individuals" "oi" - JOIN "public"."individuals" "i" ON (("oi"."individual_id" = "i"."id"))) - JOIN "related_organizations" "ro" ON (("oi"."organization_id" = "ro"."organization_id"))) - ), "organization_nodes" AS ( - SELECT "ro"."organization_id", - "jsonb_build_object"('id', ("ro"."organization_id")::"text", 'type', 'custom', 'data', "jsonb_build_object"('id', "ro"."organization_id", 'name', "ro"."name", 'label', "ro"."name", 'type', 'organization'), 'position', "jsonb_build_object"('x', 200, 'y', 0)) AS "node" - FROM "related_organizations" "ro" - ), "individual_nodes" AS ( - SELECT "ri"."organization_id", - "jsonb_build_object"('id', ("ri"."individual_id")::"text", 'type', 'custom', 'data', "jsonb_build_object"('id', "ri"."individual_id", 'full_name', "ri"."full_name", 'label', "ri"."full_name", 'type', 'individual'), 'position', "jsonb_build_object"('x', 0, 'y', 100)) AS "node" - FROM "related_individuals" "ri" - ), "organization_edges" AS ( - SELECT "oo"."organization_a" AS "organization_id", - "jsonb_build_object"('id', "concat"('org-org-', "oo"."id"), 'source', ("oo"."organization_a")::"text", 'target', ("oo"."organization_b")::"text", 'type', 'custom', 'label', COALESCE("oo"."relation_type", 'related'::"text"), 'data', "jsonb_build_object"('relation_type', "oo"."relation_type")) AS "edge" - FROM "public"."organizations_organizations" "oo" - WHERE (("oo"."organization_a" IS NOT NULL) AND ("oo"."organization_b" IS NOT NULL) AND (EXISTS ( SELECT 1 - FROM "related_organizations" "ro" - WHERE ("ro"."organization_id" = "oo"."organization_a")))) - ), "org_individual_edges" AS ( - SELECT "oi"."organization_id", - "jsonb_build_object"('id', "concat"('org-ind-', "oi"."id"), 'source', ("oi"."organization_id")::"text", 'target', ("oi"."individual_id")::"text", 'type', 'custom', 'label', COALESCE("oi"."relation_type", 'employee'::"text"), 'data', "jsonb_build_object"('relation_type', "oi"."relation_type")) AS "edge" - FROM "public"."organizations_individuals" "oi" - WHERE (EXISTS ( SELECT 1 - FROM "related_organizations" "ro" - WHERE ("ro"."organization_id" = "oi"."organization_id"))) - ), "individual_edges" AS ( - SELECT "ri"."organization_id", - "jsonb_build_object"('id', "concat"('ind-ind-', "r"."id"), 'source', ("r"."individual_a")::"text", 'target', ("r"."individual_b")::"text", 'type', 'custom', 'label', COALESCE("r"."relation_type", 'related'::"text"), 'data', "jsonb_build_object"('confidence_level', "r"."confidence_level", 'relation_type', "r"."relation_type")) AS "edge" - FROM ("public"."individuals_individuals" "r" - JOIN "related_individuals" "ri" ON (("r"."individual_a" = "ri"."individual_id"))) - WHERE (("r"."individual_a" IS NOT NULL) AND ("r"."individual_b" IS NOT NULL) AND (EXISTS ( SELECT 1 - FROM "related_individuals" "ri2" - WHERE ("ri2"."individual_id" = "r"."individual_b")))) - ), "nodes_by_organization" AS ( - SELECT "all_nodes"."organization_id", - "json_agg"(DISTINCT "all_nodes"."node") AS "nodes" - FROM ( SELECT "organization_nodes"."organization_id", - "organization_nodes"."node" - FROM "organization_nodes" - UNION ALL - SELECT "individual_nodes"."organization_id", - "individual_nodes"."node" - FROM "individual_nodes") "all_nodes" - GROUP BY "all_nodes"."organization_id" - ), "edges_by_organization" AS ( - SELECT "all_edges"."organization_id", - "json_agg"(DISTINCT "all_edges"."edge") AS "edges" - FROM ( SELECT "organization_edges"."organization_id", - "organization_edges"."edge" - FROM "organization_edges" - UNION ALL - SELECT "org_individual_edges"."organization_id", - "org_individual_edges"."edge" - FROM "org_individual_edges" - UNION ALL - SELECT "individual_edges"."organization_id", - "individual_edges"."edge" - FROM "individual_edges") "all_edges" - GROUP BY "all_edges"."organization_id" - ) - SELECT "o"."id" AS "organization_id", - "o"."name" AS "organization_name", - COALESCE("n"."nodes", '[]'::"json") AS "nodes", - COALESCE("e"."edges", '[]'::"json") AS "edges" - FROM (("public"."organizations" "o" - LEFT JOIN "nodes_by_organization" "n" ON (("n"."organization_id" = "o"."id"))) - LEFT JOIN "edges_by_organization" "e" ON (("e"."organization_id" = "o"."id"))); - - -ALTER TABLE "public"."organization_graph" OWNER TO "postgres"; - - -ALTER TABLE "public"."organizations_organizations" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."organizations_organizations_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."phones" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "individual_id" "uuid", - "sketch_id" "uuid", - "phone_number" "text", - "country" "text", - "organization_id" "uuid", - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."phones" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."physical_addresses" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "address" "text", - "city" "text", - "country" "text", - "zip" "text", - "sketch_id" "uuid", - "individual_id" "uuid", - "organization_id" "uuid" -); - - -ALTER TABLE "public"."physical_addresses" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."profiles" ( - "id" "uuid" NOT NULL, - "first_name" "text", - "last_name" "text", - "avatar_url" "text" -); - - -ALTER TABLE "public"."profiles" OWNER TO "postgres"; - - -ALTER TABLE "public"."investigations_profiles" ALTER COLUMN "id" ADD GENERATED BY DEFAULT AS IDENTITY ( - SEQUENCE NAME "public"."projects_profiles_id_seq" - START WITH 1 - INCREMENT BY 1 - NO MINVALUE - NO MAXVALUE - CACHE 1 -); - - - -CREATE TABLE IF NOT EXISTS "public"."scans" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "status" "text", - "scan_name" "text", - "results" "jsonb", - "value" "text", - "sketch_id" "uuid" -); - - -ALTER TABLE "public"."scans" OWNER TO "postgres"; - - -COMMENT ON COLUMN "public"."scans"."value" IS 'The value that was searched for. Can be a username, an email, an IP address, etc.'; - - - -CREATE OR REPLACE VIEW "public"."sketch_graph" AS -SELECT - NULL::"uuid" AS "sketch_id", - NULL::"json" AS "nodes", - NULL::"json" AS "edges", - NULL::bigint AS "debug_relationship_count"; - - -ALTER TABLE "public"."sketch_graph" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."social_accounts" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "individual_id" "uuid", - "sketch_id" "uuid", - "platform" "text", - "username" "text", - "profile_url" "text", - "last_seen" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text"), - "organization_id" "uuid", - "created_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."social_accounts" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."vehicles" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "model" "text", - "brand" "text", - "year" "text", - "plate" "text", - "type" "text", - "sketch_id" "uuid", - "individual_id" "uuid", - "organization_id" "uuid", - "color" "text" -); - - -ALTER TABLE "public"."vehicles" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."websites" ( - "id" "uuid" DEFAULT "gen_random_uuid"() NOT NULL, - "created_at" timestamp with time zone DEFAULT "now"() NOT NULL, - "sketch_id" "uuid", - "individual_id" "uuid", - "registration_date" "text", - "url" "text", - "registrar" "text", - "ip_address" "text", - "organization_id" "uuid" -); - - -ALTER TABLE "public"."websites" OWNER TO "postgres"; - - -CREATE OR REPLACE VIEW "public"."sketch_table" WITH ("security_invoker"='on') AS - SELECT "all_entities"."sketch_id", - "jsonb_agg"("jsonb_build_object"('id', "all_entities"."id", 'data', "all_entities"."data")) AS "data" - FROM ( SELECT "organizations"."id", - "organizations"."sketch_id", - "jsonb_build_object"('id', "organizations"."id", 'type', 'organization', 'label', "organizations"."name", 'name', "organizations"."name", 'registration_number', "organizations"."registration_number", 'founding_date', "organizations"."founding_date", 'created_at', "organizations"."created_at") AS "data" - FROM "public"."organizations" - UNION ALL - SELECT "individuals"."id", - "individuals"."sketch_id", - "jsonb_build_object"('id', "individuals"."id", 'type', 'individual', 'label', "individuals"."full_name", 'full_name', "individuals"."full_name", 'birth_date', "individuals"."birth_date", 'gender', "individuals"."gender", 'nationality', "individuals"."nationality", 'notes', "individuals"."notes", 'image_url', "individuals"."image_url", 'created_at', "individuals"."created_at") AS "data" - FROM "public"."individuals" - UNION ALL - SELECT "emails"."id", - "emails"."sketch_id", - "jsonb_build_object"('id', "emails"."id", 'type', 'email', 'label', "emails"."email", 'email', "emails"."email", 'breach_found', "emails"."breach_found", 'created_at', "emails"."created_at") AS "data" - FROM "public"."emails" - UNION ALL - SELECT "phones"."id", - "phones"."sketch_id", - "jsonb_build_object"('id', "phones"."id", 'type', 'phone', 'label', "phones"."phone_number", 'phone_number', "phones"."phone_number", 'country', "phones"."country", 'created_at', "phones"."created_at") AS "data" - FROM "public"."phones" - UNION ALL - SELECT "websites"."id", - "websites"."sketch_id", - "jsonb_build_object"('id', "websites"."id", 'type', 'website', 'label', "websites"."url", 'url', "websites"."url", 'registration_date', "websites"."registration_date", 'registrar', "websites"."registrar", 'ip_address', "websites"."ip_address", 'created_at', "websites"."created_at") AS "data" - FROM "public"."websites" - UNION ALL - SELECT "social_accounts"."id", - "social_accounts"."sketch_id", - "jsonb_build_object"('id', "social_accounts"."id", 'type', 'social', 'label', "concat"("social_accounts"."username", '(', "social_accounts"."platform", ')'), 'platform', "social_accounts"."platform", 'username', "social_accounts"."username", 'profile_url', "social_accounts"."profile_url", 'last_seen', "social_accounts"."last_seen", 'created_at', "social_accounts"."created_at") AS "data" - FROM "public"."social_accounts" - UNION ALL - SELECT "ip_addresses"."id", - "ip_addresses"."sketch_id", - "jsonb_build_object"('id', "ip_addresses"."id", 'type', 'ip', 'label', "ip_addresses"."ip_address", 'ip_address', "ip_addresses"."ip_address", 'geolocation', "ip_addresses"."geolocation", 'last_seen', "ip_addresses"."last_seen", 'created_at', "ip_addresses"."created_at") AS "data" - FROM "public"."ip_addresses" - UNION ALL - SELECT "vehicles"."id", - "vehicles"."sketch_id", - "jsonb_build_object"('id', "vehicles"."id", 'type', 'vehicle', 'label', "concat"("vehicles"."brand", '', "vehicles"."model", ': ', "vehicles"."plate"), 'plate', "vehicles"."plate", 'brand', "vehicles"."brand", 'model', "vehicles"."model", 'color', "vehicles"."color", 'created_at', "vehicles"."created_at") AS "data" - FROM "public"."vehicles" - UNION ALL - SELECT "physical_addresses"."id", - "physical_addresses"."sketch_id", - "jsonb_build_object"('id', "physical_addresses"."id", 'type', 'address', 'label', "concat"("physical_addresses"."address", ' ', "physical_addresses"."city", ' ', "physical_addresses"."country"), 'address', "physical_addresses"."address", 'city', "physical_addresses"."city", 'country', "physical_addresses"."country", 'zip', "physical_addresses"."zip", 'created_at', "physical_addresses"."created_at") AS "data" - FROM "public"."physical_addresses") "all_entities" - GROUP BY "all_entities"."sketch_id"; - - -ALTER TABLE "public"."sketch_table" OWNER TO "postgres"; - - -CREATE TABLE IF NOT EXISTS "public"."sketches" ( - "id" "uuid" DEFAULT "extensions"."uuid_generate_v4"() NOT NULL, - "title" "text", - "description" "text", - "created_at" timestamp without time zone DEFAULT CURRENT_TIMESTAMP, - "owner_id" "uuid" DEFAULT "auth"."uid"(), - "status" "public"."investigation_status" DEFAULT 'active'::"public"."investigation_status", - "investigation_id" "uuid" NOT NULL, - "last_updated_at" timestamp with time zone DEFAULT ("now"() AT TIME ZONE 'utc'::"text") -); - - -ALTER TABLE "public"."sketches" OWNER TO "postgres"; - - -ALTER TABLE ONLY "public"."accounts_breaches" - ADD CONSTRAINT "accounts_breaches_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."breaches" - ADD CONSTRAINT "breaches_name_key" UNIQUE ("name"); - - - -ALTER TABLE ONLY "public"."breaches" - ADD CONSTRAINT "breaches_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."emails" - ADD CONSTRAINT "emails_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."feedbacks" - ADD CONSTRAINT "feedbacks_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."groups" - ADD CONSTRAINT "groups_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."individuals" - ADD CONSTRAINT "individuals_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."sketches" - ADD CONSTRAINT "investigations_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."sketches_profiles" - ADD CONSTRAINT "investigations_profiles_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."sketches_profiles" - ADD CONSTRAINT "investigations_profiles_unique_profile_investigation" UNIQUE ("profile_id", "sketch_id"); - - - -ALTER TABLE ONLY "public"."ip_addresses" - ADD CONSTRAINT "ip_addresses_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."organizations_individuals" - ADD CONSTRAINT "organizations_individuals_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."organizations_organizations" - ADD CONSTRAINT "organizations_organizations_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."organizations" - ADD CONSTRAINT "organizations_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."phones" - ADD CONSTRAINT "phones_phone_number_key" UNIQUE ("phone_number"); - - - -ALTER TABLE ONLY "public"."phones" - ADD CONSTRAINT "phones_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."physical_addresses" - ADD CONSTRAINT "physical_addresses_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."profiles" - ADD CONSTRAINT "profiles_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."investigations" - ADD CONSTRAINT "projects_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."investigations_profiles" - ADD CONSTRAINT "projects_profiles_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."investigations_profiles" - ADD CONSTRAINT "projects_profiles_unique_profile_project" UNIQUE ("profile_id", "investigation_id"); - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "relationships_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."scans" - ADD CONSTRAINT "scans_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."social_accounts" - ADD CONSTRAINT "social_accounts_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "unique_relationship" UNIQUE ("individual_a", "individual_b"); - - - -ALTER TABLE ONLY "public"."accounts_breaches" - ADD CONSTRAINT "unique_relationship_breaches" UNIQUE ("breach_id", "account"); - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "unique_relationship_individuals" UNIQUE ("individual_a", "individual_b"); - - - -ALTER TABLE ONLY "public"."vehicles" - ADD CONSTRAINT "vehicles_pkey" PRIMARY KEY ("id"); - - - -ALTER TABLE ONLY "public"."websites" - ADD CONSTRAINT "websites_pkey" PRIMARY KEY ("id"); - - - -CREATE INDEX "idx_emails_sketch_id" ON "public"."emails" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_individuals_individuals_sketch_id" ON "public"."individuals_individuals" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_individuals_sketch_id" ON "public"."individuals" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_investigations_id" ON "public"."investigations" USING "btree" ("id"); - - - -CREATE INDEX "idx_investigations_owner_id" ON "public"."investigations" USING "btree" ("owner_id"); - - - -CREATE INDEX "idx_investigations_profiles_investigation_id" ON "public"."investigations_profiles" USING "btree" ("investigation_id"); - - - -CREATE INDEX "idx_investigations_profiles_profile_id" ON "public"."investigations_profiles" USING "btree" ("profile_id"); - - - -CREATE INDEX "idx_ip_addresses_sketch_id" ON "public"."ip_addresses" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_organizations_individuals_sketch_id" ON "public"."organizations_individuals" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_organizations_organizations_sketch_id" ON "public"."organizations_organizations" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_organizations_sketch_id" ON "public"."organizations" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_phones_sketch_id" ON "public"."phones" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_scans_sketch_id" ON "public"."scans" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_sketches_investigation_id" ON "public"."sketches" USING "btree" ("investigation_id"); - - - -CREATE INDEX "idx_sketches_owner_id" ON "public"."sketches" USING "btree" ("owner_id"); - - - -CREATE INDEX "idx_sketches_profiles_profile_id" ON "public"."sketches_profiles" USING "btree" ("profile_id"); - - - -CREATE INDEX "idx_sketches_profiles_sketch_id" ON "public"."sketches_profiles" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_social_accounts_sketch_id" ON "public"."social_accounts" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_vehicles_sketch_id" ON "public"."vehicles" USING "btree" ("sketch_id"); - - - -CREATE INDEX "idx_websites_sketch_id" ON "public"."websites" USING "btree" ("sketch_id"); - - - -CREATE OR REPLACE VIEW "public"."sketch_graph" WITH ("security_invoker"='on') AS - WITH "individual_data" AS ( - SELECT "i"."id", - "i"."full_name", - "i"."sketch_id", - "json_agg"(DISTINCT "jsonb_build_object"('id', "e_1"."id", 'email', "e_1"."email")) FILTER (WHERE ("e_1"."id" IS NOT NULL)) AS "emails", - "json_agg"(DISTINCT "jsonb_build_object"('id', "p"."id", 'phone_number', "p"."phone_number")) FILTER (WHERE ("p"."id" IS NOT NULL)) AS "phones", - "json_agg"(DISTINCT "jsonb_build_object"('id', "s"."id", 'platform', "s"."platform", 'username', "s"."username")) FILTER (WHERE ("s"."id" IS NOT NULL)) AS "social_accounts", - "json_agg"(DISTINCT "jsonb_build_object"('id', "ip"."id", 'ip_address', "ip"."ip_address")) FILTER (WHERE ("ip"."id" IS NOT NULL)) AS "ip_addresses", - "json_agg"(DISTINCT "jsonb_build_object"('id', "v"."id", 'plate', "v"."plate", 'model', "v"."model", 'brand', "v"."brand", 'type', "v"."type")) FILTER (WHERE ("v"."id" IS NOT NULL)) AS "vehicles", - "json_agg"(DISTINCT "jsonb_build_object"('id', "w"."id", 'url', "w"."url", 'registration_date', "w"."registration_date", 'registrar', "w"."registrar", 'ip_address', "w"."ip_address")) FILTER (WHERE ("w"."id" IS NOT NULL)) AS "websites", - "json_agg"(DISTINCT "jsonb_build_object"('id', "pa"."id", 'address', "pa"."address", 'city', "pa"."city", 'country', "pa"."country")) FILTER (WHERE ("pa"."id" IS NOT NULL)) AS "physical_addresses" - FROM ((((((("public"."individuals" "i" - LEFT JOIN "public"."emails" "e_1" ON (("i"."id" = "e_1"."individual_id"))) - LEFT JOIN "public"."phones" "p" ON (("i"."id" = "p"."individual_id"))) - LEFT JOIN "public"."social_accounts" "s" ON (("i"."id" = "s"."individual_id"))) - LEFT JOIN "public"."ip_addresses" "ip" ON (("i"."id" = "ip"."individual_id"))) - LEFT JOIN "public"."vehicles" "v" ON (("i"."id" = "v"."individual_id"))) - LEFT JOIN "public"."websites" "w" ON (("i"."id" = "w"."individual_id"))) - LEFT JOIN "public"."physical_addresses" "pa" ON (("i"."id" = "pa"."individual_id"))) - GROUP BY "i"."id" - ), "organization_data" AS ( - SELECT "o"."id", - "o"."name", - "o"."registration_number", - "o"."founding_date", - "o"."sketch_id", - "json_agg"(DISTINCT "jsonb_build_object"('id', "poa"."id", 'address', "poa"."address", 'city', "poa"."city", 'country', "poa"."country")) FILTER (WHERE ("poa"."id" IS NOT NULL)) AS "addresses", - "json_agg"(DISTINCT "jsonb_build_object"('id', "op"."id", 'phone_number', "op"."phone_number")) FILTER (WHERE ("op"."id" IS NOT NULL)) AS "phones", - "json_agg"(DISTINCT "jsonb_build_object"('id', "e_1"."id", 'email', "e_1"."email")) FILTER (WHERE ("e_1"."id" IS NOT NULL)) AS "emails", - "json_agg"(DISTINCT "jsonb_build_object"('id', "s"."id", 'platform', "s"."platform", 'username', "s"."username")) FILTER (WHERE ("s"."id" IS NOT NULL)) AS "social_accounts", - "json_agg"(DISTINCT "jsonb_build_object"('id', "ip"."id", 'ip_address', "ip"."ip_address")) FILTER (WHERE ("ip"."id" IS NOT NULL)) AS "ip_addresses", - "json_agg"(DISTINCT "jsonb_build_object"('id', "v"."id", 'plate', "v"."plate", 'model', "v"."model", 'type', "v"."type", 'brand', "v"."brand")) FILTER (WHERE ("v"."id" IS NOT NULL)) AS "vehicles", - "json_agg"(DISTINCT "jsonb_build_object"('id', "w"."id", 'url', "w"."url", 'registration_date', "w"."registration_date", 'registrar', "w"."registrar", 'ip_address', "w"."ip_address")) FILTER (WHERE ("w"."id" IS NOT NULL)) AS "websites" - FROM ((((((("public"."organizations" "o" - LEFT JOIN "public"."physical_addresses" "poa" ON (("poa"."organization_id" = "o"."id"))) - LEFT JOIN "public"."phones" "op" ON (("op"."organization_id" = "o"."id"))) - LEFT JOIN "public"."emails" "e_1" ON (("e_1"."organization_id" = "o"."id"))) - LEFT JOIN "public"."social_accounts" "s" ON (("s"."organization_id" = "o"."id"))) - LEFT JOIN "public"."ip_addresses" "ip" ON (("ip"."organization_id" = "o"."id"))) - LEFT JOIN "public"."vehicles" "v" ON (("v"."organization_id" = "o"."id"))) - LEFT JOIN "public"."websites" "w" ON (("w"."organization_id" = "o"."id"))) - GROUP BY "o"."id" - ), "individual_nodes" AS ( - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("id"."id")::"text", 'type', 'custom', 'data', "jsonb_build_object"('id', "id"."id", 'full_name', "id"."full_name", 'label', "id"."full_name", 'type', 'individual'), 'position', "jsonb_build_object"('x', 0, 'y', 100)) AS "node" - FROM "individual_data" "id" - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("e_1"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("e_1"."value" ->> 'id'::"text"), 'email', ("e_1"."value" ->> 'email'::"text"), 'label', ("e_1"."value" ->> 'email'::"text"), 'type', 'email'), 'position', "jsonb_build_object"('x', 100, 'y', 100)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."emails") "e_1"("value") - WHERE (("e_1"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("p"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("p"."value" ->> 'id'::"text"), 'phone_number', ("p"."value" ->> 'phone_number'::"text"), 'label', ("p"."value" ->> 'phone_number'::"text"), 'type', 'phone'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', 100)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."phones") "p"("value") - WHERE (("p"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("s"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("s"."value" ->> 'id'::"text"), 'platform', ("s"."value" ->> 'platform'::"text"), 'username', ("s"."value" ->> 'username'::"text"), 'label', "concat"(("s"."value" ->> 'platform'::"text"), ': ', ("s"."value" ->> 'username'::"text")), 'type', 'social'), 'position', "jsonb_build_object"('x', 100, 'y', '-100'::integer)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."social_accounts") "s"("value") - WHERE (("s"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("ip"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("ip"."value" ->> 'id'::"text"), 'ip_address', ("ip"."value" ->> 'ip_address'::"text"), 'label', ("ip"."value" ->> 'ip_address'::"text"), 'type', 'ip'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', '-100'::integer)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."ip_addresses") "ip"("value") - WHERE (("ip"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("v"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("v"."value" ->> 'id'::"text"), 'plate', ("v"."value" ->> 'plate'::"text"), 'brand', ("v"."value" ->> 'brand'::"text"), 'model', ("v"."value" ->> 'model'::"text"), 'label', "concat"(("v"."value" ->> 'brand'::"text"), ' ', ("v"."value" ->> 'model'::"text"), ': ', ("v"."value" ->> 'plate'::"text")), 'type', 'vehicle'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', '-100'::integer)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."vehicles") "v"("value") - WHERE (("v"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("pa"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("pa"."value" ->> 'id'::"text"), 'address', ("pa"."value" ->> 'address'::"text"), 'city', ("pa"."value" ->> 'city'::"text"), 'country', ("pa"."value" ->> 'country'::"text"), 'label', "concat"(("pa"."value" ->> 'address'::"text"), ', ', ("pa"."value" ->> 'city'::"text"), ', ', ("pa"."value" ->> 'country'::"text")), 'type', 'address'), 'position', "jsonb_build_object"('x', 100, 'y', 100)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."physical_addresses") "pa"("value") - WHERE (("pa"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', ("w"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("w"."value" ->> 'id'::"text"), 'url', ("w"."value" ->> 'url'::"text"), 'registration_date', ("w"."value" ->> 'registration_date'::"text"), 'registrar', ("w"."value" ->> 'registrar'::"text"), 'ip_address', ("w"."value" ->> 'ip_address'::"text"), 'label', ("w"."value" ->> 'url'::"text"), 'type', 'website'), 'position', "jsonb_build_object"('x', 200, 'y', '-50'::integer)) AS "node" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."websites") "w"("value") - WHERE (("w"."value" ->> 'id'::"text") IS NOT NULL) - ), "organization_nodes" AS ( - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("od"."id")::"text", 'type', 'custom', 'data', "jsonb_build_object"('id', "od"."id", 'name', "od"."name", 'registration_number', "od"."registration_number", 'founding_date', "od"."founding_date", 'label', "od"."name", 'type', 'organization'), 'position', "jsonb_build_object"('x', 200, 'y', 0)) AS "node" - FROM "organization_data" "od" - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("a"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("a"."value" ->> 'id'::"text"), 'address', ("a"."value" ->> 'address'::"text"), 'city', ("a"."value" ->> 'city'::"text"), 'country', ("a"."value" ->> 'country'::"text"), 'label', "concat"(("a"."value" ->> 'address'::"text"), ', ', ("a"."value" ->> 'city'::"text"), ', ', ("a"."value" ->> 'country'::"text")), 'type', 'address'), 'position', "jsonb_build_object"('x', 100, 'y', 100)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."addresses") "a"("value") - WHERE (("a"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("p"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("p"."value" ->> 'id'::"text"), 'phone_number', ("p"."value" ->> 'phone_number'::"text"), 'label', ("p"."value" ->> 'phone_number'::"text"), 'type', 'phone'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', 100)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."phones") "p"("value") - WHERE (("p"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("e_1"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("e_1"."value" ->> 'id'::"text"), 'email', ("e_1"."value" ->> 'email'::"text"), 'label', ("e_1"."value" ->> 'email'::"text"), 'type', 'email'), 'position', "jsonb_build_object"('x', 100, 'y', 100)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."emails") "e_1"("value") - WHERE (("e_1"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("s"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("s"."value" ->> 'id'::"text"), 'platform', ("s"."value" ->> 'platform'::"text"), 'username', ("s"."value" ->> 'username'::"text"), 'label', "concat"(("s"."value" ->> 'platform'::"text"), ': ', ("s"."value" ->> 'username'::"text")), 'type', 'social'), 'position', "jsonb_build_object"('x', 100, 'y', '-100'::integer)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."social_accounts") "s"("value") - WHERE (("s"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("ip"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("ip"."value" ->> 'id'::"text"), 'ip_address', ("ip"."value" ->> 'ip_address'::"text"), 'label', ("ip"."value" ->> 'ip_address'::"text"), 'type', 'ip'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', '-100'::integer)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."ip_addresses") "ip"("value") - WHERE (("ip"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("v"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("v"."value" ->> 'id'::"text"), 'plate', ("v"."value" ->> 'plate'::"text"), 'brand', ("v"."value" ->> 'brand'::"text"), 'model', ("v"."value" ->> 'model'::"text"), 'label', "concat"(("v"."value" ->> 'brand'::"text"), ' ', ("v"."value" ->> 'model'::"text"), ': ', ("v"."value" ->> 'plate'::"text")), 'type', 'vehicle'), 'position', "jsonb_build_object"('x', '-100'::integer, 'y', '-100'::integer)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."vehicles") "v"("value") - WHERE (("v"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', ("w"."value" ->> 'id'::"text"), 'type', 'custom', 'data', "jsonb_build_object"('id', ("w"."value" ->> 'id'::"text"), 'url', ("w"."value" ->> 'url'::"text"), 'registration_date', ("w"."value" ->> 'registration_date'::"text"), 'registrar', ("w"."value" ->> 'registrar'::"text"), 'ip_address', ("w"."value" ->> 'ip_address'::"text"), 'label', ("w"."value" ->> 'url'::"text"), 'type', 'website'), 'position', "jsonb_build_object"('x', 200, 'y', '-50'::integer)) AS "node" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."websites") "w"("value") - WHERE (("w"."value" ->> 'id'::"text") IS NOT NULL) - ), "individual_edges" AS ( - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("e_1"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("e_1"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'email') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."emails") "e_1"("value") - WHERE (("e_1"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("p"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("p"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'phone') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."phones") "p"("value") - WHERE (("p"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("s"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("s"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'social') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."social_accounts") "s"("value") - WHERE (("s"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("ip"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("ip"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'IP') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."ip_addresses") "ip"("value") - WHERE (("ip"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("v"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("v"."value" ->> 'id'::"text"), 'type', 'custom', 'label', ("v"."value" ->> 'type'::"text")) AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."vehicles") "v"("value") - WHERE (("v"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("pa"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("pa"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'address') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."physical_addresses") "pa"("value") - WHERE (("pa"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "id"."sketch_id", - "jsonb_build_object"('id', "concat"("id"."id", '-', ("w"."value" ->> 'id'::"text")), 'source', ("id"."id")::"text", 'target', ("w"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'website') AS "edge" - FROM "individual_data" "id", - LATERAL "json_array_elements"("id"."websites") "w"("value") - WHERE (("w"."value" ->> 'id'::"text") IS NOT NULL) - ), "organization_edges" AS ( - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("a"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("a"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'address') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."addresses") "a"("value") - WHERE (("a"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("p"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("p"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'phone') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."phones") "p"("value") - WHERE (("p"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("e_1"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("e_1"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'email') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."emails") "e_1"("value") - WHERE (("e_1"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("s"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("s"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'social') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."social_accounts") "s"("value") - WHERE (("s"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("ip"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("ip"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'IP') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."ip_addresses") "ip"("value") - WHERE (("ip"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("v"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("v"."value" ->> 'id'::"text"), 'type', 'custom', 'label', ("v"."value" ->> 'type'::"text")) AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."vehicles") "v"("value") - WHERE (("v"."value" ->> 'id'::"text") IS NOT NULL) - UNION ALL - SELECT "od"."sketch_id", - "jsonb_build_object"('id', "concat"("od"."id", '-', ("w"."value" ->> 'id'::"text")), 'source', ("od"."id")::"text", 'target', ("w"."value" ->> 'id'::"text"), 'type', 'custom', 'label', 'website') AS "edge" - FROM "organization_data" "od", - LATERAL "json_array_elements"("od"."websites") "w"("value") - WHERE (("w"."value" ->> 'id'::"text") IS NOT NULL) - ), "debug_relationships" AS ( - SELECT "individuals_individuals"."sketch_id", - "count"(*) AS "relationship_count" - FROM "public"."individuals_individuals" - GROUP BY "individuals_individuals"."sketch_id" - ), "relationship_edges" AS ( - SELECT "r"."sketch_id", - "jsonb_build_object"('id', ("r"."id")::"text", 'source', ("r"."individual_a")::"text", 'target', ("r"."individual_b")::"text", 'type', 'custom', 'label', COALESCE("r"."relation_type", 'related'::"text"), 'data', "jsonb_build_object"('confidence_level', "r"."confidence_level", 'relation_type', "r"."relation_type")) AS "edge" - FROM "public"."individuals_individuals" "r" - WHERE (("r"."individual_a" IS NOT NULL) AND ("r"."individual_b" IS NOT NULL)) - ), "orgs_individuals_edges" AS ( - SELECT "r"."sketch_id", - "jsonb_build_object"('id', ("r"."id")::"text", 'source', ("r"."organization_id")::"text", 'target', ("r"."individual_id")::"text", 'type', 'custom', 'label', COALESCE("r"."relation_type", 'employee'::"text"), 'data', "jsonb_build_object"('relation_type', "r"."relation_type")) AS "edge" - FROM "public"."organizations_individuals" "r" - WHERE (("r"."organization_id" IS NOT NULL) AND ("r"."individual_id" IS NOT NULL)) - ), "orgs_organizations_edges" AS ( - SELECT "oo"."sketch_id", - "jsonb_build_object"('id', ("oo"."id")::"text", 'source', ("oo"."organization_a")::"text", 'target', ("oo"."organization_b")::"text", 'type', 'custom', 'label', COALESCE("oo"."relation_type", 'related'::"text"), 'data', "jsonb_build_object"('relation_type', "oo"."relation_type")) AS "edge" - FROM "public"."organizations_organizations" "oo" - WHERE (("oo"."organization_a" IS NOT NULL) AND ("oo"."organization_b" IS NOT NULL)) - ), "nodes_by_investigation" AS ( - SELECT "all_nodes"."sketch_id", - "json_agg"("all_nodes"."node") AS "nodes" - FROM ( SELECT "individual_nodes"."sketch_id", - "individual_nodes"."node" - FROM "individual_nodes" - UNION ALL - SELECT "organization_nodes"."sketch_id", - "organization_nodes"."node" - FROM "organization_nodes") "all_nodes" - GROUP BY "all_nodes"."sketch_id" - ), "edges_by_investigation" AS ( - SELECT "all_edges"."sketch_id", - "json_agg"("all_edges"."edge") AS "edges" - FROM ( SELECT "individual_edges"."sketch_id", - "individual_edges"."edge" - FROM "individual_edges" - UNION ALL - SELECT "organization_edges"."sketch_id", - "organization_edges"."edge" - FROM "organization_edges" - UNION ALL - SELECT "relationship_edges"."sketch_id", - "relationship_edges"."edge" - FROM "relationship_edges" - UNION ALL - SELECT "orgs_individuals_edges"."sketch_id", - "orgs_individuals_edges"."edge" - FROM "orgs_individuals_edges" - UNION ALL - SELECT "orgs_organizations_edges"."sketch_id", - "orgs_organizations_edges"."edge" - FROM "orgs_organizations_edges") "all_edges" - GROUP BY "all_edges"."sketch_id" - ) - SELECT "inv"."id" AS "sketch_id", - COALESCE("n"."nodes", '[]'::"json") AS "nodes", - COALESCE("e"."edges", '[]'::"json") AS "edges", - "dr"."relationship_count" AS "debug_relationship_count" - FROM ((("public"."sketches" "inv" - LEFT JOIN "nodes_by_investigation" "n" ON (("n"."sketch_id" = "inv"."id"))) - LEFT JOIN "edges_by_investigation" "e" ON (("e"."sketch_id" = "inv"."id"))) - LEFT JOIN "debug_relationships" "dr" ON (("dr"."sketch_id" = "inv"."id"))); - - - -CREATE OR REPLACE TRIGGER "on_investigation_insert" AFTER INSERT ON "public"."investigations" FOR EACH ROW EXECUTE FUNCTION "public"."handle_new_investigation"(); - - - -CREATE OR REPLACE TRIGGER "on_sketch_insert" AFTER INSERT ON "public"."sketches" FOR EACH ROW EXECUTE FUNCTION "public"."handle_new_sketch"(); - - - -CREATE OR REPLACE TRIGGER "trg_sync_investigation_profile" AFTER INSERT ON "public"."sketches_profiles" FOR EACH ROW EXECUTE FUNCTION "public"."sync_investigation_profile_from_sketch"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_emails" AFTER INSERT OR DELETE OR UPDATE ON "public"."emails" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_individuals" AFTER INSERT OR DELETE OR UPDATE ON "public"."individuals" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_ip_addresses" AFTER INSERT OR DELETE OR UPDATE ON "public"."ip_addresses" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_phones" AFTER INSERT OR DELETE OR UPDATE ON "public"."phones" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_physical_addresses" AFTER INSERT OR DELETE OR UPDATE ON "public"."physical_addresses" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_relationships" AFTER INSERT OR DELETE OR UPDATE ON "public"."individuals_individuals" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "trigger_update_project_last_updated_social_accounts" AFTER INSERT OR DELETE OR UPDATE ON "public"."social_accounts" FOR EACH ROW EXECUTE FUNCTION "public"."update_investigation_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "update_investigation_last_updated" AFTER UPDATE ON "public"."sketches" FOR EACH ROW EXECUTE FUNCTION "public"."update_sketch_last_updated"(); - - - -CREATE OR REPLACE TRIGGER "update_last_updated_at_trigger" AFTER UPDATE ON "public"."sketches" FOR EACH ROW EXECUTE FUNCTION "public"."update_last_updated_at"(); - - - -ALTER TABLE ONLY "public"."accounts_breaches" - ADD CONSTRAINT "accounts_breaches_breach_id_fkey" FOREIGN KEY ("breach_id") REFERENCES "public"."breaches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."emails" - ADD CONSTRAINT "emails_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."emails" - ADD CONSTRAINT "emails_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."emails" - ADD CONSTRAINT "emails_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."feedbacks" - ADD CONSTRAINT "feedbacks_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "public"."profiles"("id"); - - - -ALTER TABLE ONLY "public"."groups" - ADD CONSTRAINT "groups_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id"); - - - -ALTER TABLE ONLY "public"."individuals" - ADD CONSTRAINT "individuals_group_id_fkey" FOREIGN KEY ("group_id") REFERENCES "public"."groups"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."individuals" - ADD CONSTRAINT "individuals_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."investigations" - ADD CONSTRAINT "investigations_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "public"."profiles"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."sketches_profiles" - ADD CONSTRAINT "investigations_profiles_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profiles"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."sketches" - ADD CONSTRAINT "investigations_project_id_fkey" FOREIGN KEY ("investigation_id") REFERENCES "public"."investigations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."ip_addresses" - ADD CONSTRAINT "ip_addresses_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."ip_addresses" - ADD CONSTRAINT "ip_addresses_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."ip_addresses" - ADD CONSTRAINT "ip_addresses_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_individuals" - ADD CONSTRAINT "organizations_individuals_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_individuals" - ADD CONSTRAINT "organizations_individuals_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_individuals" - ADD CONSTRAINT "organizations_individuals_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_organizations" - ADD CONSTRAINT "organizations_organizations_organization_a_fkey" FOREIGN KEY ("organization_a") REFERENCES "public"."organizations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_organizations" - ADD CONSTRAINT "organizations_organizations_organization_b_fkey" FOREIGN KEY ("organization_b") REFERENCES "public"."organizations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations_organizations" - ADD CONSTRAINT "organizations_organizations_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."organizations" - ADD CONSTRAINT "organizations_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."phones" - ADD CONSTRAINT "phones_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."phones" - ADD CONSTRAINT "phones_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."phones" - ADD CONSTRAINT "phones_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."physical_addresses" - ADD CONSTRAINT "physical_addresses_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."physical_addresses" - ADD CONSTRAINT "physical_addresses_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."physical_addresses" - ADD CONSTRAINT "physical_addresses_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."profiles" - ADD CONSTRAINT "profiles_id_fkey" FOREIGN KEY ("id") REFERENCES "auth"."users"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."investigations_profiles" - ADD CONSTRAINT "projects_profiles_profile_id_fkey" FOREIGN KEY ("profile_id") REFERENCES "public"."profiles"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."investigations_profiles" - ADD CONSTRAINT "projects_profiles_project_id_fkey" FOREIGN KEY ("investigation_id") REFERENCES "public"."investigations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "relationships_individual_a_fkey" FOREIGN KEY ("individual_a") REFERENCES "public"."individuals"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "relationships_individual_b_fkey" FOREIGN KEY ("individual_b") REFERENCES "public"."individuals"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."individuals_individuals" - ADD CONSTRAINT "relationships_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."scans" - ADD CONSTRAINT "scans_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."sketches" - ADD CONSTRAINT "sketches_owner_id_fkey" FOREIGN KEY ("owner_id") REFERENCES "public"."profiles"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."sketches_profiles" - ADD CONSTRAINT "sketches_profiles_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."social_accounts" - ADD CONSTRAINT "social_accounts_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."social_accounts" - ADD CONSTRAINT "social_accounts_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."social_accounts" - ADD CONSTRAINT "social_accounts_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."vehicles" - ADD CONSTRAINT "vehicles_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON UPDATE CASCADE ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."vehicles" - ADD CONSTRAINT "vehicles_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON DELETE SET NULL; - - - -ALTER TABLE ONLY "public"."vehicles" - ADD CONSTRAINT "vehicles_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."websites" - ADD CONSTRAINT "websites_individual_id_fkey" FOREIGN KEY ("individual_id") REFERENCES "public"."individuals"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."websites" - ADD CONSTRAINT "websites_organization_id_fkey" FOREIGN KEY ("organization_id") REFERENCES "public"."organizations"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -ALTER TABLE ONLY "public"."websites" - ADD CONSTRAINT "websites_sketch_id_fkey" FOREIGN KEY ("sketch_id") REFERENCES "public"."sketches"("id") ON UPDATE CASCADE ON DELETE CASCADE; - - - -CREATE POLICY "Can create sketches in investigations you are part of" ON "public"."sketches" FOR INSERT TO "authenticated" WITH CHECK (((EXISTS ( SELECT 1 - FROM "public"."investigations_profiles" "ip" - WHERE (("ip"."investigation_id" = "sketches"."investigation_id") AND ("ip"."profile_id" = "auth"."uid"())))) OR ("auth"."uid"() = "owner_id"))); - - - -CREATE POLICY "Can delete emails if you have access to the sketch" ON "public"."emails" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "emails"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete individuals if you have access to the sketch" ON "public"."individuals" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete individuals_individuals if you have access to the sk" ON "public"."individuals_individuals" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete ip_addresses if you have access to the sketch" ON "public"."ip_addresses" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "ip_addresses"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete organizations if you have access to the sketch" ON "public"."organizations" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete organizations_individuals if you have access to the " ON "public"."organizations_individuals" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete organizations_organizations if you have access to th" ON "public"."organizations_organizations" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete phones if you have access to the sketch" ON "public"."phones" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "phones"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete scans if you have access to the sketch" ON "public"."scans" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "scans"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete social_accounts if you have access to the sketch" ON "public"."social_accounts" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "social_accounts"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete vehicles if you have access to the sketch" ON "public"."vehicles" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "vehicles"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can delete websites if you have access to the sketch" ON "public"."websites" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "websites"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert emails if you have access to the sketch" ON "public"."emails" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "emails"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert individuals if you have access to the sketch" ON "public"."individuals" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert individuals_individuals if you have access to the sk" ON "public"."individuals_individuals" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert ip_addresses if you have access to the sketch" ON "public"."ip_addresses" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "ip_addresses"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert organizations if you have access to the sketch" ON "public"."organizations" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert organizations_individuals if you have access to the " ON "public"."organizations_individuals" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert organizations_organizations if you have access to th" ON "public"."organizations_organizations" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert phones if you have access to the sketch" ON "public"."phones" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "phones"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert scans if you have access to the sketch" ON "public"."scans" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "scans"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert social_accounts if you have access to the sketch" ON "public"."social_accounts" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "social_accounts"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert vehicles if you have access to the sketch" ON "public"."vehicles" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "vehicles"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can insert websites if you have access to the sketch" ON "public"."websites" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "websites"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read all profiles in investigations you are part of" ON "public"."investigations_profiles" FOR SELECT TO "authenticated" USING (true); - - - -CREATE POLICY "Can read all sketches in investigations you are part of" ON "public"."sketches" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "ip" - WHERE ((("ip"."sketch_id" = "sketches"."id") AND ("ip"."profile_id" = "auth"."uid"())) OR ("sketches"."owner_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read emails if you have access to the sketch" ON "public"."emails" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "emails"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read individuals if you have access to the sketch" ON "public"."individuals" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read individuals_individuals if you have access to the sket" ON "public"."individuals_individuals" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read ip_addresses if you have access to the sketch" ON "public"."ip_addresses" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "ip_addresses"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read organizations if you have access to the sketch" ON "public"."organizations" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read organizations_individuals if you have access to the sk" ON "public"."organizations_individuals" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read organizations_organizations if you have access to the " ON "public"."organizations_organizations" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read phones if you have access to the sketch" ON "public"."phones" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "phones"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read profiles in sketches if you have access to the investi" ON "public"."sketches_profiles" FOR SELECT TO "authenticated" USING (true); - - - -CREATE POLICY "Can read scans if you have access to the sketch" ON "public"."scans" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "scans"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read social_accounts if you have access to the sketch" ON "public"."social_accounts" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "social_accounts"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read vehicles if you have access to the sketch" ON "public"."vehicles" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "vehicles"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can read websites if you have access to the sketch" ON "public"."websites" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "websites"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update emails if you have access to the sketch" ON "public"."emails" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "emails"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update individuals if you have access to the sketch" ON "public"."individuals" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update individuals_individuals if you have access to the sk" ON "public"."individuals_individuals" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "individuals_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update ip_addresses if you have access to the sketch" ON "public"."ip_addresses" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "ip_addresses"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update organizations if you have access to the sketch" ON "public"."organizations" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update organizations_individuals if you have access to the " ON "public"."organizations_individuals" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_individuals"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update organizations_organizations if you have access to th" ON "public"."organizations_organizations" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "organizations_organizations"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update phones if you have access to the sketch" ON "public"."phones" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "phones"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update scans if you have access to the sketch" ON "public"."scans" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "scans"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update social_accounts if you have access to the sketch" ON "public"."social_accounts" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "social_accounts"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update vehicles if you have access to the sketch" ON "public"."vehicles" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "vehicles"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Can update websites if you have access to the sketch" ON "public"."websites" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "sp" - WHERE (("sp"."sketch_id" = "websites"."sketch_id") AND ("sp"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Members can edit their own sketch profile" ON "public"."sketches_profiles" FOR UPDATE TO "authenticated" USING (("profile_id" = "auth"."uid"())); - - - -CREATE POLICY "Members can update own investigations" ON "public"."investigations" FOR UPDATE TO "authenticated" USING ((("auth"."uid"() = "owner_id") OR (EXISTS ( SELECT 1 - FROM "public"."investigations_profiles" "ip" - WHERE (("ip"."investigation_id" = "investigations"."id") AND ("ip"."profile_id" = "auth"."uid"())))))); - - - -CREATE POLICY "Members of investigations_profiles can read investigation" ON "public"."investigations" FOR SELECT TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."investigations_profiles" "ip" - WHERE (("ip"."investigation_id" = "investigations"."id") AND ("ip"."profile_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Only investigation owner can add members" ON "public"."investigations_profiles" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."investigations" - WHERE (("investigations"."id" = "investigations_profiles"."investigation_id") AND ("investigations"."owner_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Only investigation owner can delete profiles" ON "public"."investigations_profiles" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."investigations" - WHERE (("investigations"."id" = "investigations_profiles"."investigation_id") AND ("investigations"."owner_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Only investigation owner can update profiles" ON "public"."investigations_profiles" FOR UPDATE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."investigations" - WHERE (("investigations"."id" = "investigations_profiles"."investigation_id") AND ("investigations"."owner_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Only owner can add profiles to sketches" ON "public"."sketches_profiles" FOR INSERT TO "authenticated" WITH CHECK ((EXISTS ( SELECT 1 - FROM "public"."sketches" "s" - WHERE ("s"."owner_id" = "auth"."uid"())))); - - - -CREATE POLICY "Only owner can delete profiles from sketches" ON "public"."sketches_profiles" FOR DELETE TO "authenticated" USING ((EXISTS ( SELECT 1 - FROM "public"."sketches" "s" - WHERE (("s"."id" = "sketches_profiles"."sketch_id") AND ("s"."owner_id" = "auth"."uid"()))))); - - - -CREATE POLICY "Only owner or sketch creator can delete their sketch" ON "public"."sketches" FOR DELETE TO "authenticated" USING (((EXISTS ( SELECT 1 - FROM "public"."investigations" "i" - WHERE (("i"."id" = "sketches"."investigation_id") AND ("i"."owner_id" = "auth"."uid"())))) OR ("owner_id" = "auth"."uid"()))); - - - -CREATE POLICY "Owner can delete own investigations" ON "public"."investigations" FOR DELETE TO "authenticated" USING (("auth"."uid"() = "owner_id")); - - - -CREATE POLICY "Owner can read own investigations" ON "public"."investigations" FOR SELECT TO "authenticated" USING (("auth"."uid"() = "owner_id")); - - - -CREATE POLICY "Sketch members can update their sketch" ON "public"."sketches" FOR UPDATE TO "authenticated" USING (((EXISTS ( SELECT 1 - FROM "public"."sketches_profiles" "i" - WHERE (("i"."sketch_id" = "sketches"."id") AND ("i"."profile_id" = "auth"."uid"())))) OR ("auth"."uid"() = "owner_id"))); - - - -CREATE POLICY "Users can delete their own profiles" ON "public"."profiles" FOR DELETE TO "authenticated" USING (("auth"."uid"() = "id")); - - - -CREATE POLICY "Users can insert their own investigations" ON "public"."investigations" FOR INSERT TO "authenticated" WITH CHECK (("auth"."uid"() = "owner_id")); - - - -CREATE POLICY "Users can insert their own profiles" ON "public"."profiles" FOR INSERT TO "authenticated" WITH CHECK (("auth"."uid"() IS NOT NULL)); - - - -CREATE POLICY "Users can update their own profiles" ON "public"."profiles" FOR UPDATE TO "authenticated" USING (("auth"."uid"() = "id")) WITH CHECK (("auth"."uid"() = "id")); - - - -CREATE POLICY "Users can view their own profiles" ON "public"."profiles" FOR SELECT TO "authenticated" USING (true); - - - -ALTER TABLE "public"."accounts_breaches" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."breaches" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."emails" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."feedbacks" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."groups" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."individuals" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."individuals_individuals" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."investigations" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."investigations_profiles" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."ip_addresses" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."organizations" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."organizations_individuals" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."organizations_organizations" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."phones" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."physical_addresses" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."profiles" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."sketches" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."sketches_profiles" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."social_accounts" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."vehicles" ENABLE ROW LEVEL SECURITY; - - -ALTER TABLE "public"."websites" ENABLE ROW LEVEL SECURITY; - - - - -ALTER PUBLICATION "supabase_realtime" OWNER TO "postgres"; - - - - - - -ALTER PUBLICATION "supabase_realtime" ADD TABLE ONLY "public"."scans"; - - - -ALTER PUBLICATION "supabase_realtime" ADD TABLE ONLY "public"."sketches"; - - - -GRANT USAGE ON SCHEMA "public" TO "postgres"; -GRANT USAGE ON SCHEMA "public" TO "anon"; -GRANT USAGE ON SCHEMA "public" TO "authenticated"; -GRANT USAGE ON SCHEMA "public" TO "service_role"; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -GRANT ALL ON FUNCTION "public"."handle_new_investigation"() TO "anon"; -GRANT ALL ON FUNCTION "public"."handle_new_investigation"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."handle_new_investigation"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."handle_new_project"() TO "anon"; -GRANT ALL ON FUNCTION "public"."handle_new_project"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."handle_new_project"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."handle_new_sketch"() TO "anon"; -GRANT ALL ON FUNCTION "public"."handle_new_sketch"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."handle_new_sketch"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "anon"; -GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."handle_new_user"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."sync_investigation_profile_from_sketch"() TO "anon"; -GRANT ALL ON FUNCTION "public"."sync_investigation_profile_from_sketch"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."sync_investigation_profile_from_sketch"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."update_investigation_last_updated"() TO "anon"; -GRANT ALL ON FUNCTION "public"."update_investigation_last_updated"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."update_investigation_last_updated"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."update_last_updated_at"() TO "anon"; -GRANT ALL ON FUNCTION "public"."update_last_updated_at"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."update_last_updated_at"() TO "service_role"; - - - -GRANT ALL ON FUNCTION "public"."update_sketch_last_updated"() TO "anon"; -GRANT ALL ON FUNCTION "public"."update_sketch_last_updated"() TO "authenticated"; -GRANT ALL ON FUNCTION "public"."update_sketch_last_updated"() TO "service_role"; - - - - - - - - - - - - - - - - - - -GRANT ALL ON TABLE "public"."accounts_breaches" TO "anon"; -GRANT ALL ON TABLE "public"."accounts_breaches" TO "authenticated"; -GRANT ALL ON TABLE "public"."accounts_breaches" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."accounts_breaches_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."accounts_breaches_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."accounts_breaches_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."breaches" TO "anon"; -GRANT ALL ON TABLE "public"."breaches" TO "authenticated"; -GRANT ALL ON TABLE "public"."breaches" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."breaches_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."breaches_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."breaches_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."emails" TO "anon"; -GRANT ALL ON TABLE "public"."emails" TO "authenticated"; -GRANT ALL ON TABLE "public"."emails" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."feedbacks" TO "anon"; -GRANT ALL ON TABLE "public"."feedbacks" TO "authenticated"; -GRANT ALL ON TABLE "public"."feedbacks" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."feedbacks_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."groups" TO "anon"; -GRANT ALL ON TABLE "public"."groups" TO "authenticated"; -GRANT ALL ON TABLE "public"."groups" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."individuals" TO "anon"; -GRANT ALL ON TABLE "public"."individuals" TO "authenticated"; -GRANT ALL ON TABLE "public"."individuals" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."individuals_individuals" TO "anon"; -GRANT ALL ON TABLE "public"."individuals_individuals" TO "authenticated"; -GRANT ALL ON TABLE "public"."individuals_individuals" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."investigations" TO "anon"; -GRANT ALL ON TABLE "public"."investigations" TO "authenticated"; -GRANT ALL ON TABLE "public"."investigations" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."investigations_profiles" TO "anon"; -GRANT ALL ON TABLE "public"."investigations_profiles" TO "authenticated"; -GRANT ALL ON TABLE "public"."investigations_profiles" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."sketches_profiles" TO "anon"; -GRANT ALL ON TABLE "public"."sketches_profiles" TO "authenticated"; -GRANT ALL ON TABLE "public"."sketches_profiles" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."investigations_profiles_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."investigations_profiles_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."investigations_profiles_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."ip_addresses" TO "anon"; -GRANT ALL ON TABLE "public"."ip_addresses" TO "authenticated"; -GRANT ALL ON TABLE "public"."ip_addresses" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."organizations" TO "anon"; -GRANT ALL ON TABLE "public"."organizations" TO "authenticated"; -GRANT ALL ON TABLE "public"."organizations" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."organizations_individuals" TO "anon"; -GRANT ALL ON TABLE "public"."organizations_individuals" TO "authenticated"; -GRANT ALL ON TABLE "public"."organizations_individuals" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."organizations_organizations" TO "anon"; -GRANT ALL ON TABLE "public"."organizations_organizations" TO "authenticated"; -GRANT ALL ON TABLE "public"."organizations_organizations" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."organization_graph" TO "anon"; -GRANT ALL ON TABLE "public"."organization_graph" TO "authenticated"; -GRANT ALL ON TABLE "public"."organization_graph" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."organizations_organizations_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."organizations_organizations_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."organizations_organizations_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."phones" TO "anon"; -GRANT ALL ON TABLE "public"."phones" TO "authenticated"; -GRANT ALL ON TABLE "public"."phones" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."physical_addresses" TO "anon"; -GRANT ALL ON TABLE "public"."physical_addresses" TO "authenticated"; -GRANT ALL ON TABLE "public"."physical_addresses" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."profiles" TO "anon"; -GRANT ALL ON TABLE "public"."profiles" TO "authenticated"; -GRANT ALL ON TABLE "public"."profiles" TO "service_role"; - - - -GRANT ALL ON SEQUENCE "public"."projects_profiles_id_seq" TO "anon"; -GRANT ALL ON SEQUENCE "public"."projects_profiles_id_seq" TO "authenticated"; -GRANT ALL ON SEQUENCE "public"."projects_profiles_id_seq" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."scans" TO "anon"; -GRANT ALL ON TABLE "public"."scans" TO "authenticated"; -GRANT ALL ON TABLE "public"."scans" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."sketch_graph" TO "anon"; -GRANT ALL ON TABLE "public"."sketch_graph" TO "authenticated"; -GRANT ALL ON TABLE "public"."sketch_graph" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."social_accounts" TO "anon"; -GRANT ALL ON TABLE "public"."social_accounts" TO "authenticated"; -GRANT ALL ON TABLE "public"."social_accounts" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."vehicles" TO "anon"; -GRANT ALL ON TABLE "public"."vehicles" TO "authenticated"; -GRANT ALL ON TABLE "public"."vehicles" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."websites" TO "anon"; -GRANT ALL ON TABLE "public"."websites" TO "authenticated"; -GRANT ALL ON TABLE "public"."websites" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."sketch_table" TO "anon"; -GRANT ALL ON TABLE "public"."sketch_table" TO "authenticated"; -GRANT ALL ON TABLE "public"."sketch_table" TO "service_role"; - - - -GRANT ALL ON TABLE "public"."sketches" TO "anon"; -GRANT ALL ON TABLE "public"."sketches" TO "authenticated"; -GRANT ALL ON TABLE "public"."sketches" TO "service_role"; - - - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON SEQUENCES TO "service_role"; - - - - - - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON FUNCTIONS TO "service_role"; - - - - - - -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "postgres"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "anon"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "authenticated"; -ALTER DEFAULT PRIVILEGES FOR ROLE "postgres" IN SCHEMA "public" GRANT ALL ON TABLES TO "service_role"; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -RESET ALL; diff --git a/backend/volumes/api/kong.yml b/backend/volumes/api/kong.yml deleted file mode 100644 index 7abf425..0000000 --- a/backend/volumes/api/kong.yml +++ /dev/null @@ -1,241 +0,0 @@ -_format_version: '2.1' -_transform: true - -### -### Consumers / Users -### -consumers: - - username: DASHBOARD - - username: anon - keyauth_credentials: - - key: $SUPABASE_ANON_KEY - - username: service_role - keyauth_credentials: - - key: $SUPABASE_SERVICE_KEY - -### -### Access Control List -### -acls: - - consumer: anon - group: anon - - consumer: service_role - group: admin - -### -### Dashboard credentials -### -basicauth_credentials: - - consumer: DASHBOARD - username: $DASHBOARD_USERNAME - password: $DASHBOARD_PASSWORD - -### -### API Routes -### -services: - ## Open Auth routes - - name: auth-v1-open - url: http://auth:9999/verify - routes: - - name: auth-v1-open - strip_path: true - paths: - - /auth/v1/verify - plugins: - - name: cors - - name: auth-v1-open-callback - url: http://auth:9999/callback - routes: - - name: auth-v1-open-callback - strip_path: true - paths: - - /auth/v1/callback - plugins: - - name: cors - - name: auth-v1-open-authorize - url: http://auth:9999/authorize - routes: - - name: auth-v1-open-authorize - strip_path: true - paths: - - /auth/v1/authorize - plugins: - - name: cors - - ## Secure Auth routes - - name: auth-v1 - _comment: 'GoTrue: /auth/v1/* -> http://auth:9999/*' - url: http://auth:9999/ - routes: - - name: auth-v1-all - strip_path: true - paths: - - /auth/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - ## Secure REST routes - - name: rest-v1 - _comment: 'PostgREST: /rest/v1/* -> http://rest:3000/*' - url: http://rest:3000/ - routes: - - name: rest-v1-all - strip_path: true - paths: - - /rest/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: true - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - ## Secure GraphQL routes - - name: graphql-v1 - _comment: 'PostgREST: /graphql/v1/* -> http://rest:3000/rpc/graphql' - url: http://rest:3000/rpc/graphql - routes: - - name: graphql-v1-all - strip_path: true - paths: - - /graphql/v1 - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: true - - name: request-transformer - config: - add: - headers: - - Content-Profile:graphql_public - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - ## Secure Realtime routes - - name: realtime-v1-ws - _comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*' - url: http://realtime-dev.supabase-realtime:4000/socket - protocol: ws - routes: - - name: realtime-v1-ws - strip_path: true - paths: - - /realtime/v1/ - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - - name: realtime-v1-rest - _comment: 'Realtime: /realtime/v1/* -> ws://realtime:4000/socket/*' - url: http://realtime-dev.supabase-realtime:4000/api - protocol: http - routes: - - name: realtime-v1-rest - strip_path: true - paths: - - /realtime/v1/api - plugins: - - name: cors - - name: key-auth - config: - hide_credentials: false - - name: acl - config: - hide_groups_header: true - allow: - - admin - - anon - ## Storage routes: the storage server manages its own auth - - name: storage-v1 - _comment: 'Storage: /storage/v1/* -> http://storage:5000/*' - url: http://storage:5000/ - routes: - - name: storage-v1-all - strip_path: true - paths: - - /storage/v1/ - plugins: - - name: cors - - ## Edge Functions routes - - name: functions-v1 - _comment: 'Edge Functions: /functions/v1/* -> http://functions:9000/*' - url: http://functions:9000/ - routes: - - name: functions-v1-all - strip_path: true - paths: - - /functions/v1/ - plugins: - - name: cors - - ## Analytics routes - - name: analytics-v1 - _comment: 'Analytics: /analytics/v1/* -> http://logflare:4000/*' - url: http://analytics:4000/ - routes: - - name: analytics-v1-all - strip_path: true - paths: - - /analytics/v1/ - - ## Secure Database routes - - name: meta - _comment: 'pg-meta: /pg/* -> http://pg-meta:8080/*' - url: http://meta:8080/ - routes: - - name: meta-all - strip_path: true - paths: - - /pg/ - plugins: - - name: key-auth - config: - hide_credentials: false - - name: acl - config: - hide_groups_header: true - allow: - - admin - - ## Protected Dashboard - catch all remaining routes - - name: dashboard - _comment: 'Studio: /* -> http://studio:3000/*' - url: http://studio:3000/ - routes: - - name: dashboard-all - strip_path: true - paths: - - / - plugins: - - name: cors - - name: basic-auth - config: - hide_credentials: true diff --git a/backend/volumes/db/_supabase.sql b/backend/volumes/db/_supabase.sql deleted file mode 100644 index 6236ae1..0000000 --- a/backend/volumes/db/_supabase.sql +++ /dev/null @@ -1,3 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` - -CREATE DATABASE _supabase WITH OWNER :pguser; diff --git a/backend/volumes/db/jwt.sql b/backend/volumes/db/jwt.sql deleted file mode 100644 index cfd3b16..0000000 --- a/backend/volumes/db/jwt.sql +++ /dev/null @@ -1,5 +0,0 @@ -\set jwt_secret `echo "$JWT_SECRET"` -\set jwt_exp `echo "$JWT_EXP"` - -ALTER DATABASE postgres SET "app.settings.jwt_secret" TO :'jwt_secret'; -ALTER DATABASE postgres SET "app.settings.jwt_exp" TO :'jwt_exp'; diff --git a/backend/volumes/db/logs.sql b/backend/volumes/db/logs.sql deleted file mode 100644 index 255c0f4..0000000 --- a/backend/volumes/db/logs.sql +++ /dev/null @@ -1,6 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` - -\c _supabase -create schema if not exists _analytics; -alter schema _analytics owner to :pguser; -\c postgres diff --git a/backend/volumes/db/pooler.sql b/backend/volumes/db/pooler.sql deleted file mode 100644 index 162c5b9..0000000 --- a/backend/volumes/db/pooler.sql +++ /dev/null @@ -1,6 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` - -\c _supabase -create schema if not exists _supavisor; -alter schema _supavisor owner to :pguser; -\c postgres diff --git a/backend/volumes/db/realtime.sql b/backend/volumes/db/realtime.sql deleted file mode 100644 index 4d4b9ff..0000000 --- a/backend/volumes/db/realtime.sql +++ /dev/null @@ -1,4 +0,0 @@ -\set pguser `echo "$POSTGRES_USER"` - -create schema if not exists _realtime; -alter schema _realtime owner to :pguser; diff --git a/backend/volumes/db/roles.sql b/backend/volumes/db/roles.sql deleted file mode 100644 index 8f7161a..0000000 --- a/backend/volumes/db/roles.sql +++ /dev/null @@ -1,8 +0,0 @@ --- NOTE: change to your own passwords for production environments -\set pgpass `echo "$POSTGRES_PASSWORD"` - -ALTER USER authenticator WITH PASSWORD :'pgpass'; -ALTER USER pgbouncer WITH PASSWORD :'pgpass'; -ALTER USER supabase_auth_admin WITH PASSWORD :'pgpass'; -ALTER USER supabase_functions_admin WITH PASSWORD :'pgpass'; -ALTER USER supabase_storage_admin WITH PASSWORD :'pgpass'; diff --git a/backend/volumes/db/webhooks.sql b/backend/volumes/db/webhooks.sql deleted file mode 100644 index 5837b86..0000000 --- a/backend/volumes/db/webhooks.sql +++ /dev/null @@ -1,208 +0,0 @@ -BEGIN; - -- Create pg_net extension - CREATE EXTENSION IF NOT EXISTS pg_net SCHEMA extensions; - -- Create supabase_functions schema - CREATE SCHEMA supabase_functions AUTHORIZATION supabase_admin; - GRANT USAGE ON SCHEMA supabase_functions TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON TABLES TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON FUNCTIONS TO postgres, anon, authenticated, service_role; - ALTER DEFAULT PRIVILEGES IN SCHEMA supabase_functions GRANT ALL ON SEQUENCES TO postgres, anon, authenticated, service_role; - -- supabase_functions.migrations definition - CREATE TABLE supabase_functions.migrations ( - version text PRIMARY KEY, - inserted_at timestamptz NOT NULL DEFAULT NOW() - ); - -- Initial supabase_functions migration - INSERT INTO supabase_functions.migrations (version) VALUES ('initial'); - -- supabase_functions.hooks definition - CREATE TABLE supabase_functions.hooks ( - id bigserial PRIMARY KEY, - hook_table_id integer NOT NULL, - hook_name text NOT NULL, - created_at timestamptz NOT NULL DEFAULT NOW(), - request_id bigint - ); - CREATE INDEX supabase_functions_hooks_request_id_idx ON supabase_functions.hooks USING btree (request_id); - CREATE INDEX supabase_functions_hooks_h_table_id_h_name_idx ON supabase_functions.hooks USING btree (hook_table_id, hook_name); - COMMENT ON TABLE supabase_functions.hooks IS 'Supabase Functions Hooks: Audit trail for triggered hooks.'; - CREATE FUNCTION supabase_functions.http_request() - RETURNS trigger - LANGUAGE plpgsql - AS $function$ - DECLARE - request_id bigint; - payload jsonb; - url text := TG_ARGV[0]::text; - method text := TG_ARGV[1]::text; - headers jsonb DEFAULT '{}'::jsonb; - params jsonb DEFAULT '{}'::jsonb; - timeout_ms integer DEFAULT 1000; - BEGIN - IF url IS NULL OR url = 'null' THEN - RAISE EXCEPTION 'url argument is missing'; - END IF; - - IF method IS NULL OR method = 'null' THEN - RAISE EXCEPTION 'method argument is missing'; - END IF; - - IF TG_ARGV[2] IS NULL OR TG_ARGV[2] = 'null' THEN - headers = '{"Content-Type": "application/json"}'::jsonb; - ELSE - headers = TG_ARGV[2]::jsonb; - END IF; - - IF TG_ARGV[3] IS NULL OR TG_ARGV[3] = 'null' THEN - params = '{}'::jsonb; - ELSE - params = TG_ARGV[3]::jsonb; - END IF; - - IF TG_ARGV[4] IS NULL OR TG_ARGV[4] = 'null' THEN - timeout_ms = 1000; - ELSE - timeout_ms = TG_ARGV[4]::integer; - END IF; - - CASE - WHEN method = 'GET' THEN - SELECT http_get INTO request_id FROM net.http_get( - url, - params, - headers, - timeout_ms - ); - WHEN method = 'POST' THEN - payload = jsonb_build_object( - 'old_record', OLD, - 'record', NEW, - 'type', TG_OP, - 'table', TG_TABLE_NAME, - 'schema', TG_TABLE_SCHEMA - ); - - SELECT http_post INTO request_id FROM net.http_post( - url, - payload, - params, - headers, - timeout_ms - ); - ELSE - RAISE EXCEPTION 'method argument % is invalid', method; - END CASE; - - INSERT INTO supabase_functions.hooks - (hook_table_id, hook_name, request_id) - VALUES - (TG_RELID, TG_NAME, request_id); - - RETURN NEW; - END - $function$; - -- Supabase super admin - DO - $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM pg_roles - WHERE rolname = 'supabase_functions_admin' - ) - THEN - CREATE USER supabase_functions_admin NOINHERIT CREATEROLE LOGIN NOREPLICATION; - END IF; - END - $$; - GRANT ALL PRIVILEGES ON SCHEMA supabase_functions TO supabase_functions_admin; - GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA supabase_functions TO supabase_functions_admin; - GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA supabase_functions TO supabase_functions_admin; - ALTER USER supabase_functions_admin SET search_path = "supabase_functions"; - ALTER table "supabase_functions".migrations OWNER TO supabase_functions_admin; - ALTER table "supabase_functions".hooks OWNER TO supabase_functions_admin; - ALTER function "supabase_functions".http_request() OWNER TO supabase_functions_admin; - GRANT supabase_functions_admin TO postgres; - -- Remove unused supabase_pg_net_admin role - DO - $$ - BEGIN - IF EXISTS ( - SELECT 1 - FROM pg_roles - WHERE rolname = 'supabase_pg_net_admin' - ) - THEN - REASSIGN OWNED BY supabase_pg_net_admin TO supabase_admin; - DROP OWNED BY supabase_pg_net_admin; - DROP ROLE supabase_pg_net_admin; - END IF; - END - $$; - -- pg_net grants when extension is already enabled - DO - $$ - BEGIN - IF EXISTS ( - SELECT 1 - FROM pg_extension - WHERE extname = 'pg_net' - ) - THEN - GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - END IF; - END - $$; - -- Event trigger for pg_net - CREATE OR REPLACE FUNCTION extensions.grant_pg_net_access() - RETURNS event_trigger - LANGUAGE plpgsql - AS $$ - BEGIN - IF EXISTS ( - SELECT 1 - FROM pg_event_trigger_ddl_commands() AS ev - JOIN pg_extension AS ext - ON ev.objid = ext.oid - WHERE ext.extname = 'pg_net' - ) - THEN - GRANT USAGE ON SCHEMA net TO supabase_functions_admin, postgres, anon, authenticated, service_role; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SECURITY DEFINER; - ALTER function net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - ALTER function net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) SET search_path = net; - REVOKE ALL ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - REVOKE ALL ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) FROM PUBLIC; - GRANT EXECUTE ON FUNCTION net.http_get(url text, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - GRANT EXECUTE ON FUNCTION net.http_post(url text, body jsonb, params jsonb, headers jsonb, timeout_milliseconds integer) TO supabase_functions_admin, postgres, anon, authenticated, service_role; - END IF; - END; - $$; - COMMENT ON FUNCTION extensions.grant_pg_net_access IS 'Grants access to pg_net'; - DO - $$ - BEGIN - IF NOT EXISTS ( - SELECT 1 - FROM pg_event_trigger - WHERE evtname = 'issue_pg_net_access' - ) THEN - CREATE EVENT TRIGGER issue_pg_net_access ON ddl_command_end WHEN TAG IN ('CREATE EXTENSION') - EXECUTE PROCEDURE extensions.grant_pg_net_access(); - END IF; - END - $$; - INSERT INTO supabase_functions.migrations (version) VALUES ('20210809183423_update_grants'); - ALTER function supabase_functions.http_request() SECURITY DEFINER; - ALTER function supabase_functions.http_request() SET search_path = supabase_functions; - REVOKE ALL ON FUNCTION supabase_functions.http_request() FROM PUBLIC; - GRANT EXECUTE ON FUNCTION supabase_functions.http_request() TO postgres, anon, authenticated, service_role; -COMMIT; diff --git a/backend/volumes/functions/hello/index.ts b/backend/volumes/functions/hello/index.ts deleted file mode 100644 index f1e20b9..0000000 --- a/backend/volumes/functions/hello/index.ts +++ /dev/null @@ -1,16 +0,0 @@ -// Follow this setup guide to integrate the Deno language server with your editor: -// https://deno.land/manual/getting_started/setup_your_environment -// This enables autocomplete, go to definition, etc. - -import { serve } from "https://deno.land/std@0.177.1/http/server.ts" - -serve(async () => { - return new Response( - `"Hello from Edge Functions!"`, - { headers: { "Content-Type": "application/json" } }, - ) -}) - -// To invoke: -// curl 'http://localhost:/functions/v1/hello' \ -// --header 'Authorization: Bearer ' diff --git a/backend/volumes/functions/main/index.ts b/backend/volumes/functions/main/index.ts deleted file mode 100644 index a094010..0000000 --- a/backend/volumes/functions/main/index.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { serve } from 'https://deno.land/std@0.131.0/http/server.ts' -import * as jose from 'https://deno.land/x/jose@v4.14.4/index.ts' - -console.log('main function started') - -const JWT_SECRET = Deno.env.get('JWT_SECRET') -const VERIFY_JWT = Deno.env.get('VERIFY_JWT') === 'true' - -function getAuthToken(req: Request) { - const authHeader = req.headers.get('authorization') - if (!authHeader) { - throw new Error('Missing authorization header') - } - const [bearer, token] = authHeader.split(' ') - if (bearer !== 'Bearer') { - throw new Error(`Auth header is not 'Bearer {token}'`) - } - return token -} - -async function verifyJWT(jwt: string): Promise { - const encoder = new TextEncoder() - const secretKey = encoder.encode(JWT_SECRET) - try { - await jose.jwtVerify(jwt, secretKey) - } catch (err) { - console.error(err) - return false - } - return true -} - -serve(async (req: Request) => { - if (req.method !== 'OPTIONS' && VERIFY_JWT) { - try { - const token = getAuthToken(req) - const isValidJWT = await verifyJWT(token) - - if (!isValidJWT) { - return new Response(JSON.stringify({ msg: 'Invalid JWT' }), { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }) - } - } catch (e) { - console.error(e) - return new Response(JSON.stringify({ msg: e.toString() }), { - status: 401, - headers: { 'Content-Type': 'application/json' }, - }) - } - } - - const url = new URL(req.url) - const { pathname } = url - const path_parts = pathname.split('/') - const service_name = path_parts[1] - - if (!service_name || service_name === '') { - const error = { msg: 'missing function name in request' } - return new Response(JSON.stringify(error), { - status: 400, - headers: { 'Content-Type': 'application/json' }, - }) - } - - const servicePath = `/home/deno/functions/${service_name}` - console.error(`serving the request with ${servicePath}`) - - const memoryLimitMb = 150 - const workerTimeoutMs = 1 * 60 * 1000 - const noModuleCache = false - const importMapPath = null - const envVarsObj = Deno.env.toObject() - const envVars = Object.keys(envVarsObj).map((k) => [k, envVarsObj[k]]) - - try { - const worker = await EdgeRuntime.userWorkers.create({ - servicePath, - memoryLimitMb, - workerTimeoutMs, - noModuleCache, - importMapPath, - envVars, - }) - return await worker.fetch(req) - } catch (e) { - const error = { msg: e.toString() } - return new Response(JSON.stringify(error), { - status: 500, - headers: { 'Content-Type': 'application/json' }, - }) - } -}) diff --git a/backend/volumes/logs/vector.yml b/backend/volumes/logs/vector.yml deleted file mode 100644 index cce46df..0000000 --- a/backend/volumes/logs/vector.yml +++ /dev/null @@ -1,232 +0,0 @@ -api: - enabled: true - address: 0.0.0.0:9001 - -sources: - docker_host: - type: docker_logs - exclude_containers: - - supabase-vector - -transforms: - project_logs: - type: remap - inputs: - - docker_host - source: |- - .project = "default" - .event_message = del(.message) - .appname = del(.container_name) - del(.container_created_at) - del(.container_id) - del(.source_type) - del(.stream) - del(.label) - del(.image) - del(.host) - del(.stream) - router: - type: route - inputs: - - project_logs - route: - kong: '.appname == "supabase-kong"' - auth: '.appname == "supabase-auth"' - rest: '.appname == "supabase-rest"' - realtime: '.appname == "supabase-realtime"' - storage: '.appname == "supabase-storage"' - functions: '.appname == "supabase-functions"' - db: '.appname == "supabase-db"' - # Ignores non nginx errors since they are related with kong booting up - kong_logs: - type: remap - inputs: - - router.kong - source: |- - req, err = parse_nginx_log(.event_message, "combined") - if err == null { - .timestamp = req.timestamp - .metadata.request.headers.referer = req.referer - .metadata.request.headers.user_agent = req.agent - .metadata.request.headers.cf_connecting_ip = req.client - .metadata.request.method = req.method - .metadata.request.path = req.path - .metadata.request.protocol = req.protocol - .metadata.response.status_code = req.status - } - if err != null { - abort - } - # Ignores non nginx errors since they are related with kong booting up - kong_err: - type: remap - inputs: - - router.kong - source: |- - .metadata.request.method = "GET" - .metadata.response.status_code = 200 - parsed, err = parse_nginx_log(.event_message, "error") - if err == null { - .timestamp = parsed.timestamp - .severity = parsed.severity - .metadata.request.host = parsed.host - .metadata.request.headers.cf_connecting_ip = parsed.client - url, err = split(parsed.request, " ") - if err == null { - .metadata.request.method = url[0] - .metadata.request.path = url[1] - .metadata.request.protocol = url[2] - } - } - if err != null { - abort - } - # Gotrue logs are structured json strings which frontend parses directly. But we keep metadata for consistency. - auth_logs: - type: remap - inputs: - - router.auth - source: |- - parsed, err = parse_json(.event_message) - if err == null { - .metadata.timestamp = parsed.time - .metadata = merge!(.metadata, parsed) - } - # PostgREST logs are structured so we separate timestamp from message using regex - rest_logs: - type: remap - inputs: - - router.rest - source: |- - parsed, err = parse_regex(.event_message, r'^(?P