Fix: Resolve account login issues in Node.js hosted version
In a previous commit, a new proxy endpoint was added to the backend to resolve CORS errors that occurred when the frontend directly fetched data from Risu Realm. However, the proxy endpoint handler failed to properly process POST requests, causing account login failures. Additionally, the backend was inefficiently performing complex body processing. The updated code now directly pipes the original request, providing a more efficient and reliable solution.
This commit is contained in:
@@ -69,7 +69,6 @@
|
|||||||
"mnemonist": "^0.40.3",
|
"mnemonist": "^0.40.3",
|
||||||
"mobile-drag-drop": "3.0.0-rc.0",
|
"mobile-drag-drop": "3.0.0-rc.0",
|
||||||
"msgpackr": "1.10.1",
|
"msgpackr": "1.10.1",
|
||||||
"node-fetch": "2",
|
|
||||||
"node-html-parser": "^6.1.12",
|
"node-html-parser": "^6.1.12",
|
||||||
"ollama": "^0.5.0",
|
"ollama": "^0.5.0",
|
||||||
"pdfjs-dist": "^4.0.379",
|
"pdfjs-dist": "^4.0.379",
|
||||||
|
|||||||
18
pnpm-lock.yaml
generated
18
pnpm-lock.yaml
generated
@@ -158,15 +158,15 @@ importers:
|
|||||||
ml-distance:
|
ml-distance:
|
||||||
specifier: ^4.0.1
|
specifier: ^4.0.1
|
||||||
version: 4.0.1
|
version: 4.0.1
|
||||||
|
mnemonist:
|
||||||
|
specifier: ^0.40.3
|
||||||
|
version: 0.40.3
|
||||||
mobile-drag-drop:
|
mobile-drag-drop:
|
||||||
specifier: 3.0.0-rc.0
|
specifier: 3.0.0-rc.0
|
||||||
version: 3.0.0-rc.0
|
version: 3.0.0-rc.0
|
||||||
msgpackr:
|
msgpackr:
|
||||||
specifier: 1.10.1
|
specifier: 1.10.1
|
||||||
version: 1.10.1
|
version: 1.10.1
|
||||||
node-fetch:
|
|
||||||
specifier: '2'
|
|
||||||
version: 2.7.0
|
|
||||||
node-html-parser:
|
node-html-parser:
|
||||||
specifier: ^6.1.12
|
specifier: ^6.1.12
|
||||||
version: 6.1.12
|
version: 6.1.12
|
||||||
@@ -2756,6 +2756,9 @@ packages:
|
|||||||
ml-tree-similarity@1.0.0:
|
ml-tree-similarity@1.0.0:
|
||||||
resolution: {integrity: sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==}
|
resolution: {integrity: sha512-XJUyYqjSuUQkNQHMscr6tcjldsOoAekxADTplt40QKfwW6nd++1wHWV9AArl0Zvw/TIHgNaZZNvr8QGvE8wLRg==}
|
||||||
|
|
||||||
|
mnemonist@0.40.3:
|
||||||
|
resolution: {integrity: sha512-Vjyr90sJ23CKKH/qPAgUKicw/v6pRoamxIEDFOF8uSgFME7DqPRpHgRTejWVjkdGg5dXj0/NyxZHZ9bcjH+2uQ==}
|
||||||
|
|
||||||
mobile-drag-drop@3.0.0-rc.0:
|
mobile-drag-drop@3.0.0-rc.0:
|
||||||
resolution: {integrity: sha512-f8wIDTbBYLBW/+5sei1cqUE+StyDpf/LP+FRZELlVX6tmOOmELk84r3wh1z3woxCB9G5octhF06K5COvFjGgqg==}
|
resolution: {integrity: sha512-f8wIDTbBYLBW/+5sei1cqUE+StyDpf/LP+FRZELlVX6tmOOmELk84r3wh1z3woxCB9G5octhF06K5COvFjGgqg==}
|
||||||
|
|
||||||
@@ -2900,6 +2903,9 @@ packages:
|
|||||||
object-inspect@1.13.1:
|
object-inspect@1.13.1:
|
||||||
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==}
|
||||||
|
|
||||||
|
obliterator@2.0.5:
|
||||||
|
resolution: {integrity: sha512-42CPE9AhahZRsMNslczq0ctAEtqk8Eka26QofnqC346BZdHDySk3LWka23LI7ULIw11NmltpiLagIq8gBozxTw==}
|
||||||
|
|
||||||
ollama@0.5.0:
|
ollama@0.5.0:
|
||||||
resolution: {integrity: sha512-CRtRzsho210EGdK52GrUMohA2pU+7NbgEaBG3DcYeRmvQthDO7E2LHOkLlUUeaYUlNmEd8icbjC02ug9meSYnw==}
|
resolution: {integrity: sha512-CRtRzsho210EGdK52GrUMohA2pU+7NbgEaBG3DcYeRmvQthDO7E2LHOkLlUUeaYUlNmEd8icbjC02ug9meSYnw==}
|
||||||
|
|
||||||
@@ -6505,6 +6511,10 @@ snapshots:
|
|||||||
binary-search: 1.3.6
|
binary-search: 1.3.6
|
||||||
num-sort: 2.1.0
|
num-sort: 2.1.0
|
||||||
|
|
||||||
|
mnemonist@0.40.3:
|
||||||
|
dependencies:
|
||||||
|
obliterator: 2.0.5
|
||||||
|
|
||||||
mobile-drag-drop@3.0.0-rc.0: {}
|
mobile-drag-drop@3.0.0-rc.0: {}
|
||||||
|
|
||||||
modify-values@1.0.1: {}
|
modify-values@1.0.1: {}
|
||||||
@@ -6665,6 +6675,8 @@ snapshots:
|
|||||||
|
|
||||||
object-inspect@1.13.1: {}
|
object-inspect@1.13.1: {}
|
||||||
|
|
||||||
|
obliterator@2.0.5: {}
|
||||||
|
|
||||||
ollama@0.5.0:
|
ollama@0.5.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-fetch: 3.6.20
|
whatwg-fetch: 3.6.20
|
||||||
|
|||||||
@@ -11,8 +11,7 @@ app.use(express.raw({ type: 'application/octet-stream', limit: '50mb' }));
|
|||||||
const {pipeline} = require('stream/promises')
|
const {pipeline} = require('stream/promises')
|
||||||
const https = require('https');
|
const https = require('https');
|
||||||
const sslPath = path.join(process.cwd(), 'server/node/ssl/certificate');
|
const sslPath = path.join(process.cwd(), 'server/node/ssl/certificate');
|
||||||
const EXTERNAL_HUB_URL = 'https://sv.risuai.xyz';
|
const hubURL = 'https://sv.risuai.xyz';
|
||||||
const fetch = require('node-fetch');
|
|
||||||
|
|
||||||
let password = ''
|
let password = ''
|
||||||
|
|
||||||
@@ -31,12 +30,17 @@ function isHex(str) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
app.get('/', async (req, res, next) => {
|
app.get('/', async (req, res, next) => {
|
||||||
console.log("[Server] Connected")
|
|
||||||
|
const clientIP = req.headers['x-forwarded-for'] || req.ip || req.socket.remoteAddress || 'Unknown IP';
|
||||||
|
const timestamp = new Date().toISOString();
|
||||||
|
console.log(`[Server] ${timestamp} | Connection from: ${clientIP}`);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const mainIndex = await fs.readFile(path.join(process.cwd(), 'dist', 'index.html'))
|
const mainIndex = await fs.readFile(path.join(process.cwd(), 'dist', 'index.html'))
|
||||||
const root = htmlparser.parse(mainIndex)
|
const root = htmlparser.parse(mainIndex)
|
||||||
const head = root.querySelector('head')
|
const head = root.querySelector('head')
|
||||||
head.innerHTML = `<script>globalThis.__NODE__ = true</script>` + head.innerHTML
|
head.innerHTML = `<script>globalThis.__NODE__ = true</script>` + head.innerHTML
|
||||||
|
|
||||||
res.send(root.toString())
|
res.send(root.toString())
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log(error)
|
console.log(error)
|
||||||
@@ -139,116 +143,49 @@ const reverseProxyFunc_get = async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Risu Realm Proxy
|
async function hubProxyFunc(req, res) {
|
||||||
async function hubProxyHandler(req, res, next) {
|
|
||||||
try {
|
try {
|
||||||
// Extract request path and query parameters
|
|
||||||
const pathAndQuery = req.originalUrl.replace(/^\/hub-proxy/, '');
|
const pathAndQuery = req.originalUrl.replace(/^\/hub-proxy/, '');
|
||||||
const externalURL = EXTERNAL_HUB_URL + pathAndQuery;
|
const externalURL = hubURL + pathAndQuery;
|
||||||
|
|
||||||
console.log(`[Hub Proxy] Forwarding ${req.method} request to: ${externalURL}`);
|
|
||||||
|
|
||||||
// Prepare headers to send to the realm server (including Accept-Encoding modification)
|
|
||||||
const headersToSend = { ...req.headers };
|
const headersToSend = { ...req.headers };
|
||||||
delete headersToSend['host'];
|
delete headersToSend.host;
|
||||||
delete headersToSend['connection'];
|
delete headersToSend.connection;
|
||||||
headersToSend['accept-encoding'] = 'gzip, deflate'; // Exclude zstd, etc.
|
|
||||||
if (!headersToSend['x-forwarded-for']) {
|
const proxyReq = new Request(externalURL, {
|
||||||
headersToSend['x-forwarded-for'] = req.ip;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute the fetch request to the realm server
|
|
||||||
const response = await fetch(externalURL, {
|
|
||||||
method: req.method,
|
method: req.method,
|
||||||
headers: headersToSend,
|
headers: headersToSend,
|
||||||
body: (req.method !== 'GET' && req.method !== 'HEAD') ? req.body : undefined,
|
body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined,
|
||||||
|
duplex: 'half'
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`[Hub Proxy] Received status ${response.status} from external server`);
|
const response = await fetch(proxyReq);
|
||||||
|
|
||||||
// Handle the realm server response
|
for (const [key, value] of response.headers.entries()) {
|
||||||
// Clean up response headers and extract Content-Type
|
res.setHeader(key, value);
|
||||||
const responseHeaders = {};
|
|
||||||
// Check the Content-Type of the realm server response (use default if missing)
|
|
||||||
let contentType = response.headers.get('content-type') || 'application/octet-stream';
|
|
||||||
|
|
||||||
response.headers.forEach((value, key) => {
|
|
||||||
const lowerKey = key.toLowerCase();
|
|
||||||
// List of headers not to be forwarded to the client
|
|
||||||
const excludedHeaders = [
|
|
||||||
'transfer-encoding', 'connection', 'content-encoding',
|
|
||||||
'access-control-allow-origin', 'access-control-allow-methods',
|
|
||||||
'access-control-allow-headers', 'content-security-policy',
|
|
||||||
'content-security-policy-report-only', 'clear-site-data',
|
|
||||||
'strict-transport-security', 'expect-ct',
|
|
||||||
'cf-ray', 'cf-cache-status', 'report-to', 'nel', 'server', 'server-timing', 'alt-svc'
|
|
||||||
];
|
|
||||||
if (!excludedHeaders.includes(lowerKey)) {
|
|
||||||
responseHeaders[key] = value;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Set the status code and cleaned headers for the client
|
|
||||||
res.status(response.status).set(responseHeaders);
|
|
||||||
|
|
||||||
// Determine body processing method based on Content-Type
|
|
||||||
try {
|
|
||||||
if (contentType.startsWith('application/json')) {
|
|
||||||
// JSON response: read as text and send
|
|
||||||
const bodyText = await response.text();
|
|
||||||
console.log(`[Hub Proxy] Processing JSON response (size: ${bodyText.length})`);
|
|
||||||
res.setHeader('Content-Type', contentType); // Set the final Content-Type
|
|
||||||
res.send(bodyText);
|
|
||||||
|
|
||||||
} else if (contentType.startsWith('image/')) {
|
|
||||||
// Image response: read as buffer and send
|
|
||||||
const bodyBuffer = await response.buffer(); // Assuming 'fetch' response object has a .buffer() method or similar
|
|
||||||
console.log(`[Hub Proxy] Processing Image response (type: ${contentType}, size: ${bodyBuffer.length} bytes)`);
|
|
||||||
res.setHeader('Content-Type', contentType); // Set the final Content-Type
|
|
||||||
res.send(bodyBuffer);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Other responses (HTML, other text, unknown binary, etc.): read as buffer and send safely
|
|
||||||
const bodyBuffer = await response.buffer(); // Assuming 'fetch' response object has a .buffer() method or similar
|
|
||||||
console.log(`[Hub Proxy] Processing Other response as buffer (type: ${contentType}, size: ${bodyBuffer.length} bytes)`);
|
|
||||||
// Use original Content-Type if available, otherwise use octet-stream (already handled by default assignment)
|
|
||||||
res.setHeader('Content-Type', contentType);
|
|
||||||
res.send(bodyBuffer);
|
|
||||||
}
|
|
||||||
} catch (bodyError) {
|
|
||||||
// If an error occurs while reading/processing the response body
|
|
||||||
console.error("[Hub Proxy] Error reading/processing response body:", bodyError);
|
|
||||||
if (!res.headersSent) {
|
|
||||||
res.status(500).send({ error: 'Failed to process response body from hub server.' });
|
|
||||||
} else {
|
|
||||||
console.error("[Hub Proxy] Headers already sent, cannot send body error to client.");
|
|
||||||
res.end();
|
|
||||||
}
|
|
||||||
return; // End the handler
|
|
||||||
}
|
}
|
||||||
|
res.status(response.status);
|
||||||
|
|
||||||
|
await pipeline(response.body, res);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Fetch request itself failed or other exceptions
|
console.error("[Hub Proxy] Error:", error);
|
||||||
console.error("[Hub Proxy] Request failed:", error);
|
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
res.status(502).send({ error: 'Proxy failed to connect to or get response from the hub server.' });
|
res.status(502).send({ error: 'Proxy request failed' });
|
||||||
} else {
|
} else {
|
||||||
console.error("[Hub Proxy] Headers already sent, cannot send connection error to client.");
|
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/hub-proxy/*', hubProxyHandler);
|
|
||||||
app.post('/hub-proxy/*', hubProxyHandler);
|
|
||||||
app.put('/hub-proxy/*', hubProxyHandler);
|
|
||||||
|
|
||||||
app.get('/proxy', reverseProxyFunc_get);
|
app.get('/proxy', reverseProxyFunc_get);
|
||||||
app.get('/proxy2', reverseProxyFunc_get);
|
app.get('/proxy2', reverseProxyFunc_get);
|
||||||
|
app.get('/hub-proxy/*', hubProxyFunc);
|
||||||
|
|
||||||
app.post('/proxy', reverseProxyFunc);
|
app.post('/proxy', reverseProxyFunc);
|
||||||
app.post('/proxy2', reverseProxyFunc);
|
app.post('/proxy2', reverseProxyFunc);
|
||||||
|
app.post('/hub-proxy/*', hubProxyFunc);
|
||||||
|
|
||||||
app.get('/api/password', async(req, res)=> {
|
app.get('/api/password', async(req, res)=> {
|
||||||
if(password === ''){
|
if(password === ''){
|
||||||
@@ -408,9 +345,6 @@ async function getHttpsOptions() {
|
|||||||
const keyPath = path.join(sslPath, 'server.key');
|
const keyPath = path.join(sslPath, 'server.key');
|
||||||
const certPath = path.join(sslPath, 'server.crt');
|
const certPath = path.join(sslPath, 'server.crt');
|
||||||
|
|
||||||
console.log(keyPath)
|
|
||||||
console.log(certPath)
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await fs.access(keyPath);
|
await fs.access(keyPath);
|
||||||
|
|||||||
Reference in New Issue
Block a user