diff --git a/apps/field/deploy.sh b/apps/field/deploy.sh index 1479e7a..79913a3 100755 --- a/apps/field/deploy.sh +++ b/apps/field/deploy.sh @@ -22,7 +22,7 @@ echo "==> Installing dependencies..." npm ci --silent echo "==> Building PWA (base=/field/)..." -VITE_ERP_TOKEN="b273a666c86d2d0:06120709db5e414" DEPLOY_BASE=/field/ npx quasar build -m pwa +DEPLOY_BASE=/field/ npx quasar build -m pwa if [ "$1" = "local" ]; then echo "==> Deploying to local $DEST..." diff --git a/apps/field/infra/docker-compose.yaml b/apps/field/infra/docker-compose.yaml index 4469255..e211597 100644 --- a/apps/field/infra/docker-compose.yaml +++ b/apps/field/infra/docker-compose.yaml @@ -15,7 +15,7 @@ services: - "traefik.enable=true" - "traefik.http.routers.field.rule=Host(`erp.gigafibre.ca`) && PathPrefix(`/field`)" - "traefik.http.routers.field.entrypoints=web,websecure" - - "traefik.http.routers.field.middlewares=authentik@file,field-strip@docker" + - "traefik.http.routers.field.middlewares=authentik-client@file,field-strip@docker" - "traefik.http.routers.field.service=field" - "traefik.http.routers.field.tls.certresolver=letsencrypt" - "traefik.http.routers.field.priority=200" diff --git a/apps/field/infra/nginx.conf b/apps/field/infra/nginx.conf index 8107653..3f4b9ba 100644 --- a/apps/field/infra/nginx.conf +++ b/apps/field/infra/nginx.conf @@ -4,6 +4,19 @@ server { root /usr/share/nginx/html; index index.html; + # ERPNext API proxy — token injected server-side (never in JS bundle) + location /api/ { + proxy_pass https://erp.gigafibre.ca; + proxy_ssl_verify off; + proxy_set_header Host erp.gigafibre.ca; + proxy_set_header Authorization "token b273a666c86d2d0:06120709db5e414"; + proxy_set_header X-Authentik-Email $http_x_authentik_email; + proxy_set_header X-Authentik-Username $http_x_authentik_username; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + } + + # SPA fallback location / { try_files $uri $uri/ /index.html; } diff --git a/apps/field/src/api/auth.js b/apps/field/src/api/auth.js index 62ad280..92f3781 100644 --- a/apps/field/src/api/auth.js +++ b/apps/field/src/api/auth.js @@ -1,11 +1,17 @@ import { BASE_URL } from 'src/config/erpnext' -const SERVICE_TOKEN = import.meta.env.VITE_ERP_TOKEN || window.__ERP_TOKEN__ || '' +// Token is optional — in production, nginx injects it server-side. +// Only needed for local dev (VITE_ERP_TOKEN in .env). +const SERVICE_TOKEN = import.meta.env.VITE_ERP_TOKEN || '' export function authFetch (url, opts = {}) { - opts.headers = { - ...opts.headers, - Authorization: 'token ' + SERVICE_TOKEN, + if (SERVICE_TOKEN) { + opts.headers = { + ...opts.headers, + Authorization: 'token ' + SERVICE_TOKEN, + } + } else { + opts.headers = { ...opts.headers } } opts.redirect = 'manual' if (opts.method && opts.method !== 'GET') { @@ -22,9 +28,8 @@ export function authFetch (url, opts = {}) { export async function getLoggedUser () { try { - const res = await fetch(BASE_URL + '/api/method/frappe.auth.get_logged_user', { - headers: { Authorization: 'token ' + SERVICE_TOKEN }, - }) + const headers = SERVICE_TOKEN ? { Authorization: 'token ' + SERVICE_TOKEN } : {} + const res = await fetch(BASE_URL + '/api/method/frappe.auth.get_logged_user', { headers }) if (res.ok) { const data = await res.json() return data.message || 'authenticated' @@ -34,5 +39,5 @@ export async function getLoggedUser () { } export async function logout () { - window.location.href = 'https://auth.targo.ca/if/flow/default-invalidation-flow/' + window.location.href = 'https://id.gigafibre.ca/if/flow/default-invalidation-flow/' } diff --git a/apps/ops/deploy.sh b/apps/ops/deploy.sh index 55e44eb..08e09fc 100755 --- a/apps/ops/deploy.sh +++ b/apps/ops/deploy.sh @@ -29,7 +29,7 @@ echo "==> Installing dependencies..." npm ci --silent echo "==> Building PWA (base=/ops/)..." -VITE_ERP_TOKEN="b273a666c86d2d0:06120709db5e414" DEPLOY_BASE=/ops/ npx quasar build -m pwa +DEPLOY_BASE=/ops/ npx quasar build -m pwa if [ "$1" = "local" ]; then # ── Local deploy ── diff --git a/apps/ops/infra/docker-compose.yaml b/apps/ops/infra/docker-compose.yaml index 2cb0fbf..e891f82 100644 --- a/apps/ops/infra/docker-compose.yaml +++ b/apps/ops/infra/docker-compose.yaml @@ -24,7 +24,7 @@ services: # Main router: erp.gigafibre.ca/ops/* with Authentik + StripPrefix - "traefik.http.routers.ops.rule=Host(`erp.gigafibre.ca`) && PathPrefix(`/ops`)" - "traefik.http.routers.ops.entrypoints=web,websecure" - - "traefik.http.routers.ops.middlewares=authentik@file,ops-strip@docker" + - "traefik.http.routers.ops.middlewares=authentik-client@file,ops-strip@docker" - "traefik.http.routers.ops.service=ops" - "traefik.http.routers.ops.tls.certresolver=letsencrypt" - "traefik.http.routers.ops.priority=200" @@ -34,7 +34,7 @@ services: # Authentik outpost callback (required for login redirect) - "traefik.http.routers.ops-ak.rule=Host(`erp.gigafibre.ca`) && PathPrefix(`/outpost.goauthentik.io/`)" - "traefik.http.routers.ops-ak.entrypoints=web,websecure" - - "traefik.http.routers.ops-ak.middlewares=authentik@file" + - "traefik.http.routers.ops-ak.middlewares=authentik-client@file" - "traefik.http.routers.ops-ak.service=ops" - "traefik.http.routers.ops-ak.tls.certresolver=letsencrypt" - "traefik.http.routers.ops-ak.priority=250" diff --git a/apps/ops/infra/nginx.conf b/apps/ops/infra/nginx.conf index 880ae84..7addf57 100644 --- a/apps/ops/infra/nginx.conf +++ b/apps/ops/infra/nginx.conf @@ -4,6 +4,19 @@ server { root /usr/share/nginx/html; index index.html; + # ERPNext API proxy — token injected server-side (never in JS bundle) + # To rotate: edit this file + docker restart ops-frontend + location /api/ { + proxy_pass https://erp.gigafibre.ca; + proxy_ssl_verify off; + proxy_set_header Host erp.gigafibre.ca; + proxy_set_header Authorization "token b273a666c86d2d0:06120709db5e414"; + proxy_set_header X-Authentik-Email $http_x_authentik_email; + proxy_set_header X-Authentik-Username $http_x_authentik_username; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto https; + } + # SPA fallback — all routes serve index.html location / { try_files $uri $uri/ /index.html; diff --git a/apps/ops/src/api/auth.js b/apps/ops/src/api/auth.js index 7d46894..92f3781 100644 --- a/apps/ops/src/api/auth.js +++ b/apps/ops/src/api/auth.js @@ -1,15 +1,19 @@ import { BASE_URL } from 'src/config/erpnext' -const SERVICE_TOKEN = import.meta.env.VITE_ERP_TOKEN || window.__ERP_TOKEN__ || '' +// Token is optional — in production, nginx injects it server-side. +// Only needed for local dev (VITE_ERP_TOKEN in .env). +const SERVICE_TOKEN = import.meta.env.VITE_ERP_TOKEN || '' export function authFetch (url, opts = {}) { - opts.headers = { - ...opts.headers, - Authorization: 'token ' + SERVICE_TOKEN, + if (SERVICE_TOKEN) { + opts.headers = { + ...opts.headers, + Authorization: 'token ' + SERVICE_TOKEN, + } + } else { + opts.headers = { ...opts.headers } } opts.redirect = 'manual' - // For state-changing requests, omit cookies to avoid CSRF check - // (token auth doesn't require CSRF, but session cookies trigger it) if (opts.method && opts.method !== 'GET') { opts.credentials = 'omit' } @@ -24,9 +28,8 @@ export function authFetch (url, opts = {}) { export async function getLoggedUser () { try { - const res = await fetch(BASE_URL + '/api/method/frappe.auth.get_logged_user', { - headers: { Authorization: 'token ' + SERVICE_TOKEN }, - }) + const headers = SERVICE_TOKEN ? { Authorization: 'token ' + SERVICE_TOKEN } : {} + const res = await fetch(BASE_URL + '/api/method/frappe.auth.get_logged_user', { headers }) if (res.ok) { const data = await res.json() return data.message || 'authenticated' @@ -36,5 +39,5 @@ export async function getLoggedUser () { } export async function logout () { - window.location.href = 'https://auth.targo.ca/if/flow/default-invalidation-flow/' + window.location.href = 'https://id.gigafibre.ca/if/flow/default-invalidation-flow/' } diff --git a/apps/ops/src/components/shared/DetailModal.vue b/apps/ops/src/components/shared/DetailModal.vue index 8c4942c..a125373 100644 --- a/apps/ops/src/components/shared/DetailModal.vue +++ b/apps/ops/src/components/shared/DetailModal.vue @@ -139,7 +139,7 @@
-