adds config setting for PoW verification timeout
This commit is contained in:
parent
8d2ed23522
commit
a3462e21bc
|
@ -127,6 +127,15 @@ type Config = {
|
||||||
* details on the available modes.
|
* details on the available modes.
|
||||||
*/
|
*/
|
||||||
powDifficultyLevel: "low" | "medium" | "high" | "extreme";
|
powDifficultyLevel: "low" | "medium" | "high" | "extreme";
|
||||||
|
/**
|
||||||
|
* Duration in minutes before a PoW challenge expires. Users' browsers must
|
||||||
|
* solve the challenge within this time frame or it will be rejected.
|
||||||
|
* Defaults to 30 minutes. It should be kept somewhat low to prevent abusive
|
||||||
|
* clients from working on many challenges in parallel, but you may need to
|
||||||
|
* increase this value for higher difficulty levels or older devices will not
|
||||||
|
* be able to solve the challenge in time.
|
||||||
|
*/
|
||||||
|
powChallengeTimeout: number;
|
||||||
/** Per-user limit for requests per minute to text and chat models. */
|
/** Per-user limit for requests per minute to text and chat models. */
|
||||||
textModelRateLimit: number;
|
textModelRateLimit: number;
|
||||||
/** Per-user limit for requests per minute to image generation models. */
|
/** Per-user limit for requests per minute to image generation models. */
|
||||||
|
@ -322,6 +331,7 @@ export const config: Config = {
|
||||||
powTokenHours: getEnvWithDefault("POW_TOKEN_HOURS", 24),
|
powTokenHours: getEnvWithDefault("POW_TOKEN_HOURS", 24),
|
||||||
powTokenMaxIps: getEnvWithDefault("POW_TOKEN_MAX_IPS", 2),
|
powTokenMaxIps: getEnvWithDefault("POW_TOKEN_MAX_IPS", 2),
|
||||||
powDifficultyLevel: getEnvWithDefault("POW_DIFFICULTY_LEVEL", "low"),
|
powDifficultyLevel: getEnvWithDefault("POW_DIFFICULTY_LEVEL", "low"),
|
||||||
|
powChallengeTimeout: getEnvWithDefault("POW_CHALLENGE_TIMEOUT", 30),
|
||||||
firebaseRtdbUrl: getEnvWithDefault("FIREBASE_RTDB_URL", undefined),
|
firebaseRtdbUrl: getEnvWithDefault("FIREBASE_RTDB_URL", undefined),
|
||||||
firebaseKey: getEnvWithDefault("FIREBASE_KEY", undefined),
|
firebaseKey: getEnvWithDefault("FIREBASE_KEY", undefined),
|
||||||
textModelRateLimit: getEnvWithDefault("TEXT_MODEL_RATE_LIMIT", 4),
|
textModelRateLimit: getEnvWithDefault("TEXT_MODEL_RATE_LIMIT", 4),
|
||||||
|
|
|
@ -16,7 +16,7 @@ const MODEL_FAMILY_FRIENDLY_NAME: { [f in ModelFamily]: string } = {
|
||||||
gpt4: "GPT-4",
|
gpt4: "GPT-4",
|
||||||
"gpt4-32k": "GPT-4 32k",
|
"gpt4-32k": "GPT-4 32k",
|
||||||
"gpt4-turbo": "GPT-4 Turbo",
|
"gpt4-turbo": "GPT-4 Turbo",
|
||||||
"gpt4o": "GPT-4o",
|
gpt4o: "GPT-4o",
|
||||||
"dall-e": "DALL-E",
|
"dall-e": "DALL-E",
|
||||||
claude: "Claude (Sonnet)",
|
claude: "Claude (Sonnet)",
|
||||||
"claude-opus": "Claude (Opus)",
|
"claude-opus": "Claude (Opus)",
|
||||||
|
@ -146,11 +146,15 @@ This proxy keeps full logs of all prompts and AI responses. Prompt logs are anon
|
||||||
|
|
||||||
function getSelfServiceLinks() {
|
function getSelfServiceLinks() {
|
||||||
if (config.gatekeeper !== "user_token") return "";
|
if (config.gatekeeper !== "user_token") return "";
|
||||||
const links = [
|
|
||||||
["Request a user token", "/user/captcha",],
|
const links = [["Check your user token", "/user/lookup"]];
|
||||||
["Check your user token", "/user/lookup",]
|
if (config.captchaMode !== "none") {
|
||||||
]
|
links.unshift(["Request a user token", "/user/captcha"]);
|
||||||
return `<div style="font-size: 0.8em;">${links.map(([text, link]) => `<a target="_blank" href="${link}">${text}</a>`).join(" / ")}</div><hr />`;
|
}
|
||||||
|
|
||||||
|
return `<div style="font-size: 0.8em;">${links
|
||||||
|
.map(([text, link]) => `<a target="_blank" href="${link}">${text}</a>`)
|
||||||
|
.join(" / ")}</div><hr />`;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getServerTitle() {
|
function getServerTitle() {
|
||||||
|
@ -262,7 +266,7 @@ if (config.serviceInfoPassword?.length) {
|
||||||
});
|
});
|
||||||
infoPageRouter.use(checkIfUnlocked);
|
infoPageRouter.use(checkIfUnlocked);
|
||||||
}
|
}
|
||||||
infoPageRouter.get("/", handleInfoPage);
|
infoPageRouter.get("/", (req, res) => res.sendStatus(204));
|
||||||
infoPageRouter.get("/status", (req, res) => {
|
infoPageRouter.get("/status", (req, res) => {
|
||||||
res.json(buildInfo(req.protocol + "://" + req.get("host"), false));
|
res.json(buildInfo(req.protocol + "://" + req.get("host"), false));
|
||||||
});
|
});
|
||||||
|
|
|
@ -3,7 +3,6 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<meta name="csrf-token" content="<%= csrfToken %>" />
|
<meta name="csrf-token" content="<%= csrfToken %>" />
|
||||||
<!-- prettier-ignore -->
|
|
||||||
<title><%= title %></title>
|
<title><%= title %></title>
|
||||||
<style>
|
<style>
|
||||||
body {
|
body {
|
||||||
|
@ -112,5 +111,3 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%- include("partials/shared_flash", { flashData: flash }) %>
|
<%- include("partials/shared_flash", { flashData: flash }) %>
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
|
|
|
@ -7,8 +7,6 @@ import { config } from "../../config";
|
||||||
|
|
||||||
/** HMAC key for signing challenges; regenerated on startup */
|
/** HMAC key for signing challenges; regenerated on startup */
|
||||||
const HMAC_KEY = crypto.randomBytes(32).toString("hex");
|
const HMAC_KEY = crypto.randomBytes(32).toString("hex");
|
||||||
/** Expiry time for a challenge in milliseconds */
|
|
||||||
const POW_EXPIRY = 1000 * 60 * 30; // 30 minutes
|
|
||||||
/** Lockout time after verification in milliseconds */
|
/** Lockout time after verification in milliseconds */
|
||||||
const LOCKOUT_TIME = 1000 * 60; // 60 seconds
|
const LOCKOUT_TIME = 1000 * 60; // 60 seconds
|
||||||
|
|
||||||
|
@ -95,7 +93,7 @@ setInterval(() => {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const [key, timestamp] of solves) {
|
for (const [key, timestamp] of solves) {
|
||||||
if (now - timestamp > POW_EXPIRY) {
|
if (now - timestamp > config.powChallengeTimeout * 1000 * 60) {
|
||||||
solves.delete(key);
|
solves.delete(key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -118,7 +116,7 @@ function generateChallenge(clientIp?: string, token?: string): Challenge {
|
||||||
m: argon2Params.ARGON2_MEMORY_KB,
|
m: argon2Params.ARGON2_MEMORY_KB,
|
||||||
p: argon2Params.ARGON2_PARALLELISM,
|
p: argon2Params.ARGON2_PARALLELISM,
|
||||||
d: targetValue.toString() + "n",
|
d: targetValue.toString() + "n",
|
||||||
e: Date.now() + POW_EXPIRY,
|
e: Date.now() + config.powChallengeTimeout * 1000 * 60,
|
||||||
ip: clientIp,
|
ip: clientIp,
|
||||||
token,
|
token,
|
||||||
};
|
};
|
||||||
|
|
|
@ -71,25 +71,21 @@
|
||||||
</style>
|
</style>
|
||||||
<div style="display: none" id="captcha-container">
|
<div style="display: none" id="captcha-container">
|
||||||
<p>
|
<p>
|
||||||
Your device needs to perform a verification task before a user token will be issued. This verification might take
|
Your device needs to perform a verification task before you can receive access. This might take anywhere from a few
|
||||||
anywhere from a few seconds to a few minutes, depending on your device and the proxy's security settings.
|
seconds to a few minutes, depending on your device and the proxy's security settings.
|
||||||
</p>
|
</p>
|
||||||
<p>Click the button below to start.</p>
|
<p>Click the button below to start.</p>
|
||||||
<details>
|
<details>
|
||||||
<summary>What is this?</summary>
|
<summary>What is this?</summary>
|
||||||
<p>
|
<p>
|
||||||
This is an anti-abuse measure to slow down automated requests. It requires your device's CPU to find a solution to
|
This is an anti-abuse measure designed to slow down automated requests. It requires your device's CPU to find a
|
||||||
a cryptographic puzzle, after which a user token will be issued.
|
solution to a cryptographic puzzle, after which a user token will be issued.
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Your browser may slow down during the verification process. If you want to do something else while waiting, reduce
|
|
||||||
the number of workers to reduce the load on your device's CPU.
|
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
<summary>How long does verification take?</summary>
|
<summary>How long does verification take?</summary>
|
||||||
<p>
|
<p>
|
||||||
The exact time depends on the device you're using and the server's difficulty setting (currently
|
It on the device you're using and the verification task's difficulty level (currently
|
||||||
<strong><%= difficultyLevel %></strong>). It could take anywhere from a few seconds to a few minutes.
|
<strong><%= difficultyLevel %></strong>). It could take anywhere from a few seconds to a few minutes.
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
|
@ -97,8 +93,19 @@
|
||||||
<summary>How often do I need to do this?</summary>
|
<summary>How often do I need to do this?</summary>
|
||||||
<p>Once you've earned a user token, you can use it for <%= tokenLifetime %> hours before it expires.</p>
|
<p>Once you've earned a user token, you can use it for <%= tokenLifetime %> hours before it expires.</p>
|
||||||
<p>
|
<p>
|
||||||
You can refresh an expired token by returning to this page and completing the verification again, which will be
|
You can refresh an expired token by returning to this page and verifying again. Subsequent verifications will go
|
||||||
faster than the first time.
|
faster than the first one.
|
||||||
|
</p>
|
||||||
|
</details>
|
||||||
|
<details>
|
||||||
|
<summary>What is the "Workers" setting?</summary>
|
||||||
|
<p>
|
||||||
|
This controls how many CPU cores will be used to solve the verification task. By default, all of your device's
|
||||||
|
cores will be used to solve the task as quickly as possible.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
If your device gets too hot or you want to use it for other tasks while verification is in progress, reduce the
|
||||||
|
number of workers to lower the CPU load at the cost of slower verification.
|
||||||
</p>
|
</p>
|
||||||
</details>
|
</details>
|
||||||
<details>
|
<details>
|
||||||
|
|
|
@ -18,9 +18,7 @@
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<h1>Request User Token</h1>
|
<h1>Request User Token</h1>
|
||||||
<p>
|
<p>You can request a temporary user token to use this proxy. The token will be valid for <%= tokenLifetime %> hours.</p>
|
||||||
You can request a temporary user token to use this proxy. The token will be valid for <%= tokenLifetime %> hours.
|
|
||||||
</p>
|
|
||||||
<% if (keyRequired) { %>
|
<% if (keyRequired) { %>
|
||||||
<div>
|
<div>
|
||||||
<p>You need to supply the proxy password to request or refresh a token.</p>
|
<p>You need to supply the proxy password to request or refresh a token.</p>
|
||||||
|
@ -31,10 +29,7 @@
|
||||||
</div>
|
</div>
|
||||||
<% } %>
|
<% } %>
|
||||||
<div id="existing-token" style="display: none">
|
<div id="existing-token" style="display: none">
|
||||||
<p>
|
<p>It looks like you might have an older temporary user token. If it has expired, you can try to refresh it.</p>
|
||||||
It looks like you might have an older temporary user token. You can refresh its expiration by completing a
|
|
||||||
faster verification challenge.
|
|
||||||
</p>
|
|
||||||
<strong id="existing-token-value">Existing token:</strong>
|
<strong id="existing-token-value">Existing token:</strong>
|
||||||
</div>
|
</div>
|
||||||
<div id="request-buttons">
|
<div id="request-buttons">
|
||||||
|
|
Loading…
Reference in New Issue