Skip to content

Community administrators now can use checkorder and checkinvoice commands#732

Merged
grunch merged 5 commits intomainfrom
issue703
Mar 20, 2026
Merged

Community administrators now can use checkorder and checkinvoice commands#732
grunch merged 5 commits intomainfrom
issue703

Conversation

@Luquitasjeffrey
Copy link
Copy Markdown
Collaborator

@Luquitasjeffrey Luquitasjeffrey commented Feb 2, 2026

Before you needed to be superadmin in order been able to run those commands

Summary by CodeRabbit

  • New Features

    • checkorder and checkinvoice commands are now available to admin users (not just superadmins).
  • Bug Fixes

    • Non-superadmin admins are now restricted to their assigned community; attempts to check orders/invoices outside that community return a not-authorized response.
  • Chores

    • Error handling and user-facing behavior remain unchanged.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 2, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: b08eef11-3cde-4662-8744-d02dd13454a9

📥 Commits

Reviewing files that changed from the base of the PR and between 2610270 and 9ca2320.

📒 Files selected for processing (1)
  • bot/start.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • bot/start.ts

Walkthrough

Both bot commands in bot/start.tscheckorder and checkinvoice—now use adminMiddleware (not superAdminMiddleware) and enforce community scoping for non-superadmin admins; checkinvoice body was refactored (dedented) without changing error handling or sequence.

Changes

Cohort / File(s) Summary
Bot command handlers
bot/start.ts
Replaced superAdminMiddleware with adminMiddleware for checkorder and checkinvoice. Added community scoping checks: when !ctx.admin.admin, compare order.community_id to ctx.admin.default_community_id (string) and return messages.notAuthorized(...) on mismatch. checkinvoice body was refactored (dedented) but preserves validate→fetch Order→require hash→fetch invoice→messages.checkInvoiceMessage flow and existing try/catch logger.error handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through commands in the night,

Gates lowered so more admins might,
I checked the hashes, kept the logs bright,
Small refactor — the workflow's right.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly and clearly summarizes the main change: enabling community administrators to use checkorder and checkinvoice commands, which aligns with the primary objective of the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch issue703
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bot/start.ts (1)

582-595: ⚠️ Potential issue | 🟠 Major

Add community scoping for non‑super admins in checkorder/checkinvoice.

By switching to adminMiddleware without adding the community checks used elsewhere, a community admin can query any order/invoice by ID across communities. That’s a permissions regression.

