fix: allow shopinbit car request status updates
What changed, and why it matters
This commit removes a special workaround that previously skipped status and message updates for car-research tickets in a shopping feature. Now those tickets will call the same backend endpoints as other tickets. The change appears to be a functional bug fix rather than a security fix, but it slightly increases the amount of data exchanged with the backend for car-research tickets.
Treat as a routine functional fix. If reviewing for security, verify that the backend now correctly authorizes `/tickets/:id/*` requests for car-research tickets and that no 403 error handling or data leakage regressions were introduced. No immediate security action is indicated by the diff alone.
Security signals we found
No security-relevant keywords in commit title or message
No input validation, authentication, authorization, or cryptography changes
Change increases backend API call surface for a specific ticket type
No references to CVEs, vulnerabilities, researchers, or security advisories
Evidence from the diff
The patch deletes the _isCarResearch guard in shopinbit_ticket_detail.dart. Previously, car-research tickets created via /car-research/log-payment were intentionally excluded from calls to /tickets/:id/* because the API returned 403. The new code unconditionally calls client.getMessages(id), client.getTicketStatus(id), and client.getTicketFull(id) for all ticket types. This is described as enabling status updates for car-research tickets. There is no evidence in the diff of input validation changes, authentication/authorization changes, cryptographic changes, or injection points.
Changed components
lib/pages/shopinbit/shopinbit_ticket_detail.dartShopInBit ticket detail UIShopInBitService client message/status/offer fetchingInspect captured patch +30 / −35
diff --git a/lib/pages/shopinbit/shopinbit_ticket_detail.dart b/lib/pages/shopinbit/shopinbit_ticket_detail.dart
index 99e799f..671ee89 100644
--- a/lib/pages/shopinbit/shopinbit_ticket_detail.dart
+++ b/lib/pages/shopinbit/shopinbit_ticket_detail.dart
@@ -68,44 +68,39 @@ class _ShopInBitTicketDetailState extends State<ShopInBitTicketDetail> {
final client = ShopInBitService.instance.client;
final id = widget.model.apiTicketId;
- // Car research tickets created via /car-research/log-payment are not
- // accessible via /tickets/:id/* endpoints (API returns 403). Skip
- // those calls for car tickets to avoid log spam. Local data is used.
- if (!_isCarResearch) {
- final messagesResp = await client.getMessages(id);
- final statusResp = await client.getTicketStatus(id);
-
- if (!messagesResp.hasError && messagesResp.value != null) {
- final apiMessages = messagesResp.value!;
- widget.model.clearMessages();
- for (final m in apiMessages) {
- widget.model.addMessage(
- ShopInBitMessage(
- text: m.content,
- timestamp: m.timestamp,
- isFromUser: !m.fromAgent,
- ),
- );
- }
- }
-
- if (!statusResp.hasError && statusResp.value != null) {
- widget.model.status = ShopInBitOrderModel.statusFromTicketState(
- statusResp.value!.state,
+ final messagesResp = await client.getMessages(id);
+ final statusResp = await client.getTicketStatus(id);
+
+ if (!messagesResp.hasError && messagesResp.value != null) {
+ final apiMessages = messagesResp.value!;
+ widget.model.clearMessages();
+ for (final m in apiMessages) {
+ widget.model.addMessage(
+ ShopInBitMessage(
+ text: m.content,
+ timestamp: m.timestamp,
+ isFromUser: !m.fromAgent,
+ ),
);
}
+ }
- if (widget.model.status == ShopInBitOrderStatus.offerAvailable &&
- (widget.model.offerProductName == null ||
- widget.model.offerPrice == null)) {
- final offerResp = await client.getTicketFull(id);
- if (!offerResp.hasError && offerResp.value != null) {
- final t = offerResp.value!;
- widget.model.setOffer(
- productName: t.productName,
- price: t.customerPrice,
- );
- }
+ if (!statusResp.hasError && statusResp.value != null) {
+ widget.model.status = ShopInBitOrderModel.statusFromTicketState(
+ statusResp.value!.state,
+ );
+ }
+
+ if (widget.model.status == ShopInBitOrderStatus.offerAvailable &&
+ (widget.model.offerProductName == null ||
+ widget.model.offerPrice == null)) {
+ final offerResp = await client.getTicketFull(id);
+ if (!offerResp.hasError && offerResp.value != null) {
+ final t = offerResp.value!;
+ widget.model.setOffer(
+ productName: t.productName,
+ price: t.customerPrice,
+ );
}
}
Why this scored 17/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.