---
title: "Sikre eksporter med custom templates og fonts"
output: rmarkdown::html_vignette
vignette: >
  %\VignetteIndexEntry{Sikre eksporter med custom templates og fonts}
  %\VignetteEngine{knitr::rmarkdown}
  %\VignetteEncoding{UTF-8}
---

```{r, include = FALSE}
knitr::opts_chunk$set(
  collapse = TRUE,
  comment = "#>"
)
```

## To extension points med trust-krav

`bfh_export_pdf()` og `bfh_create_export_session()` eksponerer to parametre der
**kører caller-supplied kode/templates**. Begge er legitime for proprietære fonts
og organisationsspecifikke templates, men begge kræver eksplicit trust:

| Parameter | Hvad det gør | Risiko ved misbrug |
|-----------|--------------|--------------------|
| `inject_assets` | Kalder en R-callback med skrive-adgang til template-mappen | Vilkårlig R-kode-eksekvering |
| `template_path` | Erstatter den pakkede Typst-template | Vilkårlig Typst (kan læse/skrive paths under compilation) |

Begge parametre skal behandles med samme tillidskontrakt som `source()`:
**aldrig fra user-input**, altid fra code-reviewed organisationskontrolleret kilde.

## Brug `font_path` for de fleste tilfælde

Hvis du **kun** har brug for at injicere fonts, brug `font_path` i stedet for
`inject_assets`. Det er sikkert at videresende fra konfiguration eller
miljøvariable, og kræver ikke trust på samme niveau:

```{r font-path, eval = FALSE}
library(BFHcharts)

# Fonts er statiske filer på disk — ingen kode-eksekvering
bfh_export_pdf(result, "rapport.pdf",
  font_path = "/etc/bfh-fonts"
)
```

`font_path` videregives som `--font-path` til Typst-compileren. Typst læser
fonts fra mappen men eksekverer ingen kode fra den.

## `inject_assets` — kun til organisations-kontrolleret kode

Brug `inject_assets` når du har **dynamiske** filsystem-operationer der ikke
passer ind i en fast `font_path`-mappe. Eksempel: en privat pakke der bundler
fonts og afpakker dem til template-mappen lige før compilation.

```{r inject-assets-good, eval = FALSE}
# Sikkert: callback fra code-reviewed privat pakke
inject_my_org_assets <- function(template_dir) {
  font_dir <- file.path(template_dir, "fonts")
  dir.create(font_dir, showWarnings = FALSE)
  file.copy(
    system.file("fonts", "Mari", package = "MyOrgPrivateFonts"),
    font_dir,
    recursive = TRUE
  )
}

bfh_export_pdf(result, "rapport.pdf",
  inject_assets = inject_my_org_assets
)
```

```r
# FARLIGT: callback bygget fra Shiny-input
server <- function(input, output, session) {
  output$pdf <- downloadHandler(
    content = function(file) {
      # ALDRIG videresend user-supplied kode/strenge til inject_assets:
      user_callback <- parse_user_input(input$user_callback)
      bfh_export_pdf(result, file, inject_assets = user_callback)
    }
  )
}
```

Sidstnævnte mønster konverterer en Shiny-input til en eksekverbar callback —
hvilket giver brugeren vilkårlig kode-eksekvering på serveren. Kald den
"remote code execution" eller "RCE": uacceptabel selv i interne enterprise
deployments.

## `template_path` — kun til organisations-kontrolleret Typst

Tilsvarende: `template_path` peger på en `.typ`-fil som Typst-compileren kører.
En custom template kan udføre filsystem-operationer under compilation — så
**aldrig** modtag template-stien fra user-input.

**Siden BFHcharts 0.16.0** kræver custom-template eksplicit opt-out via
`restrict_template = FALSE`. Default er `TRUE` (production-safe). Callers
der ikke eksplicit opt-outer modtager en valideringsfejl ved kald-tid.

```{r template-path-good, eval = FALSE}
# Sikkert: template fra organisations-repo, code-reviewed
bfh_export_pdf(result, "rapport.pdf",
  template_path = system.file(
    "templates", "afdelings-template.typ",
    package = "MyOrgTemplates"
  ),
  restrict_template = FALSE  # eksplicit opt-out paakraevet siden 0.16.0
)
```