🔧 Suggested fix (apply to both commands)
   bot.command('checkorder', adminMiddleware, async (ctx: MainContext) => {
     try {
       const [orderId] = (await validateParams(ctx, 2, '\\<_order id_\\>'))!;
       if (!orderId) return;
       if (!(await validateObjectId(ctx, orderId))) return;
       const order = await Order.findOne({ _id: orderId });

       if (order === null) return;
+      if (!ctx.admin.admin) {
+        if (!order.community_id) return await messages.notAuthorized(ctx);
+        if (order.community_id != ctx.admin.default_community_id) {
+          return await messages.notAuthorized(ctx);
+        }
+      }

       const buyer = await User.findOne({ _id: order.buyer_id });
       const seller = await User.findOne({ _id: order.seller_id });

       await messages.checkOrderMessage(ctx, order, buyer, seller);
     } catch (error) {
       logger.error(error);
     }
   });
   bot.command(
     'checkinvoice',
     adminMiddleware,
     async (ctx: MainContext) => {
       try {
         const [orderId] = (await validateParams(ctx, 2, '\\<_order id_\\>'))!;
         if (!orderId) return;
         if (!(await validateObjectId(ctx, orderId))) return;
         const order = await Order.findOne({ _id: orderId });

         if (order === null) return;
+        if (!ctx.admin.admin) {
+          if (!order.community_id) return await messages.notAuthorized(ctx);
+          if (order.community_id != ctx.admin.default_community_id) {
+            return await messages.notAuthorized(ctx);
+          }
+        }
         if (!order.hash) return;

         const invoice = await getInvoice({ hash: order.hash });
         if (invoice === undefined) {
           throw new Error('invoice is undefined');
         }

Also applies to: 600-623

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
bot/start.ts (1)

582-624: ⚠️ Potential issue | 🟠 Major

Scope community admins to their community before revealing order/invoice details.

With adminMiddleware, community admins can now call these commands. Without a community check, any admin can query any order/invoice by ID, which leaks cross‑community data. Add the same non‑super‑admin guard used elsewhere in this file (e.g., cancelorder/settleorder).

🔒 Proposed fix (apply to both handlers)
   bot.command('checkorder', adminMiddleware, async (ctx: MainContext) => {
     try {
       const [orderId] = (await validateParams(ctx, 2, '\\<_order id_\\>'))!;
       if (!orderId) return;
       if (!(await validateObjectId(ctx, orderId))) return;
       const order = await Order.findOne({ _id: orderId });

       if (order === null) return;
+
+      // Restrict community admins to their community orders
+      if (!ctx.admin.admin) {
+        if (!order.community_id) return await messages.notAuthorized(ctx);
+        if (order.community_id != ctx.admin.default_community_id) {
+          return await messages.notAuthorized(ctx);
+        }
+      }

       const buyer = await User.findOne({ _id: order.buyer_id });
       const seller = await User.findOne({ _id: order.seller_id });

       await messages.checkOrderMessage(ctx, order, buyer, seller);
     } catch (error) {
       logger.error(error);
     }
   });

   bot.command('checkinvoice', adminMiddleware, async (ctx: MainContext) => {
     try {
       const [orderId] = (await validateParams(ctx, 2, '\\<_order id_\\>'))!;
       if (!orderId) return;
       if (!(await validateObjectId(ctx, orderId))) return;
       const order = await Order.findOne({ _id: orderId });

       if (order === null) return;
+      // Restrict community admins to their community orders
+      if (!ctx.admin.admin) {
+        if (!order.community_id) return await messages.notAuthorized(ctx);
+        if (order.community_id != ctx.admin.default_community_id) {
+          return await messages.notAuthorized(ctx);
+        }
+      }
       if (!order.hash) return;

       const invoice = await getInvoice({ hash: order.hash });
       if (invoice === undefined) {
         throw new Error('invoice is undefined');
       }

       await messages.checkInvoiceMessage(
         ctx,
         invoice.is_confirmed,
         invoice.is_canceled!,
         invoice.is_held!,
       );
     } catch (error) {
       logger.error(error);
     }
   });

Copy link
Copy Markdown
Contributor

@mostronatorcoder mostronatorcoder Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing community scope check ❌

The original issue (#703) explicitly states:

"but only for orders created within their own communities"

This PR changes superAdminMiddlewareadminMiddleware, which allows any admin (including community admins and dispute solvers) to query any order in the system, not just orders from their own community.

validateAdmin() passes if user.admin === true OR isDisputeSolver(community, user). A dispute solver in community A could use checkorder to inspect orders from community B — that's an information leak.

Required fix

After fetching the order, verify the admin has jurisdiction:

const order = await Order.findOne({ _id: orderId });
if (order === null) return;

// If not a super admin, verify the order belongs to the admin's community
if (!ctx.admin.admin && order.community_id) {
  if (String(order.community_id) !== String(ctx.admin.default_community_id)) {
    return await messages.notAuthorized(ctx, ctx.admin.tg_id);
  }
}

Same check needed in both checkorder and checkinvoice.

Code quality ✅

The refactoring from callback-style to flat bot.command() for checkinvoice is a nice cleanup.

CI ✅

All checks passing.

Summary

The change in middleware is correct directionally, but without the community scope check it's a privilege escalation — community admins can see orders from other communities. Request changes until the scope check is added.

Comment thread bot/start.ts
Copy link
Copy Markdown
Contributor

@mostronatorcoder mostronatorcoder Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changes addressed ✅

The community scope check has been implemented correctly in both checkorder and checkinvoice commands:

if (
  !ctx.admin.admin &&
  String(order.community_id) !== String(ctx.admin.default_community_id)
) {
  return await messages.notAuthorized(ctx, ctx.admin.tg_id);
}

This ensures:

  • Super admins (ctx.admin.admin === true) can check any order
  • Community admins can only check orders from their own community
  • Unauthorized access returns notAuthorized message

CI ✅

All checks passing.

Summary

LGTM. The fix properly restricts community admins to their assigned communities while maintaining full access for super admins.

@grunch grunch merged commit f571f56 into main Mar 20, 2026
7 checks passed
@grunch grunch deleted the issue703 branch March 20, 2026 20:10
Matobi98 pushed a commit to Matobi98/bot that referenced this pull request Apr 2, 2026
…ands (lnp2pBot#732)

* Community administrators now can use checkorder and checkinvoice commands

* Code formatting

* Address mostronator comment, added a check for checkorder and checkinvoice commands that the order is in the community of the admin

* Code formatting
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants