codexui-android 0.1.81 → 0.1.83

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist-cli/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import "./chunk-BEXSKX6U.js";
2
+ import "./chunk-UUZOL7SL.js";
3
3
 
4
4
  // src/cli/index.ts
5
5
  import { createServer as createServer2 } from "http";
@@ -227,7 +227,7 @@ import * as Sentry4 from "@sentry/node";
227
227
  import { spawn as spawn4 } from "child_process";
228
228
  import { createHash as createHash2, randomBytes } from "crypto";
229
229
  import { mkdtemp as mkdtemp3, readFile as readFile3, rm as rm4, mkdir as mkdir4, stat as stat4 } from "fs/promises";
230
- import { createReadStream } from "fs";
230
+ import { createReadStream, readFileSync } from "fs";
231
231
  import { request as httpRequest } from "http";
232
232
  import { request as httpsRequest } from "https";
233
233
  import { homedir as homedir4 } from "os";
@@ -3141,8 +3141,27 @@ function getErrorMessage4(payload, fallback) {
3141
3141
  }
3142
3142
  return fallback;
3143
3143
  }
3144
+ function normalizeTelegramAllowlist(values) {
3145
+ const rawValues = Array.isArray(values) ? values : [];
3146
+ const allowAllUsers = rawValues.some((value) => typeof value === "string" && value.trim() === "*");
3147
+ const allowedUserIds = Array.from(new Set(rawValues.map((value) => {
3148
+ if (typeof value === "number" && Number.isFinite(value)) {
3149
+ return Math.trunc(value);
3150
+ }
3151
+ if (typeof value === "string" && value.trim().length > 0) {
3152
+ const normalized = value.trim().replace(/^(telegram|tg):/i, "").trim();
3153
+ if (/^-?\d+$/.test(normalized)) {
3154
+ return Number.parseInt(normalized, 10);
3155
+ }
3156
+ }
3157
+ return Number.NaN;
3158
+ }).filter((value) => Number.isFinite(value)))).slice(0, 100);
3159
+ return { allowAllUsers, allowedUserIds };
3160
+ }
3144
3161
  var TelegramThreadBridge = class {
3145
3162
  constructor(appServer, options = {}) {
3163
+ this.allowAllUsers = false;
3164
+ this.allowedUserIds = /* @__PURE__ */ new Set();
3146
3165
  this.threadIdByChatId = /* @__PURE__ */ new Map();
3147
3166
  this.chatIdsByThreadId = /* @__PURE__ */ new Map();
3148
3167
  this.lastForwardedTurnByThreadId = /* @__PURE__ */ new Map();
@@ -3153,6 +3172,9 @@ var TelegramThreadBridge = class {
3153
3172
  this.appServer = appServer;
3154
3173
  this.token = process.env.TELEGRAM_BOT_TOKEN?.trim() ?? "";
3155
3174
  this.defaultCwd = process.env.TELEGRAM_DEFAULT_CWD?.trim() ?? process.cwd();
3175
+ this.configureAllowedUserIds(
3176
+ (process.env.TELEGRAM_ALLOWED_USER_IDS ?? "").split(",").map((value) => value.trim()).filter(Boolean)
3177
+ );
3156
3178
  this.onChatSeen = options.onChatSeen;
3157
3179
  }
3158
3180
  start() {
@@ -3220,9 +3242,16 @@ var TelegramThreadBridge = class {
3220
3242
  active: this.active,
3221
3243
  mappedChats: this.threadIdByChatId.size,
3222
3244
  mappedThreads: this.chatIdsByThreadId.size,
3245
+ allowedUsers: this.allowedUserIds.size,
3246
+ allowAllUsers: this.allowAllUsers,
3223
3247
  lastError: this.lastError
3224
3248
  };
3225
3249
  }
3250
+ configureAllowedUserIds(allowedUserIds) {
3251
+ const normalized = normalizeTelegramAllowlist(allowedUserIds);
3252
+ this.allowAllUsers = normalized.allowAllUsers;
3253
+ this.allowedUserIds = new Set(normalized.allowedUserIds);
3254
+ }
3226
3255
  connectThread(threadId, chatId, token) {
3227
3256
  const normalizedThreadId = threadId.trim();
3228
3257
  if (!normalizedThreadId) {
@@ -3276,8 +3305,13 @@ var TelegramThreadBridge = class {
3276
3305
  }
3277
3306
  const message = update.message;
3278
3307
  const chatId = message?.chat?.id;
3308
+ const senderId = message?.from?.id;
3279
3309
  const text = message?.text?.trim();
3280
3310
  if (typeof chatId !== "number" || !text) return;
3311
+ if (!this.isAllowedSender(senderId)) {
3312
+ await this.sendTelegramMessage(chatId, this.unauthorizedMessage(senderId));
3313
+ return;
3314
+ }
3281
3315
  this.markChatSeen(chatId);
3282
3316
  if (text === "/start") {
3283
3317
  await this.sendThreadPicker(chatId);
@@ -3310,6 +3344,16 @@ var TelegramThreadBridge = class {
3310
3344
  const callbackId = typeof callbackQuery.id === "string" ? callbackQuery.id : "";
3311
3345
  const data = typeof callbackQuery.data === "string" ? callbackQuery.data : "";
3312
3346
  const chatId = callbackQuery.message?.chat?.id;
3347
+ const senderId = callbackQuery.from?.id;
3348
+ if (!this.isAllowedSender(senderId)) {
3349
+ if (callbackId) {
3350
+ await this.answerCallbackQuery(callbackId, this.unauthorizedCallbackMessage(senderId));
3351
+ }
3352
+ if (typeof chatId === "number") {
3353
+ await this.sendTelegramMessage(chatId, this.unauthorizedMessage(senderId));
3354
+ }
3355
+ return;
3356
+ }
3313
3357
  if (typeof chatId === "number") {
3314
3358
  this.markChatSeen(chatId);
3315
3359
  }
@@ -3331,6 +3375,25 @@ var TelegramThreadBridge = class {
3331
3375
  await this.sendTelegramMessage(chatId, history);
3332
3376
  }
3333
3377
  }
3378
+ isAllowedSender(senderId) {
3379
+ if (this.allowAllUsers) {
3380
+ return typeof senderId === "number" && Number.isFinite(senderId);
3381
+ }
3382
+ return typeof senderId === "number" && Number.isFinite(senderId) && this.allowedUserIds.has(Math.trunc(senderId));
3383
+ }
3384
+ unauthorizedMessage(senderId) {
3385
+ const normalizedSenderId = typeof senderId === "number" && Number.isFinite(senderId) ? String(Math.trunc(senderId)) : "unknown";
3386
+ return `Unauthorized sender.
3387
+
3388
+ Your Telegram user ID: ${normalizedSenderId}
3389
+ Add this ID to the bot allowlist before using the bridge.`;
3390
+ }
3391
+ unauthorizedCallbackMessage(senderId) {
3392
+ if (typeof senderId === "number" && Number.isFinite(senderId)) {
3393
+ return `Unauthorized: ${String(Math.trunc(senderId))}`;
3394
+ }
3395
+ return "Unauthorized sender";
3396
+ }
3334
3397
  async answerCallbackQuery(callbackQueryId, text) {
3335
3398
  await fetch(this.apiUrl("answerCallbackQuery"), {
3336
3399
  method: "POST",
@@ -3499,6 +3562,163 @@ ${summary}`;
3499
3562
  }
3500
3563
  };
3501
3564
 
3565
+ // src/server/freeMode.ts
3566
+ var ENCRYPTED_KEYS = [
3567
+ "FhkYWwEZE0MYBhAGUEADDBYFBEoDBxIHVUpUVRIMVUYDAkEHVRYNAxABUUAEAUMDV0pUDEQAU0ZTDEQCVERQVkoBVhAEBBBXAQ==",
3568
+ "FhkYWwEZE0MYVkIGUkNUUkpVXUsBBUUAVEYHUEIMBhQCVxZWBBcHVkoNUENRAxAMA0MHARBXBkVUAUVQXBAFAUVXVxFWBUtWBw==",
3569
+ "FhkYWwEZE0MYVhFWAUJUUBEMURMHAUoEAUcABRAEURRXARBRU0ZUBBFVB0YAAUNVVUYBDBBSABRUAhdVXUUBUhANV0IMBBABBA==",
3570
+ "FhkYWwEZE0MYUBIDABMBVkMHURcGDRVSXRMFBUUCBBQBVhUBUBEGDBAAVkpTVUoGUBYMBhJXB0ANABUEARBQB0RRXUBRBUNQBw==",
3571
+ "FhkYWwEZE0MYVhcFBhMFARJXVBMADRdWVxYHBkQNA0cBBEsGVEBRAkYCXEFXURBXABZQDEZSXBQHAkJSAUABVxIMA0NWAEcMUA==",
3572
+ "FhkYWwEZE0MYAEQAXEZQURUGARFRBkRWVENWDUYFBkQHBEJWU0dQUkdWBhZXARYMAERXURcBUUQNDUAGAEoEB0ABV0NTUkQDBw==",
3573
+ "FhkYWwEZE0MYABdRURBXVkYDURZWUUIAUEcMBEcMUUpXVxEGVhEMBktVXBBWAEFQBBBRVhECUEQEBkFQUUpRVRUMV0dRA0QGUw==",
3574
+ "FhkYWwEZE0MYVUMCUUIHAUFRVksFVhYMARRRBBIAVBMBDEFVAxMAAUpRXUsEBkMHVhAHBUdSVxECABJSVRdRBkMEURANAEdXVA==",
3575
+ "FhkYWwEZE0MYUkEFVEVUBEoMVkINDUFQUENQAkBSAEVQVhcEAEsDBxVWUkBWAkRSA0ANV0FVBkYMVxcBXUQEUEQCARYDDEpWXA==",
3576
+ "FhkYWwEZE0MYDBcCXBANBRdVU0YEAEsMAUoNUkoMUBYDABcHVEBQBkRVUxdWBUUAAURUVxUGB0oDVxIHABRUAhJRAEUDUkECXQ==",
3577
+ "FhkYWwEZE0MYVhUHVBEBURFQA0EBVRcNUUZXAhVXVkpQAEUHBhNTDUQMXRAGA0JQA0BRBRUHVRQMURVWXUoBVxcEBEYEAEACUQ==",
3578
+ "FhkYWwEZE0MYA0UCB0ZTABUNBhRTAUYAUENQUEANBEMCARdQBkRRBRYDUhdWVhACXBcGBhIDVBFRBRJQUREGDRAAUhQHUhUBAA==",
3579
+ "FhkYWwEZE0MYAUsMARACBBYGVxQHARVQVxRRBRcNUkAFUUQCXBEAUkcBXEMBBEYCXRENBUsBVRYABUJXU0FUAEYBUUpWABEGUw==",
3580
+ "FhkYWwEZE0MYAEdSUBcNAUoFUERUAkcFAEQAB0IBUxcFDUIMBEpQVktWUxdUB0MBXUEBBhIMXRQEUBFQXEMFAEBQXUEMVkoBUQ==",
3581
+ "FhkYWwEZE0MYDBYNUUVUA0ECUREMVhUEBkoCVxJSXEtRUENQVxAMBBcMAxACVkVVBEEDUEYDAURWA0oDXUYAAEEEVxQABUANVg==",
3582
+ "FhkYWwEZE0MYVhcHBhcFV0EBUEdWVxdSU0sMABFSUEIHA0EAU0dWBkcFXEZRBENXAUEDV0AFUkEABBAEXBdXAhZRBEAAUUBSVg==",
3583
+ "FhkYWwEZE0MYV0MHAxYBDUsHB0oFVRJWAUoABEQGAUEHDRdRUBQHBREFUkpQVUYHVkVTDBcDXUYHBkJXUhENVUIAVUtTDRcMVA==",
3584
+ "FhkYWwEZE0MYBxVXBEsAUkYBA0EEAUIGBkRQA0MNABZRVkcHA0JTUEdWUkNRBBUEXUFUB0oFB0QGDBdWUUsEV0NXBBQBVRUEVg==",
3585
+ "FhkYWwEZE0MYVxcCVBYHAEsNVBEADEENUkMAUhFWXBNUVxdWBxNWURYAVEEAUUdSURAHDUsAUkEABBJSVRZQV0YNVRBRDUVSBw==",
3586
+ "FhkYWwEZE0MYAEQEV0YGVxcMVkRQUEsGUEBRUEADAEYEV0NRBBRWBUpXV0oMA0NRXBBRAkAMXUZWURBSXEZRB0EEVBQNVxYBXQ==",
3587
+ "FhkYWwEZE0MYA0IBUhADUERXB0MNB0MHVUtUDRUNBEpXVkEGUBMABkZVUENUAkBVXRAEDEAHBkJWABAEURNWDEcEABQCVUdVVA==",
3588
+ "FhkYWwEZE0MYUhcEBBYCAUFSXUAEAEEBV0sDDRAFV0YDV0NVBENXB0QNVxdUAkYMXUQGA0tRV0tWVUoDAxcGUUVVVUQHDBEDBA==",
3589
+ "FhkYWwEZE0MYA0QBBEIAB0INXUtTBxYFVBFXABJSBkYEAxIAVEAGVkZSB0tQUEoHBkcGBBUHVENWAUNRUEYCAhJSXRcNUEQGUA==",
3590
+ "FhkYWwEZE0MYUBJQUEIFUkBXARBUBUIDAxBQVhJVVkUMVhEDAEYNVxEGBhRUVkJWURYDAUAAAUUMARVRBhYAUkAEUkUEAhYCVg==",
3591
+ "FhkYWwEZE0MYVUYGVBcEDEAFVhACVkFWXBFTAxAMUUpQURENARYBVhABAEINAEQCAUECDEsCBEUBVxBXBxRUVxdQBBRXVkcCUA==",
3592
+ "FhkYWwEZE0MYV0YMVxBTVUNQBERRURVSUxQGUUVWB0MGVUMHV0cHUkMEAEMDDUMCVEcGVkNVB0oDURdVAUFQBkIAURYDBhAHAA==",
3593
+ "FhkYWwEZE0MYUhYCXEsNVUAEURFXBkcHABFQBxcFUENWVkpVAxZWAhEBAxMBBkRRVUtQDEZWXEoBBxUNVkYBBhJQUBBQUUoDBw==",
3594
+ "FhkYWwEZE0MYB0YGXUIGDRIHVRZQVUJSV0UNB0oNAxQADRUMVUcEBhdQV0AHDUZXAEtQVkVQUhBRBUBSUEQCVkRSBEUDUkQEVQ==",
3595
+ "FhkYWwEZE0MYB0MGAUEADERVV0RXDUJSUUMAUEdRAUMCBxZSBktQDUMEBkIBBkIDAEMNURdRXUoFB0RWVEZRDUFXAEJTVRVWVg==",
3596
+ "FhkYWwEZE0MYAkQDAxcFBEpXVEIEDUJSB0tXBhVXUkIDAEEMBBBXDUdRVRcNBURVAxZXUUENARYNBkMAUBBTDUsGVUFWDEcAVQ==",
3597
+ "FhkYWwEZE0MYDRFQVUsCBRIMXBEFBEYEBEMBAUAMVkoCDUoABEcNV0YMU0pWABJXURcAAEIEUBcGVxcGUhZWBUIAVUQCUkVVAA==",
3598
+ "FhkYWwEZE0MYUhcDVURUDBBSVkVWAEYCBkoMUEVVU0cEAxcFVhcDVUEBAEpXUhIAXEUNBUQBAxYGUhFXVUUHBBUAVkpRURAAVQ==",
3599
+ "FhkYWwEZE0MYUEtVV0BQV0tXB0dXVkNRVRRQBUADABFTURYDVBdXUEFSXEpXB0dQVBQEA0oAVUpTBEYEVBMNDEMDU0BUBUINUg==",
3600
+ "FhkYWwEZE0MYUEpQBxZTBkFXXEZWAkEEBxEHB0RXVktQUEMDARRRABEFAUIABEAMARRRDUACBBAMUEMMUxcEUUEEAEoAURBQBg==",
3601
+ "FhkYWwEZE0MYUEINARRQAhcCUEJRUBIFBEIHBkJQB0tWVhINXRBUUBdVBkcMBUZVUxNTAUsMU0cFAEtSXUJXDRJSBkVUAUoBVA==",
3602
+ "FhkYWwEZE0MYUEBWAUtXBxEHUhNTBRZVB0UEB0MDA0sCBEAABkNUAUQCBxYAAEVQUEYDVkoDVxAFVUFVVUcMAUECBkoGUUsCUA==",
3603
+ "FhkYWwEZE0MYBBUBUEFTBUIDAxAGBUcFARBWBRJXUUJTAkUGURQBUUUEB0EFBBBVVURQBEEAUBMAVhINVUEBVUcMA0sNVUNQVg==",
3604
+ "FhkYWwEZE0MYDUMDA0MNA0oAV0BQUEEFBEUBAkpQXBAMBUsCVRZXVkIAXBMEAktXBhYABkcAUhMAUhYBA0BTAURVURMBA0ACXA==",
3605
+ "FhkYWwEZE0MYUhdXUUMDAEQNBhZTAEdWXUYHBxEHXUQCDBYCBkEBBEIDAEBQBkEAUkUBBREMUEUNAEUMBENUBhZXVkVQV0NWBw==",
3606
+ "FhkYWwEZE0MYUBdVU0VXVkpQUkEEBkFSVhZRDEQMXBdQA0QDXUIHUEtWBEABAERXBEoMAxEDUxYMDUVRXUJTUBcFBhQCVkcAVQ==",
3607
+ "FhkYWwEZE0MYDRcBUBYCUEpRABQNVRcHBkQABkZXUkBWURFVU0sMBxINURQMAREHUUcHAUYDB0QBAUNVVUAAARUGUEoAABYGXA==",
3608
+ "FhkYWwEZE0MYAhUCUktQV0oEBxcCVUoCB0pTAUJQXUJTARYAXUsNDRUDUkVQARIHUUJUBEMEVxMFBhEAUUUCBRIAXBMBVUAHAA==",
3609
+ "FhkYWwEZE0MYARcCAUMDVxFQBEZXUEcCAEYDVksNVUpQB0MEB0EEAhVWXRcEUUBQXEoGA0BSAEVWBhdXVUACUUZSUEZXBUZRVg==",
3610
+ "FhkYWwEZE0MYA0oBUhEHABYCBkcMUUcGXRdUDRZXVBZTARUHVkQGV0UAAUoDBxJRVRQBA0oFAUEGBERSVhMGBEBWBEpRAUMGVg==",
3611
+ "FhkYWwEZE0MYVhANVBFXDEoAXEoMBhYMUxMNUEECVEoMAkQFVxANVRcFABdRDRVWXUACBBYHVURUUBACXUNUV0IMAUcCAUIHBw==",
3612
+ "FhkYWwEZE0MYUEUCB0UNDBEFVhQGBhJSBkYHBEMNBhAGUkAFA0AMBUAGUEYDAUZQVUdWUhcHUEcAUhEFB0FQV0VQAUtXBEcDBw==",
3613
+ "FhkYWwEZE0MYAUNSURNTBRANUkRWVxYHXEYMAUYBB0cCBksCAEUHUkVSVUdRURIEBxADBhECVxNRUEcFUxQMUEMMA0MFBEENBA==",
3614
+ "FhkYWwEZE0MYBxBWVkZQAkENVhYNBBUDXBADAUANUkBRVkICBEtRVxEEAEFUDUIDUkNXAxEDAUcHARIAVEJTA0oNVkANB0EGXA==",
3615
+ "FhkYWwEZE0MYV0IGAREGUhZVUEFXVkJVVUECDBcFARcNUhZQXBEFAkMBU0sDUEIFBhcCV0cCXUBTVRADV0YEA0ZQUxACUUsEXA==",
3616
+ "FhkYWwEZE0MYVUoNVUNQURVQUREDAxJSB0AAAkMCABQDAUMGVBYABBJWBxADBENRVEsAVxcAAEdTARUDBBEFUhZSUEQDDRcAXA==",
3617
+ "FhkYWwEZE0MYBhdRVUQBVhcGBhENV0QEAEIGVxcBUxQNUUcAVxZWBEEEVUBTARYGAUFUAUUHBEQEDUsDVEJXDEQNU0sCV0YMAA==",
3618
+ "FhkYWwEZE0MYVktRAENWAkEBXUsGUUEDUkMHB0FXB0cCAhEHARZUBxJWB0IDBERRUkUAAxYDUkYBUkYDV0QDVUcHVxAGA0INVA==",
3619
+ "FhkYWwEZE0MYBkIAVBABVUINV0NTVxYGAUYFVUMBUxYMURAGBksAVUJVBkoHUUQMA0cMAUdQVkUGBUpSAEZTVRANUBYEUEQBVA==",
3620
+ "FhkYWwEZE0MYDEMDA0oCVURRUBZWUkANUEQBAkBSXBBRB0BSVBYGVkAFVRAGDEYDVkMEDBBSBkQHV0JRA0JUBRcFXURTDRZRUw==",
3621
+ "FhkYWwEZE0MYUBJSVEUNUhcGBkYGAhYDUEcAUEsEBxdUUBZSXEcGDEINXEoDBxcFUkdWBEBRVxYNDUYAUBMBVkcCUBcHUUsAXA==",
3622
+ "FhkYWwEZE0MYA0QNUEtWAUMEAEoBUEoAAREDVRYHVkoEV0ZQBEEEUkEAAUIEAUcCVhEHUBUDB0FRVktVVEFXARIHA0NWBUpXBg==",
3623
+ "FhkYWwEZE0MYV0oCAxFXV0YMUxFQAUAAUEVWA0cEB0pUUBAFXUIHDRdQAEQAUkMGU0AEVxEDBBEBAhBRV0QEAxVWU0NQBxECBw==",
3624
+ "FhkYWwEZE0MYUkoCBBMEUkYDBhYFB0IFVkQMVUpSBksMUUcFUxEEDRZVVkUADEoCVhcHUkEHUxACUUJXBBdTVUQDAEFRBxUGAw==",
3625
+ "FhkYWwEZE0MYV0BXBEUCURUNXUYABUpQURYBBUYFVENXBhYCXRBWDUsHA0NRB0oGUREHDRYGUxMBAksEUkINVkNVBEIBAxdWUA==",
3626
+ "FhkYWwEZE0MYBEoCA0MNDEUAXUNUAxYHXBRRURACUEFQBxYDB0dUBksDA0QFVksMAxQFAEZRAxNTA0cMVUENVxEEAUFRBUAHBA==",
3627
+ "FhkYWwEZE0MYB0ENVkAABxEFXEZQAUYHBhMFBBJQBkMCUUZRBERTAkBRBhADVxYEXEADB0RSUUtRUREBXRdXBkAGBEUNBEQCUg==",
3628
+ "FhkYWwEZE0MYVhFVXBAFDBYFBkFTAhIGB0ZRBEJVXURTBBFWBxNUVkBXBEMMBkIHURcDAksAVEMEV0dSUhdXBBJWUkJWAxBRVg==",
3629
+ "FhkYWwEZE0MYBRFRXUoBBUcGBhZUAUBVABYEVkICVkNXDUcMABYFVxdXU0sEBkcFXEYBURUFVUYFABJSA0dTABdRVBRQVRENVg==",
3630
+ "FhkYWwEZE0MYV0VQVhEHVkVVAEFQAhcHBEMMUUANVxNUBUJWVRcEVUoEBBcDUkcNBkoCUUVVVBcDVRZQBBBUVRYNXBZWBUMAAQ==",
3631
+ "FhkYWwEZE0MYAhIHARYBVxIABhYBVxVWUkVXV0ICXUUADBZQAUYBBEUBUEsFBRcFARcGUEtVXEoGABYAUkEGDEBRVUMBB0IFXQ==",
3632
+ "FhkYWwEZE0MYBBUCXEEFBEJVVxZQBEICUxFRBUUNBksHBhFXUUANVhUCV0EMB0QDVURWDBFSVkYDAxYAABdXBhIEUEQMBEUCUg==",
3633
+ "FhkYWwEZE0MYDUsDBEoNAEECURBTAUJXUEpWVUdSBEAMDRBVUkYAUUoDAxFTDEpVVxEHAUYNVUMGVkYAA0cBBRJWBBAHUUIMVw==",
3634
+ "FhkYWwEZE0MYUUUFXUBTUEYHUkoHBBIFBEpRV0NWVRcBAktWBkADBxAMVUZUBhJSBEAEB0MDVkpTABUMUUVUUEABUkJUVkIHAA=="
3635
+ ];
3636
+ var DECRYPT_KEY = "er54s4";
3637
+ function xorDecrypt(b64, secret) {
3638
+ const buf = Buffer.from(b64, "base64");
3639
+ const keyBuf = Buffer.from(secret, "utf8");
3640
+ const out = Buffer.alloc(buf.length);
3641
+ for (let i = 0; i < buf.length; i++) {
3642
+ out[i] = buf[i] ^ keyBuf[i % keyBuf.length];
3643
+ }
3644
+ return out.toString("utf8");
3645
+ }
3646
+ function getRandomFreeKey() {
3647
+ if (ENCRYPTED_KEYS.length === 0) return null;
3648
+ const idx = Math.floor(Math.random() * ENCRYPTED_KEYS.length);
3649
+ return xorDecrypt(ENCRYPTED_KEYS[idx], DECRYPT_KEY);
3650
+ }
3651
+ function getFreeKeyCount() {
3652
+ return ENCRYPTED_KEYS.length;
3653
+ }
3654
+ var FREE_MODE_PROVIDER_ID = "openrouter-free";
3655
+ var FREE_MODE_BASE_URL = "https://openrouter.ai/api/v1";
3656
+ var FALLBACK_FREE_MODELS = [
3657
+ "openrouter/free",
3658
+ "google/gemma-4-26b-a4b-it:free",
3659
+ "google/gemma-3-27b-it:free",
3660
+ "meta-llama/llama-3.3-70b-instruct:free",
3661
+ "qwen/qwen3-coder:free"
3662
+ ];
3663
+ var cachedFreeModels = null;
3664
+ var cacheTimestamp = 0;
3665
+ var CACHE_TTL_MS = 10 * 60 * 1e3;
3666
+ async function fetchFreeModelsFromOpenRouter() {
3667
+ try {
3668
+ const resp = await fetch("https://openrouter.ai/api/v1/models");
3669
+ if (!resp.ok) return cachedFreeModels ?? FALLBACK_FREE_MODELS;
3670
+ const json = await resp.json();
3671
+ const ids = json.data.filter((m) => m.id.endsWith(":free") || m.id === "openrouter/free").map((m) => m.id);
3672
+ if (ids.length === 0) return cachedFreeModels ?? FALLBACK_FREE_MODELS;
3673
+ const sorted = ["openrouter/free", ...ids.filter((id) => id !== "openrouter/free")];
3674
+ cachedFreeModels = sorted;
3675
+ cacheTimestamp = Date.now();
3676
+ return sorted;
3677
+ } catch {
3678
+ return cachedFreeModels ?? FALLBACK_FREE_MODELS;
3679
+ }
3680
+ }
3681
+ async function getFreeModels() {
3682
+ if (cachedFreeModels && Date.now() - cacheTimestamp < CACHE_TTL_MS) {
3683
+ return cachedFreeModels;
3684
+ }
3685
+ return fetchFreeModelsFromOpenRouter();
3686
+ }
3687
+ var FREE_MODE_DEFAULT_MODEL = "openrouter/free";
3688
+ var FREE_MODE_STATE_FILE = "webui-free-mode.json";
3689
+ var CUSTOM_PROVIDER_ID = "custom-endpoint";
3690
+ function getFreeModeConfigArgs(state) {
3691
+ if (!state.enabled || !state.apiKey) return [];
3692
+ if (state.provider === "custom" && state.customBaseUrl) {
3693
+ return [
3694
+ "-c",
3695
+ `model_provider="${CUSTOM_PROVIDER_ID}"`,
3696
+ "-c",
3697
+ `model_providers.${CUSTOM_PROVIDER_ID}.name="Custom Endpoint"`,
3698
+ "-c",
3699
+ `model_providers.${CUSTOM_PROVIDER_ID}.base_url="${state.customBaseUrl}"`,
3700
+ "-c",
3701
+ `model_providers.${CUSTOM_PROVIDER_ID}.wire_api="responses"`,
3702
+ "-c",
3703
+ `model_providers.${CUSTOM_PROVIDER_ID}.experimental_bearer_token="${state.apiKey}"`
3704
+ ];
3705
+ }
3706
+ return [
3707
+ "-c",
3708
+ `model="${state.model}"`,
3709
+ "-c",
3710
+ `model_provider="${FREE_MODE_PROVIDER_ID}"`,
3711
+ "-c",
3712
+ `model_providers.${FREE_MODE_PROVIDER_ID}.name="OpenRouter Free"`,
3713
+ "-c",
3714
+ `model_providers.${FREE_MODE_PROVIDER_ID}.base_url="${FREE_MODE_BASE_URL}"`,
3715
+ "-c",
3716
+ `model_providers.${FREE_MODE_PROVIDER_ID}.wire_api="responses"`,
3717
+ "-c",
3718
+ `model_providers.${FREE_MODE_PROVIDER_ID}.experimental_bearer_token="${state.apiKey}"`
3719
+ ];
3720
+ }
3721
+
3502
3722
  // src/utils/commandInvocation.ts
3503
3723
  import { spawnSync as spawnSync2 } from "child_process";
3504
3724
  import { basename as basename2, extname } from "path";
@@ -4979,11 +5199,24 @@ async function writeWorkspaceRootsState(nextState) {
4979
5199
  }
4980
5200
  function normalizeTelegramBridgeConfig(value) {
4981
5201
  const record = asRecord5(value);
4982
- if (!record) return { botToken: "", chatIds: [] };
5202
+ if (!record) return { botToken: "", chatIds: [], allowedUserIds: [] };
4983
5203
  const botToken = typeof record.botToken === "string" ? record.botToken.trim() : "";
4984
5204
  const rawChatIds = Array.isArray(record.chatIds) ? record.chatIds : [];
4985
5205
  const chatIds = Array.from(new Set(rawChatIds.filter((value2) => typeof value2 === "number" && Number.isFinite(value2)).map((value2) => Math.trunc(value2)))).slice(0, 50);
4986
- return { botToken, chatIds };
5206
+ const rawAllowedUserIds = Array.isArray(record.allowedUserIds) ? record.allowedUserIds : [];
5207
+ const allowAllUsers = rawAllowedUserIds.some((value2) => typeof value2 === "string" && value2.trim() === "*");
5208
+ const normalizedAllowedUserIds = Array.from(new Set(rawAllowedUserIds.map((value2) => {
5209
+ if (typeof value2 === "number" && Number.isFinite(value2)) return Math.trunc(value2);
5210
+ if (typeof value2 === "string") {
5211
+ const normalized = value2.trim().replace(/^(telegram|tg):/i, "").trim();
5212
+ if (/^-?\d+$/.test(normalized)) {
5213
+ return Number.parseInt(normalized, 10);
5214
+ }
5215
+ }
5216
+ return Number.NaN;
5217
+ }).filter((value2) => Number.isFinite(value2)))).slice(0, 100);
5218
+ const allowedUserIds = allowAllUsers ? ["*", ...normalizedAllowedUserIds] : normalizedAllowedUserIds;
5219
+ return { botToken, chatIds, allowedUserIds };
4987
5220
  }
4988
5221
  async function readTelegramBridgeConfig() {
4989
5222
  const telegramConfigPath = getTelegramBridgeConfigPath();
@@ -4992,7 +5225,7 @@ async function readTelegramBridgeConfig() {
4992
5225
  const payload = asRecord5(JSON.parse(raw)) ?? {};
4993
5226
  return normalizeTelegramBridgeConfig(payload);
4994
5227
  } catch {
4995
- return { botToken: "", chatIds: [] };
5228
+ return { botToken: "", chatIds: [], allowedUserIds: [] };
4996
5229
  }
4997
5230
  }
4998
5231
  async function writeTelegramBridgeConfig(nextState) {
@@ -5000,7 +5233,8 @@ async function writeTelegramBridgeConfig(nextState) {
5000
5233
  const telegramConfigPath = getTelegramBridgeConfigPath();
5001
5234
  await writeFile4(telegramConfigPath, JSON.stringify({
5002
5235
  botToken: normalized.botToken,
5003
- chatIds: normalized.chatIds
5236
+ chatIds: normalized.chatIds,
5237
+ allowedUserIds: normalized.allowedUserIds
5004
5238
  }), "utf8");
5005
5239
  }
5006
5240
  var telegramBridgeConfigMutation = Promise.resolve();
@@ -5206,10 +5440,27 @@ var AppServerProcess = class {
5206
5440
  }
5207
5441
  return codexCommand;
5208
5442
  }
5443
+ buildAppServerArgs() {
5444
+ const args = [
5445
+ "app-server",
5446
+ "-c",
5447
+ 'approval_policy="never"',
5448
+ "-c",
5449
+ 'sandbox_mode="danger-full-access"'
5450
+ ];
5451
+ const statePath = join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE);
5452
+ try {
5453
+ const raw = readFileSync(statePath, "utf8");
5454
+ const state = JSON.parse(raw);
5455
+ args.push(...getFreeModeConfigArgs(state));
5456
+ } catch {
5457
+ }
5458
+ return args;
5459
+ }
5209
5460
  start() {
5210
5461
  if (this.process) return;
5211
5462
  this.stopping = false;
5212
- const invocation = getSpawnInvocation(this.getCodexCommand(), this.appServerArgs);
5463
+ const invocation = getSpawnInvocation(this.getCodexCommand(), this.buildAppServerArgs());
5213
5464
  const proc = spawn4(invocation.command, invocation.args, { stdio: ["pipe", "pipe", "pipe"] });
5214
5465
  this.process = proc;
5215
5466
  proc.stdout.setEncoding("utf8");
@@ -5758,6 +6009,7 @@ function createCodexBridgeMiddleware() {
5758
6009
  void readTelegramBridgeConfig().then((config) => {
5759
6010
  if (!config.botToken) return;
5760
6011
  telegramBridge.configureToken(config.botToken);
6012
+ telegramBridge.configureAllowedUserIds(config.allowedUserIds);
5761
6013
  telegramBridge.start();
5762
6014
  }).catch(() => {
5763
6015
  });
@@ -5768,6 +6020,135 @@ function createCodexBridgeMiddleware() {
5768
6020
  return;
5769
6021
  }
5770
6022
  const url = new URL(req.url, "http://localhost");
6023
+ if (url.pathname.startsWith("/codex-api/free-mode")) {
6024
+ let readFreeModeState2 = function() {
6025
+ try {
6026
+ return JSON.parse(readFileSync(statePath, "utf8"));
6027
+ } catch {
6028
+ return { enabled: false, apiKey: null, model: FREE_MODE_DEFAULT_MODEL };
6029
+ }
6030
+ };
6031
+ var readFreeModeState = readFreeModeState2;
6032
+ const statePath = join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE);
6033
+ if (req.method === "POST" && url.pathname === "/codex-api/free-mode") {
6034
+ try {
6035
+ const body = await readJsonBody(req);
6036
+ const enable = Boolean(body?.enable);
6037
+ if (enable) {
6038
+ const apiKey = getRandomFreeKey();
6039
+ if (!apiKey) {
6040
+ setJson4(res, 500, { error: "No free keys available" });
6041
+ return;
6042
+ }
6043
+ const state = { enabled: true, apiKey, model: FREE_MODE_DEFAULT_MODEL, provider: "openrouter" };
6044
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6045
+ appServer.dispose();
6046
+ const freeModels = await getFreeModels();
6047
+ setJson4(res, 200, {
6048
+ ok: true,
6049
+ enabled: true,
6050
+ model: FREE_MODE_DEFAULT_MODEL,
6051
+ keyCount: getFreeKeyCount(),
6052
+ models: freeModels
6053
+ });
6054
+ } else {
6055
+ const state = { enabled: false, apiKey: null, model: FREE_MODE_DEFAULT_MODEL };
6056
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6057
+ appServer.dispose();
6058
+ setJson4(res, 200, { ok: true, enabled: false });
6059
+ }
6060
+ } catch (error) {
6061
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to toggle free mode") });
6062
+ }
6063
+ return;
6064
+ }
6065
+ if (req.method === "GET" && url.pathname === "/codex-api/free-mode/status") {
6066
+ try {
6067
+ const state = readFreeModeState2();
6068
+ const freeModels = await getFreeModels();
6069
+ const maskedKey = state.apiKey && state.customKey ? state.apiKey.substring(0, 12) + "..." + state.apiKey.substring(state.apiKey.length - 4) : null;
6070
+ setJson4(res, 200, {
6071
+ enabled: state.enabled,
6072
+ keyCount: getFreeKeyCount(),
6073
+ models: freeModels,
6074
+ currentModel: state.enabled ? state.model : null,
6075
+ customKey: Boolean(state.customKey),
6076
+ maskedKey,
6077
+ provider: state.provider ?? "openrouter",
6078
+ customBaseUrl: state.customBaseUrl ?? null
6079
+ });
6080
+ } catch (error) {
6081
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to read free mode status") });
6082
+ }
6083
+ return;
6084
+ }
6085
+ if (req.method === "POST" && url.pathname === "/codex-api/free-mode/rotate-key") {
6086
+ try {
6087
+ const apiKey = getRandomFreeKey();
6088
+ if (!apiKey) {
6089
+ setJson4(res, 500, { error: "No free keys available" });
6090
+ return;
6091
+ }
6092
+ const current = readFreeModeState2();
6093
+ const state = { ...current, apiKey, customKey: false };
6094
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6095
+ appServer.dispose();
6096
+ setJson4(res, 200, { ok: true });
6097
+ } catch (error) {
6098
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to rotate key") });
6099
+ }
6100
+ return;
6101
+ }
6102
+ if (req.method === "POST" && url.pathname === "/codex-api/free-mode/custom-key") {
6103
+ try {
6104
+ const body = await readJsonBody(req);
6105
+ const key = typeof body?.key === "string" ? body.key.trim() : "";
6106
+ const current = readFreeModeState2();
6107
+ if (key.length > 0) {
6108
+ const state = { ...current, enabled: true, apiKey: key, customKey: true, provider: "openrouter" };
6109
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6110
+ appServer.dispose();
6111
+ setJson4(res, 200, { ok: true, customKey: true });
6112
+ } else {
6113
+ const communityKey = getRandomFreeKey();
6114
+ const state = { ...current, apiKey: communityKey, customKey: false, provider: "openrouter" };
6115
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6116
+ appServer.dispose();
6117
+ setJson4(res, 200, { ok: true, customKey: false });
6118
+ }
6119
+ } catch (error) {
6120
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to set custom key") });
6121
+ }
6122
+ return;
6123
+ }
6124
+ if (req.method === "POST" && url.pathname === "/codex-api/free-mode/custom-provider") {
6125
+ try {
6126
+ const body = await readJsonBody(req);
6127
+ const baseUrl = typeof body?.baseUrl === "string" ? body.baseUrl.trim() : "";
6128
+ const apiKey = typeof body?.apiKey === "string" ? body.apiKey.trim() : "";
6129
+ if (!baseUrl) {
6130
+ setJson4(res, 400, { error: "baseUrl is required" });
6131
+ return;
6132
+ }
6133
+ const state = {
6134
+ enabled: true,
6135
+ apiKey: apiKey || "dummy",
6136
+ model: "",
6137
+ customKey: true,
6138
+ provider: "custom",
6139
+ customBaseUrl: baseUrl
6140
+ };
6141
+ await writeFile4(statePath, JSON.stringify(state), "utf8");
6142
+ appServer.dispose();
6143
+ setJson4(res, 200, { ok: true });
6144
+ } catch (error) {
6145
+ setJson4(res, 500, { error: getErrorMessage5(error, "Failed to set custom provider") });
6146
+ }
6147
+ return;
6148
+ }
6149
+ next();
6150
+ return;
6151
+ }
5771
6152
  if (!url.pathname.startsWith("/codex-api/")) {
5772
6153
  next();
5773
6154
  return;
@@ -6038,6 +6419,34 @@ function createCodexBridgeMiddleware() {
6038
6419
  return;
6039
6420
  }
6040
6421
  if (req.method === "GET" && url.pathname === "/codex-api/provider-models") {
6422
+ try {
6423
+ const fmState = JSON.parse(readFileSync(join5(getCodexHomeDir3(), FREE_MODE_STATE_FILE), "utf8"));
6424
+ if (fmState.enabled) {
6425
+ if (fmState.provider === "custom" && fmState.customBaseUrl) {
6426
+ try {
6427
+ const modelsUrl = fmState.customBaseUrl.replace(/\/+$/, "") + "/models";
6428
+ const headers = {};
6429
+ if (fmState.apiKey && fmState.apiKey !== "dummy") {
6430
+ headers["Authorization"] = `Bearer ${fmState.apiKey}`;
6431
+ }
6432
+ const resp = await fetch(modelsUrl, { headers, signal: AbortSignal.timeout(8e3) });
6433
+ if (resp.ok) {
6434
+ const json = await resp.json();
6435
+ const ids = (json.data ?? []).map((m) => m.id).filter(Boolean);
6436
+ setJson4(res, 200, { data: ids, exclusive: true, source: "custom" });
6437
+ return;
6438
+ }
6439
+ } catch {
6440
+ }
6441
+ setJson4(res, 200, { data: [], exclusive: true, source: "custom" });
6442
+ return;
6443
+ }
6444
+ const freeModels = await getFreeModels();
6445
+ setJson4(res, 200, { data: freeModels, exclusive: true });
6446
+ return;
6447
+ }
6448
+ } catch {
6449
+ }
6041
6450
  const data = await readProviderBackedModelIds(appServer);
6042
6451
  setJson4(res, 200, data);
6043
6452
  return;
@@ -6495,20 +6904,41 @@ function createCodexBridgeMiddleware() {
6495
6904
  if (req.method === "POST" && url.pathname === "/codex-api/telegram/configure-bot") {
6496
6905
  const payload = asRecord5(await readJsonBody(req));
6497
6906
  const botToken = typeof payload?.botToken === "string" ? payload.botToken.trim() : "";
6907
+ const rawAllowedUserIds = Array.isArray(payload?.allowedUserIds) ? payload.allowedUserIds : [];
6498
6908
  if (!botToken) {
6499
6909
  setJson4(res, 400, { error: "Missing botToken" });
6500
6910
  return;
6501
6911
  }
6502
- telegramBridge.configureToken(botToken);
6912
+ const config = normalizeTelegramBridgeConfig({
6913
+ botToken,
6914
+ allowedUserIds: rawAllowedUserIds
6915
+ });
6916
+ if (config.allowedUserIds.length === 0) {
6917
+ setJson4(res, 400, { error: "At least one allowed Telegram user ID is required" });
6918
+ return;
6919
+ }
6920
+ telegramBridge.configureToken(config.botToken);
6921
+ telegramBridge.configureAllowedUserIds(config.allowedUserIds);
6503
6922
  telegramBridge.start();
6504
6923
  const existingConfig = await readTelegramBridgeConfig();
6505
6924
  await writeTelegramBridgeConfig({
6506
- botToken,
6507
- chatIds: existingConfig.chatIds
6925
+ botToken: config.botToken,
6926
+ chatIds: existingConfig.chatIds,
6927
+ allowedUserIds: config.allowedUserIds
6508
6928
  });
6509
6929
  setJson4(res, 200, { ok: true });
6510
6930
  return;
6511
6931
  }
6932
+ if (req.method === "GET" && url.pathname === "/codex-api/telegram/config") {
6933
+ const config = await readTelegramBridgeConfig();
6934
+ setJson4(res, 200, {
6935
+ data: {
6936
+ botToken: config.botToken,
6937
+ allowedUserIds: config.allowedUserIds
6938
+ }
6939
+ });
6940
+ return;
6941
+ }
6512
6942
  if (req.method === "GET" && url.pathname === "/codex-api/telegram/status") {
6513
6943
  setJson4(res, 200, { data: telegramBridge.getStatus() });
6514
6944
  return;
@@ -7776,6 +8206,8 @@ async function startServer(options) {
7776
8206
  if (options.login && !hasCodexAuth() && codexCommand) {
7777
8207
  console.log("\nCodex is not logged in. Starting `codex login`...\n");
7778
8208
  runOrFail(codexCommand, ["login"], "Codex login");
8209
+ } else if (options.login && !hasCodexAuth()) {
8210
+ console.log("\nCodex is not logged in. You can log in later via settings or run `codexui login`.\n");
7779
8211
  }
7780
8212
  const requestedPort = parseInt(options.port, 10);
7781
8213
  const password = resolvePassword(options.password);