feat(BUG): Azure CosmosDB Integration
This commit is contained in:
10
package.json
10
package.json
@@ -6,6 +6,7 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
|
"test": "jest",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"check": "svelte-check --tsconfig ./tsconfig.json",
|
"check": "svelte-check --tsconfig ./tsconfig.json",
|
||||||
"tauri": "tauri",
|
"tauri": "tauri",
|
||||||
@@ -18,6 +19,7 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@adobe/css-tools": "4.3.2",
|
"@adobe/css-tools": "4.3.2",
|
||||||
"@aws-crypto/sha256-js": "^5.2.0",
|
"@aws-crypto/sha256-js": "^5.2.0",
|
||||||
|
"@azure/cosmos": "^4.4.1",
|
||||||
"@breezystack/lamejs": "^1.2.7",
|
"@breezystack/lamejs": "^1.2.7",
|
||||||
"@browsermt/bergamot-translator": "^0.4.9",
|
"@browsermt/bergamot-translator": "^0.4.9",
|
||||||
"@capacitor/android": "^5.6.0",
|
"@capacitor/android": "^5.6.0",
|
||||||
@@ -91,7 +93,8 @@
|
|||||||
"uuid": "^9.0.1",
|
"uuid": "^9.0.1",
|
||||||
"wasmoon": "^1.16.0",
|
"wasmoon": "^1.16.0",
|
||||||
"wavefile": "^11.0.0",
|
"wavefile": "^11.0.0",
|
||||||
"web-streams-polyfill": "^3.3.2"
|
"web-streams-polyfill": "^3.3.2",
|
||||||
|
"yup": "^1.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@capacitor/assets": "^3.0.4",
|
"@capacitor/assets": "^3.0.4",
|
||||||
@@ -105,6 +108,7 @@
|
|||||||
"@types/blueimp-md5": "^2.18.2",
|
"@types/blueimp-md5": "^2.18.2",
|
||||||
"@types/codemirror": "^5.60.15",
|
"@types/codemirror": "^5.60.15",
|
||||||
"@types/diff": "^6.0.0",
|
"@types/diff": "^6.0.0",
|
||||||
|
"@types/jest": "^29.5.14",
|
||||||
"@types/libsodium-wrappers-sumo": "^0.7.8",
|
"@types/libsodium-wrappers-sumo": "^0.7.8",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
@@ -117,6 +121,7 @@
|
|||||||
"@types/wicg-file-system-access": "^2020.9.8",
|
"@types/wicg-file-system-access": "^2020.9.8",
|
||||||
"autoprefixer": "^10.4.16",
|
"autoprefixer": "^10.4.16",
|
||||||
"internal-ip": "^7.0.0",
|
"internal-ip": "^7.0.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
"postcss": "^8.4.33",
|
"postcss": "^8.4.33",
|
||||||
"svelte": "^5.1.9",
|
"svelte": "^5.1.9",
|
||||||
"svelte-check": "^4.0.5",
|
"svelte-check": "^4.0.5",
|
||||||
@@ -127,5 +132,6 @@
|
|||||||
"vite": "^5.4.4",
|
"vite": "^5.4.4",
|
||||||
"vite-plugin-top-level-await": "1.4.1",
|
"vite-plugin-top-level-await": "1.4.1",
|
||||||
"vite-plugin-wasm": "3.3.0"
|
"vite-plugin-wasm": "3.3.0"
|
||||||
}
|
},
|
||||||
|
"packageManager": "pnpm@10.11.0+sha512.6540583f41cc5f628eb3d9773ecee802f4f9ef9923cc45b69890fb47991d4b092964694ec3a4f738a420c918a333062c8b925d312f42e4f0c263eb603551f977"
|
||||||
}
|
}
|
||||||
|
|||||||
2076
pnpm-lock.yaml
generated
2076
pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
107
server/node/db.cjs
Normal file
107
server/node/db.cjs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
const { Container, ContainerResponse, CosmosClient } = require("@azure/cosmos");
|
||||||
|
const { array, mixed, object, string } = require("yup");
|
||||||
|
|
||||||
|
class CosmosStore {
|
||||||
|
/**
|
||||||
|
* @constructor
|
||||||
|
* @param {string} endpoint - Azure Cosmos Endpoint
|
||||||
|
* @param {string} key - Azure Key
|
||||||
|
* @param {string} database - Cosmos Database ID
|
||||||
|
* @param {string} container - Cosmos Container ID
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
constructor(endpoint, key, database, container) {
|
||||||
|
if (typeof endpoint != "string") throw new Error("Invalid endpoint type");
|
||||||
|
if (typeof key != "string") throw new Error("Invalid key type");
|
||||||
|
if (typeof database != "string") throw new Error("Invalid database type");
|
||||||
|
if (typeof container != "string") throw new Error("Invalid container type");
|
||||||
|
|
||||||
|
this.$endpoint = endpoint;
|
||||||
|
this.$key = key;
|
||||||
|
this.$databaseName = database;
|
||||||
|
this.$containerName = container;
|
||||||
|
|
||||||
|
this.$containerRun = null;
|
||||||
|
this.$client = new CosmosClient({ endpoint, key });
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a container, create if not exists.
|
||||||
|
* @returns {Promise<Container>}
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
async resolveContainer() {
|
||||||
|
if (this.$containerRun) {
|
||||||
|
return this.$containerRun;
|
||||||
|
} else {
|
||||||
|
const { database } = await this.$client.databases.createIfNotExists({
|
||||||
|
id: this.$databaseName,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { container } = await database.containers.createIfNotExists({
|
||||||
|
id: this.$containerName,
|
||||||
|
partitionKey: {
|
||||||
|
paths: ["/id"],
|
||||||
|
kind: "Hash",
|
||||||
|
version: 2,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.$containerRun = container;
|
||||||
|
return container;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List all data in container.
|
||||||
|
* @returns {Promise<Array<{ name: string, content: Buffer }>>}
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
async listData() {
|
||||||
|
const c = await this.resolveContainer();
|
||||||
|
const list = await c.items.readAll().fetchAll();
|
||||||
|
return list.resources;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a data in container.
|
||||||
|
* @param {string} name - Name of the data
|
||||||
|
* @param {Buffer} content - Content
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
async createData(name, content) {
|
||||||
|
const c = await this.resolveContainer();
|
||||||
|
|
||||||
|
const item = {
|
||||||
|
id: name,
|
||||||
|
content: content,
|
||||||
|
};
|
||||||
|
|
||||||
|
await c.items.create(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a data in container by name.
|
||||||
|
* @param {string} name - Name of the data to remove
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
async removeData(name) {
|
||||||
|
const c = await this.resolveContainer();
|
||||||
|
await c.item(name).delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a data in container by name.
|
||||||
|
* @param {string} name - Name of the data to get
|
||||||
|
* @throws {Error}
|
||||||
|
*/
|
||||||
|
async getData(name) {
|
||||||
|
const c = await this.resolveContainer();
|
||||||
|
const data = await c.item(name).read();
|
||||||
|
|
||||||
|
console.log(data);
|
||||||
|
return data.content;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.CosmosStore = CosmosStore;
|
||||||
22
server/node/db.spec.js
Normal file
22
server/node/db.spec.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
const { CosmosStore } = require("./db.cjs");
|
||||||
|
|
||||||
|
describe("Azure Cosmos DB", () => {
|
||||||
|
test("should able to create", async () => {
|
||||||
|
const c = new CosmosStore(
|
||||||
|
"http://127.0.0.1:8081",
|
||||||
|
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
|
||||||
|
"db",
|
||||||
|
"container",
|
||||||
|
);
|
||||||
|
|
||||||
|
const data = Buffer.from("sfsdf");
|
||||||
|
await c.createData("hello2", data);
|
||||||
|
|
||||||
|
const l = await c.listData();
|
||||||
|
expect(l.length).toBeGreaterThanOrEqual(1);
|
||||||
|
|
||||||
|
const d = await c.getData("hello2");
|
||||||
|
console.log(d);
|
||||||
|
expect(d).toBe(data);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -1,65 +1,83 @@
|
|||||||
const express = require('express');
|
const { CosmosStore } = require("./db.cjs");
|
||||||
|
const express = require("express");
|
||||||
const app = express();
|
const app = express();
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const htmlparser = require('node-html-parser');
|
const htmlparser = require("node-html-parser");
|
||||||
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require('fs');
|
const { existsSync, mkdirSync, readFileSync, writeFileSync } = require("fs");
|
||||||
const fs = require('fs/promises')
|
const fs = require("fs/promises");
|
||||||
const crypto = require('crypto')
|
const crypto = require("crypto");
|
||||||
app.use(express.static(path.join(process.cwd(), 'dist'), {index: false}));
|
app.use(express.static(path.join(process.cwd(), "dist"), { index: false }));
|
||||||
app.use(express.json({ limit: '50mb' }));
|
app.use(express.json({ limit: "50mb" }));
|
||||||
app.use(express.raw({ type: 'application/octet-stream', limit: '50mb' }));
|
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 hubURL = 'https://sv.risuai.xyz';
|
const hubURL = "https://sv.risuai.xyz";
|
||||||
|
|
||||||
let password = ''
|
let password = "";
|
||||||
|
|
||||||
const savePath = path.join(process.cwd(), "save")
|
const cosmosStore = new CosmosStore(
|
||||||
if(!existsSync(savePath)){
|
"http://127.0.0.1:8081",
|
||||||
mkdirSync(savePath)
|
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==",
|
||||||
|
"db",
|
||||||
|
"container",
|
||||||
|
);
|
||||||
|
|
||||||
|
const savePath = path.join(process.cwd(), "save");
|
||||||
|
if (!existsSync(savePath)) {
|
||||||
|
mkdirSync(savePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
const passwordPath = path.join(process.cwd(), 'save', '__password')
|
const passwordPath = path.join(process.cwd(), "save", "__password");
|
||||||
if(existsSync(passwordPath)){
|
if (existsSync(passwordPath)) {
|
||||||
password = readFileSync(passwordPath, 'utf-8')
|
password = readFileSync(passwordPath, "utf-8");
|
||||||
}
|
}
|
||||||
const hexRegex = /^[0-9a-fA-F]+$/;
|
const hexRegex = /^[0-9a-fA-F]+$/;
|
||||||
function isHex(str) {
|
function isHex(str) {
|
||||||
return hexRegex.test(str.toUpperCase().trim()) || str === '__password';
|
return hexRegex.test(str.toUpperCase().trim()) || str === "__password";
|
||||||
}
|
}
|
||||||
|
|
||||||
app.get('/', async (req, res, next) => {
|
app.get("/", async (req, res, next) => {
|
||||||
|
const clientIP =
|
||||||
const clientIP = req.headers['x-forwarded-for'] || req.ip || req.socket.remoteAddress || 'Unknown IP';
|
req.headers["x-forwarded-for"] ||
|
||||||
|
req.ip ||
|
||||||
|
req.socket.remoteAddress ||
|
||||||
|
"Unknown IP";
|
||||||
const timestamp = new Date().toISOString();
|
const timestamp = new Date().toISOString();
|
||||||
console.log(`[Server] ${timestamp} | Connection from: ${clientIP}`);
|
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(
|
||||||
const root = htmlparser.parse(mainIndex)
|
path.join(process.cwd(), "dist", "index.html"),
|
||||||
const head = root.querySelector('head')
|
);
|
||||||
head.innerHTML = `<script>globalThis.__NODE__ = true</script>` + head.innerHTML
|
const root = htmlparser.parse(mainIndex);
|
||||||
|
const head = root.querySelector("head");
|
||||||
|
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);
|
||||||
next(error)
|
next(error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
const reverseProxyFunc = async (req, res, next) => {
|
const reverseProxyFunc = async (req, res, next) => {
|
||||||
const urlParam = req.headers['risu-url'] ? decodeURIComponent(req.headers['risu-url']) : req.query.url;
|
const urlParam = req.headers["risu-url"]
|
||||||
|
? decodeURIComponent(req.headers["risu-url"])
|
||||||
|
: req.query.url;
|
||||||
|
|
||||||
if (!urlParam) {
|
if (!urlParam) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'URL has no param'
|
error: "URL has no param",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const header = req.headers['risu-header'] ? JSON.parse(decodeURIComponent(req.headers['risu-header'])) : req.headers;
|
const header = req.headers["risu-header"]
|
||||||
if(!header['x-forwarded-for']){
|
? JSON.parse(decodeURIComponent(req.headers["risu-header"]))
|
||||||
header['x-forwarded-for'] = req.ip
|
: req.headers;
|
||||||
|
if (!header["x-forwarded-for"]) {
|
||||||
|
header["x-forwarded-for"] = req.ip;
|
||||||
}
|
}
|
||||||
let originalResponse;
|
let originalResponse;
|
||||||
try {
|
try {
|
||||||
@@ -67,17 +85,17 @@ const reverseProxyFunc = async (req, res, next) => {
|
|||||||
originalResponse = await fetch(urlParam, {
|
originalResponse = await fetch(urlParam, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
headers: header,
|
headers: header,
|
||||||
body: JSON.stringify(req.body)
|
body: JSON.stringify(req.body),
|
||||||
});
|
});
|
||||||
// get response body as stream
|
// get response body as stream
|
||||||
const originalBody = originalResponse.body;
|
const originalBody = originalResponse.body;
|
||||||
// get response headers
|
// get response headers
|
||||||
const head = new Headers(originalResponse.headers);
|
const head = new Headers(originalResponse.headers);
|
||||||
head.delete('content-security-policy');
|
head.delete("content-security-policy");
|
||||||
head.delete('content-security-policy-report-only');
|
head.delete("content-security-policy-report-only");
|
||||||
head.delete('clear-site-data');
|
head.delete("clear-site-data");
|
||||||
head.delete('Cache-Control');
|
head.delete("Cache-Control");
|
||||||
head.delete('Content-Encoding');
|
head.delete("Content-Encoding");
|
||||||
const headObj = {};
|
const headObj = {};
|
||||||
for (let [k, v] of head) {
|
for (let [k, v] of head) {
|
||||||
headObj[k] = v;
|
headObj[k] = v;
|
||||||
@@ -88,44 +106,45 @@ const reverseProxyFunc = async (req, res, next) => {
|
|||||||
res.status(originalResponse.status);
|
res.status(originalResponse.status);
|
||||||
// send response body to client
|
// send response body to client
|
||||||
await pipeline(originalResponse.body, res);
|
await pipeline(originalResponse.body, res);
|
||||||
|
} catch (err) {
|
||||||
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
const reverseProxyFunc_get = async (req, res, next) => {
|
const reverseProxyFunc_get = async (req, res, next) => {
|
||||||
const urlParam = req.headers['risu-url'] ? decodeURIComponent(req.headers['risu-url']) : req.query.url;
|
const urlParam = req.headers["risu-url"]
|
||||||
|
? decodeURIComponent(req.headers["risu-url"])
|
||||||
|
: req.query.url;
|
||||||
|
|
||||||
if (!urlParam) {
|
if (!urlParam) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'URL has no param'
|
error: "URL has no param",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const header = req.headers['risu-header'] ? JSON.parse(decodeURIComponent(req.headers['risu-header'])) : req.headers;
|
const header = req.headers["risu-header"]
|
||||||
if(!header['x-forwarded-for']){
|
? JSON.parse(decodeURIComponent(req.headers["risu-header"]))
|
||||||
header['x-forwarded-for'] = req.ip
|
: req.headers;
|
||||||
|
if (!header["x-forwarded-for"]) {
|
||||||
|
header["x-forwarded-for"] = req.ip;
|
||||||
}
|
}
|
||||||
let originalResponse;
|
let originalResponse;
|
||||||
try {
|
try {
|
||||||
// make request to original server
|
// make request to original server
|
||||||
originalResponse = await fetch(urlParam, {
|
originalResponse = await fetch(urlParam, {
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
headers: header
|
headers: header,
|
||||||
});
|
});
|
||||||
// get response body as stream
|
// get response body as stream
|
||||||
const originalBody = originalResponse.body;
|
const originalBody = originalResponse.body;
|
||||||
// get response headers
|
// get response headers
|
||||||
const head = new Headers(originalResponse.headers);
|
const head = new Headers(originalResponse.headers);
|
||||||
head.delete('content-security-policy');
|
head.delete("content-security-policy");
|
||||||
head.delete('content-security-policy-report-only');
|
head.delete("content-security-policy-report-only");
|
||||||
head.delete('clear-site-data');
|
head.delete("clear-site-data");
|
||||||
head.delete('Cache-Control');
|
head.delete("Cache-Control");
|
||||||
head.delete('Content-Encoding');
|
head.delete("Content-Encoding");
|
||||||
const headObj = {};
|
const headObj = {};
|
||||||
for (let [k, v] of head) {
|
for (let [k, v] of head) {
|
||||||
headObj[k] = v;
|
headObj[k] = v;
|
||||||
@@ -136,17 +155,15 @@ const reverseProxyFunc_get = async (req, res, next) => {
|
|||||||
res.status(originalResponse.status);
|
res.status(originalResponse.status);
|
||||||
// send response body to client
|
// send response body to client
|
||||||
await pipeline(originalResponse.body, res);
|
await pipeline(originalResponse.body, res);
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
next(err);
|
next(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
async function hubProxyFunc(req, res) {
|
async function hubProxyFunc(req, res) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const pathAndQuery = req.originalUrl.replace(/^\/hub-proxy/, '');
|
const pathAndQuery = req.originalUrl.replace(/^\/hub-proxy/, "");
|
||||||
const externalURL = hubURL + pathAndQuery;
|
const externalURL = hubURL + pathAndQuery;
|
||||||
|
|
||||||
const headersToSend = { ...req.headers };
|
const headersToSend = { ...req.headers };
|
||||||
@@ -156,9 +173,9 @@ async function hubProxyFunc(req, res) {
|
|||||||
const response = await fetch(externalURL, {
|
const response = await fetch(externalURL, {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
headers: headersToSend,
|
headers: headersToSend,
|
||||||
body: req.method !== 'GET' && req.method !== 'HEAD' ? req : undefined,
|
body: req.method !== "GET" && req.method !== "HEAD" ? req : undefined,
|
||||||
redirect: 'manual',
|
redirect: "manual",
|
||||||
duplex: 'half'
|
duplex: "half",
|
||||||
});
|
});
|
||||||
|
|
||||||
for (const [key, value] of response.headers.entries()) {
|
for (const [key, value] of response.headers.entries()) {
|
||||||
@@ -168,19 +185,15 @@ async function hubProxyFunc(req, res) {
|
|||||||
|
|
||||||
if (response.status >= 300 && response.status < 400) {
|
if (response.status >= 300 && response.status < 400) {
|
||||||
// Redirect handling (due to ‘/redirect/docs/lua’)
|
// Redirect handling (due to ‘/redirect/docs/lua’)
|
||||||
const redirectUrl = response.headers.get('location');
|
const redirectUrl = response.headers.get("location");
|
||||||
if (redirectUrl) {
|
if (redirectUrl) {
|
||||||
|
if (redirectUrl.startsWith("http")) {
|
||||||
if (redirectUrl.startsWith('http')) {
|
|
||||||
|
|
||||||
if (redirectUrl.startsWith(hubURL)) {
|
if (redirectUrl.startsWith(hubURL)) {
|
||||||
const newPath = redirectUrl.replace(hubURL, '/hub-proxy');
|
const newPath = redirectUrl.replace(hubURL, "/hub-proxy");
|
||||||
res.setHeader('location', newPath);
|
res.setHeader("location", newPath);
|
||||||
}
|
}
|
||||||
|
} else if (redirectUrl.startsWith("/")) {
|
||||||
} else if (redirectUrl.startsWith('/')) {
|
res.setHeader("location", `/hub-proxy${redirectUrl}`);
|
||||||
|
|
||||||
res.setHeader('location', `/hub-proxy${redirectUrl}`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,116 +201,115 @@ async function hubProxyFunc(req, res) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
await pipeline(response.body, res);
|
await pipeline(response.body, res);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("[Hub Proxy] Error:", error);
|
console.error("[Hub Proxy] Error:", error);
|
||||||
if (!res.headersSent) {
|
if (!res.headersSent) {
|
||||||
res.status(502).send({ error: 'Proxy request failed: ' + error.message });
|
res.status(502).send({ error: "Proxy request failed: " + error.message });
|
||||||
} else {
|
} else {
|
||||||
res.end();
|
res.end();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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.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.post("/hub-proxy/*", hubProxyFunc);
|
||||||
|
|
||||||
app.get('/api/password', async(req, res)=> {
|
app.get("/api/password", async (req, res) => {
|
||||||
if(password === ''){
|
if (password === "") {
|
||||||
res.send({status: 'unset'})
|
res.send({ status: "unset" });
|
||||||
|
} else if (req.headers["risu-auth"] === password) {
|
||||||
|
res.send({ status: "correct" });
|
||||||
|
} else {
|
||||||
|
res.send({ status: "incorrect" });
|
||||||
}
|
}
|
||||||
else if(req.headers['risu-auth'] === password){
|
});
|
||||||
res.send({status:'correct'})
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
res.send({status:'incorrect'})
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
app.post('/api/crypto', async (req, res) => {
|
app.post("/api/crypto", async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const hash = crypto.createHash('sha256')
|
const hash = crypto.createHash("sha256");
|
||||||
hash.update(Buffer.from(req.body.data, 'utf-8'))
|
hash.update(Buffer.from(req.body.data, "utf-8"));
|
||||||
res.send(hash.digest('hex'))
|
res.send(hash.digest("hex"));
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error)
|
next(error);
|
||||||
}
|
}
|
||||||
})
|
});
|
||||||
|
|
||||||
|
app.post("/api/set_password", async (req, res) => {
|
||||||
app.post('/api/set_password', async (req, res) => {
|
if (password === "") {
|
||||||
if(password === ''){
|
password = req.body.password;
|
||||||
password = req.body.password
|
writeFileSync(passwordPath, password, "utf-8");
|
||||||
writeFileSync(passwordPath, password, 'utf-8')
|
|
||||||
}
|
}
|
||||||
res.status(400).send("already set")
|
res.status(400).send("already set");
|
||||||
})
|
});
|
||||||
|
|
||||||
app.get('/api/read', async (req, res, next) => {
|
app.get("/api/read", async (req, res, next) => {
|
||||||
if(req.headers['risu-auth'].trim() !== password.trim()){
|
if (req.headers["risu-auth"].trim() !== password.trim()) {
|
||||||
console.log('incorrect')
|
console.log("incorrect");
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Password Incorrect'
|
error: "Password Incorrect",
|
||||||
});
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const filePath = req.headers['file-path'];
|
const filePath = req.headers["file-path"];
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
console.log('no path')
|
console.log("no path");
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'File path required'
|
error: "File path required",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isHex(filePath)){
|
if (!isHex(filePath)) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Invaild Path'
|
error: "Invaild Path",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
if(!existsSync(path.join(savePath, filePath))){
|
try {
|
||||||
|
const fileData = await cosmosStore.getData(filePath);
|
||||||
|
res.setHeader("Content-Type", "application/octet-stream");
|
||||||
|
res.send(fileData);
|
||||||
|
} catch (e) {
|
||||||
res.send();
|
res.send();
|
||||||
}
|
}
|
||||||
else{
|
if (!existsSync(path.join(savePath, filePath))) {
|
||||||
res.setHeader('Content-Type','application/octet-stream');
|
} else {
|
||||||
res.sendFile(path.join(savePath, filePath));
|
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/remove', async (req, res, next) => {
|
app.get("/api/remove", async (req, res, next) => {
|
||||||
if(req.headers['risu-auth'].trim() !== password.trim()){
|
if (req.headers["risu-auth"].trim() !== password.trim()) {
|
||||||
console.log('incorrect')
|
console.log("incorrect");
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Password Incorrect'
|
error: "Password Incorrect",
|
||||||
});
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const filePath = req.headers['file-path'];
|
const filePath = req.headers["file-path"];
|
||||||
if (!filePath) {
|
if (!filePath) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'File path required'
|
error: "File path required",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!isHex(filePath)){
|
if (!isHex(filePath)) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Invaild Path'
|
error: "Invaild Path",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.rm(path.join(savePath, filePath));
|
await cosmosStore.removeData(filePath);
|
||||||
res.send({
|
res.send({
|
||||||
success: true,
|
success: true,
|
||||||
});
|
});
|
||||||
@@ -306,54 +318,54 @@ app.get('/api/remove', async (req, res, next) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.get('/api/list', async (req, res, next) => {
|
app.get("/api/list", async (req, res, next) => {
|
||||||
if(req.headers['risu-auth'].trim() !== password.trim()){
|
if (req.headers["risu-auth"].trim() !== password.trim()) {
|
||||||
console.log('incorrect')
|
console.log("incorrect");
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Password Incorrect'
|
error: "Password Incorrect",
|
||||||
});
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const data = (await fs.readdir(path.join(savePath))).map((v) => {
|
const data = (await cosmosStore.listData()).map((v) => {
|
||||||
return Buffer.from(v, 'hex').toString('utf-8')
|
return Buffer.from(v, "hex").toString("utf-8");
|
||||||
})
|
});
|
||||||
res.send({
|
res.send({
|
||||||
success: true,
|
success: true,
|
||||||
content: data
|
content: data,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
app.post('/api/write', async (req, res, next) => {
|
app.post("/api/write", async (req, res, next) => {
|
||||||
if(req.headers['risu-auth'].trim() !== password.trim()){
|
if (req.headers["risu-auth"].trim() !== password.trim()) {
|
||||||
console.log('incorrect')
|
console.log("incorrect");
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Password Incorrect'
|
error: "Password Incorrect",
|
||||||
});
|
});
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
const filePath = req.headers['file-path'];
|
const filePath = req.headers["file-path"];
|
||||||
const fileContent = req.body
|
const fileContent = req.body;
|
||||||
if (!filePath || !fileContent) {
|
if (!filePath || !fileContent) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'File path required'
|
error: "File path required",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(!isHex(filePath)){
|
if (!isHex(filePath)) {
|
||||||
res.status(400).send({
|
res.status(400).send({
|
||||||
error:'Invaild Path'
|
error: "Invaild Path",
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await fs.writeFile(path.join(savePath, filePath), fileContent);
|
await cosmosStore.createData(filePath, fileContent);
|
||||||
res.send({
|
res.send({
|
||||||
success: true
|
success: true,
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
next(error);
|
next(error);
|
||||||
@@ -361,32 +373,28 @@ app.post('/api/write', async (req, res, next) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
async function getHttpsOptions() {
|
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');
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
await fs.access(keyPath);
|
await fs.access(keyPath);
|
||||||
await fs.access(certPath);
|
await fs.access(certPath);
|
||||||
|
|
||||||
const [key, cert] = await Promise.all([
|
const [key, cert] = await Promise.all([
|
||||||
fs.readFile(keyPath),
|
fs.readFile(keyPath),
|
||||||
fs.readFile(certPath)
|
fs.readFile(certPath),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return { key, cert };
|
return { key, cert };
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Server] SSL setup errors:', error.message);
|
console.error("[Server] SSL setup errors:", error.message);
|
||||||
console.log('[Server] Start the server with HTTP instead of HTTPS...');
|
console.log("[Server] Start the server with HTTP instead of HTTPS...");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startServer() {
|
async function startServer() {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
const port = process.env.PORT || 6001;
|
const port = process.env.PORT || 6001;
|
||||||
const httpsOptions = await getHttpsOptions();
|
const httpsOptions = await getHttpsOptions();
|
||||||
|
|
||||||
@@ -404,7 +412,7 @@ async function startServer() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Server] Failed to start server :', error);
|
console.error("[Server] Failed to start server :", error);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user