disables keys shared between too many IP addresses

This commit is contained in:
nai-degen 2023-05-14 14:30:32 -05:00
parent 285186d70e
commit 6eb121ac66
3 changed files with 16 additions and 2 deletions

View File

@ -16,6 +16,8 @@
# Optional settings for user management. See docs/user-management.md. # Optional settings for user management. See docs/user-management.md.
# GATEKEEPER=none # GATEKEEPER=none
# GATEKEEPER_STORE=memory
# MAX_IPS_PER_USER=20
# Optional settings for prompt logging. See docs/logging-sheets.md. # Optional settings for prompt logging. See docs/logging-sheets.md.
# PROMPT_LOGGING=false # PROMPT_LOGGING=false

View File

@ -49,6 +49,8 @@ type Config = {
firebaseRtdbUrl?: string; firebaseRtdbUrl?: string;
/** Base64-encoded Firebase service account key if using the Firebase RTDB store. */ /** Base64-encoded Firebase service account key if using the Firebase RTDB store. */
firebaseKey?: string; firebaseKey?: string;
/** Maximum number of IPs per user, after which their token is disabled. */
maxIpsPerUser: number;
/** Per-IP limit for requests per minute to OpenAI's completions endpoint. */ /** Per-IP limit for requests per minute to OpenAI's completions endpoint. */
modelRateLimit: number; modelRateLimit: number;
/** Max number of tokens to generate. Requests which specify a higher value will be rewritten to use this value. */ /** Max number of tokens to generate. Requests which specify a higher value will be rewritten to use this value. */
@ -100,6 +102,7 @@ export const config: Config = {
adminKey: getEnvWithDefault("ADMIN_KEY", ""), adminKey: getEnvWithDefault("ADMIN_KEY", ""),
gatekeeper: getEnvWithDefault("GATEKEEPER", "none"), gatekeeper: getEnvWithDefault("GATEKEEPER", "none"),
gatekeeperStore: getEnvWithDefault("GATEKEEPER_STORE", "memory"), gatekeeperStore: getEnvWithDefault("GATEKEEPER_STORE", "memory"),
maxIpsPerUser: getEnvWithDefault("MAX_IPS_PER_USER", 20),
firebaseRtdbUrl: getEnvWithDefault("FIREBASE_RTDB_URL", undefined), firebaseRtdbUrl: getEnvWithDefault("FIREBASE_RTDB_URL", undefined),
firebaseKey: getEnvWithDefault("FIREBASE_KEY", undefined), firebaseKey: getEnvWithDefault("FIREBASE_KEY", undefined),
modelRateLimit: getEnvWithDefault("MODEL_RATE_LIMIT", 4), modelRateLimit: getEnvWithDefault("MODEL_RATE_LIMIT", 4),

View File

@ -43,6 +43,8 @@ export type UserType = "normal" | "special";
type UserUpdate = Partial<User> & Pick<User, "token">; type UserUpdate = Partial<User> & Pick<User, "token">;
const MAX_IPS_PER_USER = config.maxIpsPerUser;
const users: Map<string, User> = new Map(); const users: Map<string, User> = new Map();
const usersToFlush = new Set<string>(); const usersToFlush = new Set<string>();
@ -98,12 +100,12 @@ export function upsertUser(user: UserUpdate) {
...user, ...user,
}); });
usersToFlush.add(user.token); usersToFlush.add(user.token);
// Immediately schedule a flush to the database if we're using Firebase. // Immediately schedule a flush to the database if we're using Firebase.
if (config.gatekeeperStore === "firebase_rtdb") { if (config.gatekeeperStore === "firebase_rtdb") {
setImmediate(flushUsers); setImmediate(flushUsers);
} }
return users.get(user.token); return users.get(user.token);
} }
@ -132,6 +134,13 @@ export function authenticate(token: string, ip: string) {
const user = users.get(token); const user = users.get(token);
if (!user || user.disabledAt) return; if (!user || user.disabledAt) return;
if (!user.ip.includes(ip)) user.ip.push(ip); if (!user.ip.includes(ip)) user.ip.push(ip);
// If too many IPs are associated with the user, disable the account.
if (user.ip.length > MAX_IPS_PER_USER) {
disableUser(token, "Too many IP addresses associated with this token.");
return;
}
user.lastUsedAt = Date.now(); user.lastUsedAt = Date.now();
usersToFlush.add(token); usersToFlush.add(token);
return user; return user;