UNPKG

p3x-redis-ui-server

Version:

🏍️ P3X Redis UI server — Socket.IO backend for the dual Angular + React frontend with AI queries, 54 languages, and auto data decompression

2 lines (1 loc) 5.7 kB
import e from"express";import t from"fs";import s from"path";import r from"http";import{fileURLToPath as o}from"url";import{resolveConfiguredHttpAuth as a,verifyCredentials as n,createAuthToken as i,verifyAuthToken as c}from"../../lib/http-auth.mjs";import{version as l}from"../../lib/resolve-version.mjs";const d=s.dirname(o(import.meta.url));export default function(){this.boot=async()=>{const o=e();this.app=o,o.disable("x-powered-by"),o.use((e,t,s)=>{t.set("Content-Security-Policy","default-src 'self'; script-src 'self' https://www.googletagmanager.com 'unsafe-inline' 'unsafe-eval'; worker-src 'self' blob:; style-src 'self' 'unsafe-inline'; img-src 'self' data: https://www.googletagmanager.com https://www.google-analytics.com; font-src 'self' data:; connect-src 'self' ws: wss: http://localhost:* http://127.0.0.1:* https://www.googletagmanager.com https://www.google-analytics.com https://region1.google-analytics.com https://analytics.google.com; object-src 'none'; base-uri 'self'; form-action 'self'"),s()});const p=(new Date).toISOString();o.get("/health",(e,t)=>{t.json({status:"ok",version:l,uptime:process.uptime(),startedAt:p})}),o.use("/api",(e,t,s)=>{if(t.set("Access-Control-Allow-Origin","*"),t.set("Access-Control-Allow-Methods","GET, POST, OPTIONS"),t.set("Access-Control-Allow-Headers","Content-Type"),"OPTIONS"===e.method)return t.sendStatus(204);s()}),o.get("/api/auth-status",(e,t)=>{const s=a();t.json({enabled:s.enabled})}),o.post("/api/login",e.json(),(e,t)=>{if(!a().enabled)return t.json({status:"ok",authRequired:!1});const{username:s,password:r}=e.body||{};if(!s||!r)return t.status(400).json({status:"error",error:"credentials_required"});if(!n({username:s,password:r}))return t.status(401).json({status:"error",error:"invalid_credentials"});const o=i(s);t.json({status:"ok",token:o})}),o.post("/api/verify-token",e.json(),(e,t)=>{if(!a().enabled)return t.json({valid:!0,authRequired:!1});const{token:s}=e.body||{},r=c(s);t.json({valid:!!r})});const m=e=>{if(e.startsWith("~")){return((e,r)=>{let o=d;for(;o!==s.resolve(o,"..");){const e=s.join(o,r);if(t.existsSync(e))return e;o=s.resolve(o,"..")}throw new Error("The specified module could not be found in any node_modules directory")})(0,e.substring(1))}return s.resolve(process.cwd(),e)};let h,u=!1;const f=p3xrs.cfg.static||p3xrs.cfg.staticNg;if("string"==typeof f)try{h=m(f),o.use("/ng",e.static(h,{etag:!0,lastModified:!0,setHeaders:(e,t)=>{t.endsWith(".html")&&e.setHeader("Cache-Control","no-cache")}})),u=!0,console.info("Angular static mounted at /ng/ from",h)}catch(e){console.warn("Could not resolve Angular static path:",f,"-",e.message)}let g,y=!1,w=p3xrs.cfg.staticReact;if(!w&&h){const e=h+"-react";t.existsSync(e)&&(w=e)}if(w||(w="~p3x-redis-ui-material/dist-react"),"string"==typeof w)try{g=w.startsWith("~")?m(w):w,t.existsSync(g)&&(o.use("/react",e.static(g,{etag:!0,lastModified:!0,setHeaders:(e,t)=>{t.endsWith(".html")&&e.setHeader("Cache-Control","no-cache")}})),y=!0,console.info("React static mounted at /react/ from",g))}catch(e){}let x,v=!1,b=p3xrs.cfg.staticVue;if(!b&&h){const e=h+"-vue";t.existsSync(e)&&(b=e)}if(b||(b="~p3x-redis-ui-material/dist-vue"),"string"==typeof b)try{x=b.startsWith("~")?m(b):b,t.existsSync(x)&&(o.use("/vue",e.static(x,{etag:!0,lastModified:!0,setHeaders:(e,t)=>{t.endsWith(".html")&&e.setHeader("Cache-Control","no-cache")}})),v=!0,console.info("Vue static mounted at /vue/ from",x))}catch(e){}const T=e=>e.includes(".asar");let k;const C=u?s.resolve(h,"index.html"):null;let j;u&&(k=await t.promises.readFile(C,"utf8"));const S=y?s.resolve(g,"index.html"):null;let A;y&&(j=await t.promises.readFile(S,"utf8"));const E=v?s.resolve(x,"index.html"):null;v&&(A=await t.promises.readFile(E,"utf8"));const W=e=>e.set("Cache-Control","no-cache");(u||y||v)&&o.get("/",(e,t)=>{W(t),t.type("html").send(`<!DOCTYPE html><html><head><script>try{var t=localStorage.getItem('p3xr-theme');if(t==='auto'||!t)t=window.matchMedia&&window.matchMedia('(prefers-color-scheme:dark)').matches?'p3xrThemeDark':'p3xrThemeEnterprise';var m={p3xrThemeLight:'#cfd8dc',p3xrThemeEnterprise:'#e0e0e0',p3xrThemeRedis:'#ffcdd2',p3xrThemeDark:'#212121',p3xrThemeDarkNeu:'#263238',p3xrThemeDarkoBluo:'#283593',p3xrThemeMatrix:'#1b5e20'};var c=m[t]||'#212121';var l=t==='p3xrThemeLight'||t==='p3xrThemeEnterprise'||t==='p3xrThemeRedis';var s=document.createElement('meta');s.name='color-scheme';s.content=l?'light':'dark';document.head.appendChild(s);document.documentElement.style.backgroundColor=c}catch(e){var s=document.createElement('meta');s.name='color-scheme';s.content='dark';document.head.appendChild(s)}<\/script><title>P3X Redis UI</title></head><body><script>\nvar pref='ng';try{pref=localStorage.getItem('p3xr-frontend')||'ng'}catch(e){}\nif(pref==='vue'&&${v})location.replace('/vue/')\nelse if(pref==='react'&&${y})location.replace('/react/')\nelse location.replace('/ng/')\n<\/script></body></html>`)}),u&&o.use("/ng",async(e,s,r)=>{e.path.startsWith("/socket.io")?r():(W(s),s.type("html").send(await(async()=>T(C)?k:t.promises.readFile(C,"utf8"))()))}),y&&o.use("/react",async(e,s,r)=>{e.path.startsWith("/socket.io")?r():(W(s),s.type("html").send(await(async()=>T(S)?j:t.promises.readFile(S,"utf8"))()))}),v&&o.use("/vue",async(e,s,r)=>{e.path.startsWith("/socket.io")?r():(W(s),s.type("html").send(await(async()=>T(E)?A:t.promises.readFile(E,"utf8"))()))}),u||y||v||o.use((e,t)=>{t.json({status:"operational"})}),o.use((e,t,s,r)=>{console.error("express server error",e),s.headersSent?r(e):s.status(500).json({error:"internal_server_error"})});const O=r.createServer(o);this.server=O,O.listen(p3xrs.cfg.http.port||7843,p3xrs.cfg.http.bind?p3xrs.cfg.http.bind:"0.0.0.0")}}