```r
# FARLIGT: template-sti fra user upload
template <- input$uploaded_template$datapath
bfh_export_pdf(result, "rapport.pdf",
  template_path = template
)
```

Den uploadede `.typ`-fil eksekveres af Typst-compileren med samme privilege
som R-processen. Vilkårlig Typst-kode kan læse og skrive filsystem-paths.

## Allow-list pattern: hvis du **skal** eksponere customisering

Hvis dit Shiny-interface skal lade brugere vælge mellem **forhåndsgodkendte**
templates, validér mod en fixed allow-list før kald:

```{r allowlist, eval = FALSE}
APPROVED_TEMPLATES <- list(
  standard = system.file("templates/standard.typ", package = "MyOrg"),
  klinisk  = system.file("templates/klinisk.typ", package = "MyOrg"),
  forskning = system.file("templates/forskning.typ", package = "MyOrg")
)

server <- function(input, output, session) {
  output$pdf <- downloadHandler(
    content = function(file) {
      # User vælger fra dropdown med navn — ikke fil-sti
      template <- APPROVED_TEMPLATES[[input$template_name]]
      if (is.null(template) || !file.exists(template)) {
        stop("Ugyldig template valgt")
      }
      bfh_export_pdf(result, file,
                     template_path = template,
                     restrict_template = FALSE)
    }
  )
}
```

UI komponenten viser kun navnene fra allow-listen — fil-stier eksponeres aldrig.

## Batch eksport med `bfh_create_export_session()`

For mange eksporter med identiske template-assets: brug session for at undgå
gentaget I/O. Trust-kravet for `inject_assets` er det samme:

```{r batch, eval = FALSE}
session <- bfh_create_export_session(
  font_path = "/etc/bfh-fonts",
  inject_assets = inject_my_org_assets   # Code-reviewed callback
)
on.exit(close(session))

for (afdeling in afdelinger) {
  result <- bfh_qic(data_per_afd[[afdeling]], ...)
  bfh_export_pdf(result, paste0(afdeling, ".pdf"),
    batch_session = session,
    metadata = list(department = afdeling)
  )
}
```

`inject_assets` kaldes **én gang** ved session-opret; assets deles på tværs af
alle eksporter. Trust-kravet er det samme som single-call mode.

## Font-fallback chain

Hvis `font_path` ikke matcher Typst's font-lookup, falder den tilbage på
system-fonts (medmindre `ignore_system_fonts = TRUE`, default fra v0.10.0).
Anbefalet praksis i production:

```{r font-fallback, eval = FALSE}
bfh_export_pdf(result, "rapport.pdf",
  font_path = "/etc/bfh-fonts",
  ignore_system_fonts = TRUE
)
```

Med `ignore_system_fonts = TRUE` bruger Typst kun fonts fra `font_path` plus
de bundle'de template-fonts. Det forhindrer overraskende rendering-forskelle
mellem dev-maskiner og production-deployments hvor system-font-versioner divergerer.

## Pre-deploy security checklist

Før dit Shiny app eller batch-script går i produktion:

- [ ] `inject_assets` callbacks kommer fra code-reviewed kilde (ikke user-input)
- [ ] `template_path` peger på en organisations-kontrolleret `.typ`-fil
- [ ] Hvis customisering eksponeres: allow-list validering før kald
- [ ] `font_path` peger på read-only mappe (ingen brugerskrivning)
- [ ] `ignore_system_fonts = TRUE` for reproducerbar rendering
- [ ] Output-stier validerede (ingen path traversal)
- [ ] Error messages eksponerer ikke template- eller filsystem-internals

## AI-egress audit signal

Som defense-in-depth emitter `bfh_generate_analysis(use_ai = TRUE)` en
`message()` umiddelbart inden kald til `BFHllm::bfhllm_spc_suggestion()`.
Beskeden bærer det stabile tag `[BFHcharts/AI]` og navngiver de felter der
transmitteres, så R-level logs kan bekræfte om og hvornår AI-stien blev taget.
Sæt `options(BFHcharts.suppress_ai_audit_message = TRUE)` for at undertrykke
beskeden (f.eks. i applikationer der har egen audit-trail).

## Se også

- `vignette("chart-types")` — vælg charttype før eksport
- `?bfh_export_pdf` — `\section{Security}` med fuld trust-rationale
- `?bfh_create_export_session` — batch-session security note
- BFHcharts issue #218 — security boundary discussion
