update at 2026-04-21 17:55:41

This commit is contained in:
douboer
2026-04-21 17:55:41 +08:00
parent dda7eaeec1
commit 6199ec79d4
37 changed files with 1106 additions and 174 deletions

63
server/dist/config.js vendored Normal file
View File

@@ -0,0 +1,63 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.config = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
function readDotEnv(dotEnvPath) {
if (!fs.existsSync(dotEnvPath)) {
return {};
}
const content = fs.readFileSync(dotEnvPath, "utf8");
const parsed = {};
for (const rawLine of content.split(/\r?\n/)) {
const line = rawLine.trim();
if (line.length === 0 || line.startsWith("#")) {
continue;
}
const index = line.indexOf("=");
if (index <= 0) {
continue;
}
const key = line.slice(0, index).trim();
const value = line.slice(index + 1).trim();
if (key.length > 0 && !(key in parsed)) {
parsed[key] = value;
}
}
return parsed;
}
const cwd = process.cwd();
const dotEnv = readDotEnv(path.join(cwd, ".env"));
function getEnv(name, fallback = "") {
var _a, _b;
const value = (_b = (_a = process.env[name]) !== null && _a !== void 0 ? _a : dotEnv[name]) !== null && _b !== void 0 ? _b : fallback;
return value.trim();
}
exports.config = {
port: parseInt(getEnv("PORT", "3001"), 10),
encryptKey: getEnv("ENCRYPT_KEY"),
usersFile: path.resolve(cwd, getEnv("USERS_FILE", "./data/users.json")),
};

53
server/dist/crypto.js vendored Normal file
View File

@@ -0,0 +1,53 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.decrypt = exports.encrypt = void 0;
const crypto = __importStar(require("crypto"));
const config_1 = require("./config");
const ALGORITHM = "aes-256-cbc";
const IV_LENGTH = 16;
function getKey() {
if (config_1.config.encryptKey.length !== 32) {
throw new Error("ENCRYPT_KEY must be a 32-character string");
}
return Buffer.from(config_1.config.encryptKey, "utf8");
}
function encrypt(text) {
const iv = crypto.randomBytes(IV_LENGTH);
const cipher = crypto.createCipheriv(ALGORITHM, getKey(), iv);
const encrypted = Buffer.concat([cipher.update(text, "utf8"), cipher.final()]);
return iv.toString("hex") + encrypted.toString("hex");
}
exports.encrypt = encrypt;
function decrypt(encrypted) {
const ivHex = encrypted.slice(0, IV_LENGTH * 2);
const contentHex = encrypted.slice(IV_LENGTH * 2);
const iv = Buffer.from(ivHex, "hex");
const content = Buffer.from(contentHex, "hex");
const decipher = crypto.createDecipheriv(ALGORITHM, getKey(), iv);
const decrypted = Buffer.concat([decipher.update(content), decipher.final()]);
return decrypted.toString("utf8");
}
exports.decrypt = decrypt;

31
server/dist/http.js vendored Normal file
View File

@@ -0,0 +1,31 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.readJsonBody = exports.sendJson = void 0;
function sendJson(res, statusCode, payload) {
const body = JSON.stringify(payload);
res.writeHead(statusCode, {
"Content-Type": "application/json; charset=utf-8",
"Cache-Control": "no-store",
"Content-Length": Buffer.byteLength(body),
});
res.end(body);
}
exports.sendJson = sendJson;
async function readJsonBody(req, limitBytes = 10 * 1024 * 1024) {
const chunks = [];
let size = 0;
for await (const chunk of req) {
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
size += buffer.length;
if (size > limitBytes) {
throw new Error("Request body too large");
}
chunks.push(buffer);
}
const raw = Buffer.concat(chunks).toString("utf8").trim();
if (raw.length === 0) {
return {};
}
return JSON.parse(raw);
}
exports.readJsonBody = readJsonBody;

127
server/dist/index.js vendored Normal file
View File

