UNPKG

strapi-security-suite

Version:

All-in-one authentication and session security plugin for Strapi v5

140 lines (139 loc) 4.2 kB
import { useRef, useEffect } from "react"; const __variableDynamicImportRuntimeHelper = (glob, path, segs) => { const v = glob[path]; if (v) { return typeof v === "function" ? v() : Promise.resolve(v); } return new Promise((_, reject) => { (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)( reject.bind( null, new Error( "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "") ) ) ); }); }; const PLUGIN_ID = "strapi-security-suite"; const Initializer = ({ setPlugin }) => { const ref = useRef(setPlugin); useEffect(() => { ref.current(PLUGIN_ID); }, []); return null; }; const SERVER_PLUGIN_NAME = "strapi-security-suite"; const API_BASE_PATH = `/${SERVER_PLUGIN_NAME}`; const ADMIN_TOKEN_HEADER = "app.admin.tk"; const SUCCESS_ALERT_DURATION = 3e3; const HEARTBEAT_INTERVAL_MS = 3e4; const getTrad = (id) => `${PLUGIN_ID}.${id}`; const HEARTBEAT_PATH = `${API_BASE_PATH}/heartbeat`; const ACTIVITY_EVENTS = ["mousemove", "keydown", "scroll", "click", "touchstart"]; const installHeartbeat = () => { if (typeof window === "undefined" || window.__sssHeartbeatInstalled) return; window.__sssHeartbeatInstalled = true; let lastFiredAt = 0; let inFlight = false; const fire = async () => { const now = Date.now(); if (inFlight) return; if (now - lastFiredAt < HEARTBEAT_INTERVAL_MS) return; if (typeof document !== "undefined" && document.hidden) return; lastFiredAt = now; inFlight = true; try { await window.fetch(HEARTBEAT_PATH, { method: "POST", credentials: "include", headers: { "Content-Type": "application/json" } }); } catch { } finally { inFlight = false; } }; for (const evt of ACTIVITY_EVENTS) { window.addEventListener(evt, fire, { passive: true }); } }; const index = { /** * Registers the plugin with the Strapi admin app, patches `window.fetch` * to intercept forced-logout signal headers, and installs the activity * heartbeat listener. * * @param {Object} app - Strapi admin application instance */ register(app) { app.registerPlugin({ id: PLUGIN_ID, initializer: Initializer, isReady: false, name: PLUGIN_ID }); if (!window.__secureFetchPatched) { const originalFetch = window.fetch; window.fetch = async (...args) => { const response = await originalFetch(...args); const captured = response.headers.get(ADMIN_TOKEN_HEADER); if (captured) { window.location.reload(); return new Response(null, { status: 401 }); } return response; }; window.__secureFetchPatched = true; } installHeartbeat(); }, /** * Adds the Security Suite settings link under Settings > Global. * * @param {Object} app - Strapi admin application instance */ bootstrap(app) { app.addSettingsLink("global", { id: PLUGIN_ID, to: PLUGIN_ID, intlLabel: { id: getTrad("settings.title"), defaultMessage: "Security Suite" }, Component: () => import("./App-CM1kp54o.mjs"), permissions: [ { action: "plugin::strapi-security-suite.access", subject: null } ] }); }, /** * Loads translation files for all available locales. * * @param {Object} params * @param {string[]} params.locales - Available locale codes * @returns {Promise<Array<{ data: Object, locale: string }>>} */ async registerTrads({ locales }) { const importedTrads = await Promise.all( locales.map((locale) => { return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/en.json": () => import("./en-B0wBsCyw.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => ({ data, locale })).catch(() => ({ data: {}, locale })); }) ); return importedTrads; } }; export { API_BASE_PATH as A, SUCCESS_ALERT_DURATION as S, index as i };