summaryrefslogtreecommitdiff
path: root/viewer-bff/server.js
blob: 30ef81adee82be97f230b9ae623ab9ece1857fd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
const express = require("express");
const path = require("path");

const app = express();

const PORT = process.env.PORT || 8082;
const MEDIA_API_BASE_URL =
  process.env.MEDIA_API_BASE_URL || "http://media-access-api:8081";
const CORS_ALLOWED_ORIGIN = process.env.CORS_ALLOWED_ORIGIN || "*";

app.use(express.json({ limit: "1mb" }));

app.use((req, res, next) => {
  res.setHeader("Access-Control-Allow-Origin", CORS_ALLOWED_ORIGIN);
  res.setHeader("Access-Control-Allow-Methods", "GET,POST,OPTIONS");
  res.setHeader("Access-Control-Allow-Headers", "Authorization,Content-Type");
  if (req.method === "OPTIONS") {
    return res.sendStatus(204);
  }
  return next();
});

app.use(express.static(path.join(__dirname, "public")));

app.get("/health", (_req, res) => {
  res.json({
    status: "ok",
    service: "viewer-bff",
    mediaApiBaseUrl: MEDIA_API_BASE_URL
  });
});

function getBearerToken(req) {
  const authHeader = req.headers.authorization || "";
  if (!authHeader.startsWith("Bearer ")) {
    return null;
  }
  return authHeader.slice("Bearer ".length).trim();
}

async function proxyJson(req, res, targetPath, method = "GET", body) {
  const token = getBearerToken(req);
  if (!token) {
    return res.status(401).json({
      error: "missing_token",
      message: "Header Authorization Bearer requis"
    });
  }

  try {
    const response = await fetch(`${MEDIA_API_BASE_URL}${targetPath}`, {
      method,
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json"
      },
      body: body ? JSON.stringify(body) : undefined
    });

    const text = await response.text();
    let payload = {};
    if (text) {
      try {
        payload = JSON.parse(text);
      } catch (_err) {
        payload = { raw: text };
      }
    }

    if (!response.ok) {
      return res.status(response.status).json({
        error: "media_api_error",
        status: response.status,
        message: payload.message || "Erreur retour media-access-api",
        details: payload
      });
    }

    return res.status(response.status).json(payload);
  } catch (error) {
    return res.status(502).json({
      error: "media_api_unreachable",
      message: "Impossible de joindre media-access-api",
      details: error.message
    });
  }
}

app.get("/api/me/permissions", async (req, res) => {
  return proxyJson(req, res, "/v1/permissions", "GET");
});

app.post("/api/media/presign", async (req, res) => {
  const objectKey = req.body?.objectKey;
  if (!objectKey || typeof objectKey !== "string") {
    return res.status(400).json({
      error: "invalid_payload",
      message: "Champ objectKey requis"
    });
  }

  return proxyJson(req, res, "/v1/presign", "POST", { objectKey });
});

app.get("*", (req, res) => {
  if (req.path.startsWith("/api/")) {
    return res.status(404).json({ error: "not_found" });
  }
  return res.sendFile(path.join(__dirname, "public", "index.html"));
});

app.listen(PORT, () => {
  // eslint-disable-next-line no-console
  console.log(`viewer-bff listening on port ${PORT}`);
});