@@ -0,0 +1,127 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const http = __importStar(require("http"));
const url_1 = require("url");
const config_1 = require("./config");
const crypto_1 = require("./crypto");
const http_1 = require("./http");
const wechat_1 = require("./wechat");
const tokenCache = {};
function isNonEmptyString(value) {
return typeof value === "string" && value.trim().length > 0;
}
async function handleToken(req, res) {
var _a;
const body = await (0, http_1.readJsonBody)(req);
const appid = typeof body.appid === "string" ? body.appid.trim() : "";
const secret = typeof body.secret === "string" ? body.secret.trim() : "";
if (!appid || !secret) {
(0, http_1.sendJson)(res, 400, { code: 400, msg: "Missing required fields" });
return;
}
const cached = tokenCache[appid];
if (cached && cached.expiresAt > Date.now()) {
(0, http_1.sendJson)(res, 200, {
access_token: cached.token,
expires_in: Math.floor((cached.expiresAt - Date.now()) / 1000),
});
return;
}
const realSecret = secret.startsWith("SECRET") ? (0, crypto_1.decrypt)(secret.slice(6)) : secret;
const wxUrl = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${encodeURIComponent(appid)}&secret=${encodeURIComponent(realSecret)}`;
const wxRes = await (0, wechat_1.httpsGetJson)(wxUrl);
if (typeof wxRes.errcode === "number") {
(0, http_1.sendJson)(res, 200, { code: wxRes.errcode, msg: (_a = wxRes.errmsg) !== null && _a !== void 0 ? _a : "" });
return;
}
if (!isNonEmptyString(wxRes.access_token) || typeof wxRes.expires_in !== "number") {
throw new Error("Invalid token response from WeChat API");
}
tokenCache[appid] = {
token: wxRes.access_token,
expiresAt: Date.now() + 7000 * 1000,
};
(0, http_1.sendJson)(res, 200, { ...wxRes });
}
async function handleEncrypt(req, res) {
const body = await (0, http_1.readJsonBody)(req);
const wechat = Array.isArray(body.wechat) ? body.wechat : [];
if (wechat.length === 0) {
(0, http_1.sendJson)(res, 400, { code: 400, msg: "Missing required fields" });
return;
}
const encrypted = wechat.map((item) => ({
name: typeof item.name === "string" ? item.name : "",
appid: typeof item.appid === "string" ? item.appid : "",
secret: "SECRET" + (0, crypto_1.encrypt)(typeof item.secret === "string" ? item.secret : ""),
}));
(0, http_1.sendJson)(res, 200, { code: 0, wechat: encrypted });
}
function handleInfo(authkey, res) {
(0, http_1.sendJson)(res, 200, {
code: 0,
name: authkey || "note2any",
status: "active",
created: "",
});
}
async function requestHandler(req, res) {
var _a, _b;
const method = (_a = req.method) !== null && _a !== void 0 ? _a : "GET";
const url = new url_1.URL((_b = req.url) !== null && _b !== void 0 ? _b : "/", "http://127.0.0.1");
const pathname = url.pathname;
try {
if (method === "GET" && pathname === "/") {
(0, http_1.sendJson)(res, 200, { status: "ok", service: "note2any-wx-server" });
return;
}
if (method === "POST" && pathname === "/v1/wx/token") {
await handleToken(req, res);
return;
}
if (method === "POST" && pathname === "/v1/wx/encrypt") {
await handleEncrypt(req, res);
return;
}
if (method === "GET" && pathname.startsWith("/v1/wx/info/")) {
const authkey = decodeURIComponent(pathname.slice("/v1/wx/info/".length));
handleInfo(authkey, res);
return;
}
(0, http_1.sendJson)(res, 404, { code: 404, msg: "Not Found" });
}
catch (error) {
const message = error instanceof Error ? error.message : "Unknown server error";
console.error(`[server] ${method} ${pathname} failed: ${message}`);
(0, http_1.sendJson)(res, 500, { code: 500, msg: message });
}
}
const server = http.createServer((req, res) => {
void requestHandler(req, res);
});
server.listen(config_1.config.port, () => {
console.log(`note2any-wx-server running on port ${config_1.config.port}`);
});

44
server/dist/users.js vendored Normal file
View File

@@ -0,0 +1,44 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateAuthKey = void 0;
const fs = __importStar(require("fs"));
const config_1 = require("./config");
function readUsersFile() {
const content = fs.readFileSync(config_1.config.usersFile, "utf8");
return JSON.parse(content);
}
function validateAuthKey(authkey) {
const users = readUsersFile().users;
const user = users[authkey];
if (!user) {
return null;
}
if (user.status !== "active") {
return null;
}
return user;
}
exports.validateAuthKey = validateAuthKey;

46
server/dist/wechat.js vendored Normal file
View File

@@ -0,0 +1,46 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.httpsGetJson = void 0;
const https = __importStar(require("https"));
function httpsGetJson(url) {
return new Promise((resolve, reject) => {
https.get(url, (res) => {
let data = "";
res.on("data", (chunk) => {
data += chunk;
});
res.on("end", () => {
try {
resolve(JSON.parse(data));
}
catch (_error) {
reject(new Error("Invalid JSON from WeChat API"));
}
});
}).on("error", reject);
});
}
exports.httpsGetJson = httpsGetJson;