fix: server-side API token injection + ticket modal empty state
- Move ERPNext API token from JS bundle to nginx proxy_set_header (token only lives on server, never in client code) - Switch ops + field apps from auth.targo.ca to id.gigafibre.ca SSO - Fix "Aucun contenu" showing on tickets that have comments but no description (check comments.length in v-if condition) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
11cd38f93c
commit
1ed86e37ad
|
|
@ -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..."
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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/'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ──
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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/'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@
|
|||
<div class="thread-body" v-html="c.content"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!doc.description && !doc.resolution_details && !comms.length" class="text-center text-grey-5 q-pa-lg">
|
||||
<div v-if="!doc.description && !doc.resolution_details && !comms.length && !comments.length" class="text-center text-grey-5 q-pa-lg">
|
||||
Aucun contenu pour ce ticket
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user